mirror of
https://github.com/metrostroi-repo/MetrostroiAddon.git
synced 2026-05-02 00:42:29 +00:00
741 lines
26 KiB
Lua
741 lines
26 KiB
Lua
AddCSLuaFile("cl_init.lua")
|
|
AddCSLuaFile("shared.lua")
|
|
include("shared.lua")
|
|
util.AddNetworkString "metrostroi-signal"
|
|
util.AddNetworkString "metrostroi-signal-state"
|
|
function ENT:SetSprite(index,active,model,scale,brightness,pos,color)
|
|
if active and self.Sprites[index] then return end
|
|
if not active and not self.Sprites[index] then return end
|
|
if not active and self.Sprites[index] then
|
|
SafeRemoveEntity(self.Sprites[index])
|
|
self.Sprites[index] = nil
|
|
end
|
|
|
|
if active then
|
|
local sprite = ents.Create("env_sprite")
|
|
sprite:SetParent(self)
|
|
sprite:SetLocalPos(pos)
|
|
sprite:SetLocalAngles(self:GetAngles())
|
|
|
|
-- Set parameters
|
|
sprite:SetKeyValue("rendercolor",
|
|
Format("%i %i %i",
|
|
color.r*brightness,
|
|
color.g*brightness,
|
|
color.b*brightness
|
|
)
|
|
)
|
|
sprite:SetKeyValue("rendermode", 9) -- 9: WGlow, 3: Glow
|
|
sprite:SetKeyValue("renderfx", 14)
|
|
sprite:SetKeyValue("model", model)
|
|
sprite:SetKeyValue("scale", scale)
|
|
sprite:SetKeyValue("spawnflags", 1)
|
|
|
|
-- Turn sprite on
|
|
sprite:Spawn()
|
|
self.Sprites[index] = sprite
|
|
end
|
|
end
|
|
function ENT:OpenRoute(route)
|
|
self.LastOpenedRoute = route
|
|
if self.Routes[route].Manual then self.Routes[route].IsOpened = true end
|
|
if not self.Routes[route].Switches then return end
|
|
local Switches = string.Explode(",",self.Routes[route].Switches)
|
|
|
|
for i1 =1, #Switches do
|
|
if not Switches[i1] or Switches[i1] == "" then continue end
|
|
|
|
local SwitchState = Switches[i1]:sub(-1,-1) == "-"
|
|
local SwitchName = Switches[i1]:sub(1,-2)
|
|
--if not self.Switches[SwitchName] then self.Switches[SwitchName] = Metrostroi.GetSwitchByName(SwitchName) end
|
|
if not Metrostroi.GetSwitchByName(SwitchName) then print(self.Name,"switch not found") continue end
|
|
--If route go right from this switch - add it
|
|
if SwitchState ~= (Metrostroi.GetSwitchByName(SwitchName):GetSignal() ~= 0) then
|
|
Metrostroi.GetSwitchByName(SwitchName):SendSignal(SwitchState and "alt" or "main",nil,true)
|
|
--RunConsoleCommand("say","changing",SwitchName)
|
|
end
|
|
end
|
|
end
|
|
|
|
function ENT:CloseRoute(route)
|
|
if self.Routes[route].Manual then self.Routes[route].IsOpened = false end
|
|
if not self.Routes[route].Switches then return end
|
|
|
|
local Switches = string.Explode(",",self.Routes[route].Switches)
|
|
for i1 =1, #Switches do
|
|
if not Switches[i1] or Switches[i1] == "" then continue end
|
|
|
|
--local SwitchState = Switches[i1]:sub(-1,-1) == "-"
|
|
local SwitchName = Switches[i1]:sub(1,-2)
|
|
--if not self.Switches[SwitchName] then self.Switches[SwitchName] = Metrostroi.GetSwitchByName(SwitchName) end
|
|
if not Metrostroi.GetSwitchByName(SwitchName) then print(self.Name,"switch not found") continue end
|
|
--If route go right from this switch - add it
|
|
if SwitchState ~= (Metrostroi.GetSwitchByName(SwitchName):GetSignal() ~= 0) then
|
|
Metrostroi.GetSwitchByName(SwitchName):SendSignal("main",nil,true)
|
|
--RunConsoleCommand("say","changing",SwitchName)
|
|
end
|
|
end
|
|
end
|
|
|
|
function MSignalSayHook(ply, comm, fromULX)
|
|
if ulx and not fromULX then return end
|
|
for i,sig in pairs(ents.FindByClass("gmod_track_signal")) do
|
|
local comm = comm
|
|
if comm:sub(1,8) == "!sactiv " then
|
|
comm = comm:sub(9,-1):upper()
|
|
|
|
comm = string.Explode(":",comm)
|
|
if sig.Routes then
|
|
for k,v in pairs(sig.Routes) do
|
|
if (v.RouteName and v.RouteName:upper() == comm[1] or comm[1] == "*") and v.Emer then
|
|
if sig.LastOpenedRoute and k ~= sig.LastOpenedRoute then sig:CloseRoute(sig.LastOpenedRoute) end
|
|
v.IsOpened = true
|
|
break
|
|
end
|
|
end
|
|
end
|
|
elseif comm:sub(1,10) == "!sdeactiv " then
|
|
comm = comm:sub(11,-1):upper()
|
|
|
|
comm = string.Explode(":",comm)
|
|
if sig.Routes then
|
|
for k,v in pairs(sig.Routes) do
|
|
if (v.RouteName and v.RouteName:upper() == comm[1] or comm[1] == "*") and v.Emer then
|
|
v.IsOpened = false
|
|
break
|
|
end
|
|
end
|
|
end
|
|
elseif comm:sub(1,8) == "!sclose " then
|
|
comm = comm:sub(9,-1):upper()
|
|
|
|
comm = string.Explode(":",comm)
|
|
if comm[1] == sig.Name then
|
|
if sig.Routes[1] and sig.Routes[1].Manual then
|
|
sig:CloseRoute(1)
|
|
else
|
|
if not sig.Close then
|
|
sig.Close = true
|
|
end
|
|
if sig.InvationSignal then
|
|
sig.InvationSignal = false
|
|
end
|
|
if (sig.LastOpenedRoute and sig.LastOpenedRoute == 1) or sig.Routes[1].Repeater then
|
|
sig:CloseRoute(1)
|
|
else
|
|
sig:OpenRoute(1)
|
|
end
|
|
end
|
|
elseif sig.Routes then
|
|
for k,v in pairs(sig.Routes) do
|
|
if v.RouteName and v.RouteName:upper() == comm[1] then
|
|
if sig.LastOpenedRoute and k ~= sig.LastOpenedRoute then sig:CloseRoute(sig.LastOpenedRoute) end
|
|
sig:CloseRoute(k)
|
|
end
|
|
end
|
|
end
|
|
elseif comm:sub(1,7) == "!sopen " then
|
|
comm = comm:sub(8,-1):upper()
|
|
comm = string.Explode(":",comm)
|
|
if comm[1] == sig.Name then
|
|
if comm[2] then
|
|
if sig.NextSignals[comm[2]] then
|
|
local Route
|
|
for k,v in pairs(sig.Routes) do
|
|
if v.NextSignal == comm[2] then Route = k break end
|
|
end
|
|
sig:OpenRoute(Route)
|
|
end
|
|
else
|
|
if sig.Routes[1] and sig.Routes[1].Manual then
|
|
sig:OpenRoute(1)
|
|
elseif sig.Close then
|
|
sig.Close = false
|
|
end
|
|
end
|
|
elseif sig.Routes then
|
|
for k,v in pairs(sig.Routes) do
|
|
if v.RouteName and v.RouteName:upper() == comm[1] then
|
|
if sig.LastOpenedRoute and k ~= sig.LastOpenedRoute then sig:CloseRoute(sig.LastOpenedRoute) end
|
|
sig:OpenRoute(k)
|
|
end
|
|
end
|
|
end
|
|
elseif comm:sub(1,7) == "!sopps " then
|
|
comm = comm:sub(8,-1):upper()
|
|
comm = string.Explode(":",comm)
|
|
if comm[1] == sig.Name then
|
|
sig.InvationSignal = true
|
|
end
|
|
elseif comm:sub(1,7) == "!sclps " then
|
|
comm = comm:sub(8,-1):upper()
|
|
comm = string.Explode(":",comm)
|
|
if comm[1] == sig.Name then
|
|
sig.InvationSignal = false
|
|
end
|
|
elseif comm:sub(1,7) == "!senao " then
|
|
comm = comm:sub(8,-1):upper()
|
|
comm = string.Explode(":",comm)
|
|
if comm[1] == sig.Name then
|
|
if sig.AODisabled then sig.AODisabled = false end
|
|
end
|
|
elseif comm:sub(1,8) == "!sdisao " then
|
|
comm = comm:sub(9,-1):upper()
|
|
comm = string.Explode(":",comm)
|
|
if comm[1] == sig.Name then
|
|
if sig.ARSSpeedLimit == 2 then sig.AODisabled = true end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
hook.Add("PlayerSay","metrostroi-signal-say", function(ply, comm) MSignalSayHook(ply,comm) end)
|
|
function ENT:Initialize()
|
|
self:SetModel(self.TrafficLightModels[self.SignalType or 0].ArsBox.model)
|
|
self.Sprites = {}
|
|
self.Sig = ""
|
|
self.FreeBS = 1
|
|
self.OldBSState = 1
|
|
self.OutputARS = 1
|
|
self.EnableDelay = {}
|
|
self.PostInitalized = true
|
|
|
|
self.Controllers = nil
|
|
end
|
|
|
|
function ENT:PreInitalize()
|
|
self.AutostopOverride = nil
|
|
if not self.Routes or self.Routes[1].NextSignal == "" then
|
|
self.AutostopOverride = true
|
|
end
|
|
if self.Sprites then
|
|
for k,v in pairs(self.Sprites) do
|
|
SafeRemoveEntity(v)
|
|
self.Sprites[k] = nil
|
|
end
|
|
end
|
|
self.NextSignals = {}
|
|
--self.Switches = {}
|
|
for k,v in ipairs(self.Routes) do
|
|
if v.NextSignal == "" then
|
|
self.NextSignals[""] = nil--self
|
|
elseif v.NextSignal == "*" then
|
|
else
|
|
if not v.NextSignal then
|
|
ErrorNoHalt(Format("Metrostroi: No next signal name in signal %s! Check it now!\n", self.Name))
|
|
self.AutostopOverride = true
|
|
else
|
|
self.NextSignals[v.NextSignal] = Metrostroi.GetSignalByName(v.NextSignal)
|
|
if not self.NextSignals[v.NextSignal] then
|
|
print(Format("Metrostroi: Signal %s, signal not found(%s)", self.Name, v.NextSignal))
|
|
self.AutostopOverride = true
|
|
end
|
|
end
|
|
end
|
|
end
|
|
self.MU = false
|
|
for k,v in ipairs(self.Lenses) do
|
|
if v:find("M") then self.MU = true break end
|
|
end
|
|
end
|
|
function ENT:PostInitalize()
|
|
if not self.Routes or #self.Routes == 0 then print(self, "NEED SETUP") return end
|
|
for k,v in ipairs(self.Routes) do
|
|
if v.NextSignal == "*" and self.TrackPosition then
|
|
local sig
|
|
local cursig = self
|
|
while true do
|
|
cursig = Metrostroi.GetARSJoint(cursig.TrackPosition.node1,cursig.TrackPosition.x,cursig.TrackDir,false)
|
|
if not IsValid(cursig) then break end
|
|
sig = cursig
|
|
if not cursig.PassOcc then break end
|
|
end
|
|
if IsValid(sig) then
|
|
self.NextSignals["*"] = sig
|
|
else
|
|
self.AutostopOverride = true
|
|
print(Format("Metrostroi: Signal %s, cant automaticly find signal", self.Name))
|
|
end
|
|
end
|
|
end
|
|
local pos = self.TrackPosition
|
|
local node = pos and pos.node1 or nil
|
|
self.Node = node
|
|
|
|
self.SwitchesFunction = {}
|
|
self.Switches = {}
|
|
for i = 1,#self.Routes do
|
|
if not self.Routes[i].Switches then continue end
|
|
|
|
local Switches = string.Explode(",",self.Routes[i].Switches)
|
|
local SwitchesTbl = {}
|
|
--local GoodSwitches = true
|
|
--Checking all route switches
|
|
for i1 =1, #Switches do
|
|
if not Switches[i1] or Switches[i1] == "" then continue end
|
|
|
|
local SwitchState = Switches[i1]:sub(-1,-1) == "-"
|
|
local SwitchName = Switches[i1]:sub(1,-2)
|
|
if not Metrostroi.GetSwitchByName(SwitchName) then
|
|
print(Format("Metrostroi: %s, switch not found(%s)", self.Name, SwitchName))
|
|
continue
|
|
end
|
|
--If route go right from this switch - add it
|
|
table.insert(SwitchesTbl,{n = SwitchName,s = SwitchState})
|
|
end
|
|
self.Switches[i] = SwitchesTbl
|
|
if #SwitchesTbl == 0 then continue end
|
|
self.SwitchesFunction[i] = function()
|
|
local GoodSwitches = true
|
|
for i1 = 1,#self.Switches[i] do
|
|
if not self.Switches[i][i1] or not IsValid(Metrostroi.GetSwitchByName(self.Switches[i][i1].n)) then continue end
|
|
if self.Switches[i][i1].s ~= (Metrostroi.GetSwitchByName(self.Switches[i][i1].n):GetSignal() > 0) then
|
|
GoodSwitches = false
|
|
break
|
|
end
|
|
end
|
|
return GoodSwitches
|
|
end
|
|
end
|
|
for k,v in pairs(self.Routes) do
|
|
if not v.Lights then continue end
|
|
v.LightsExploded = string.Explode("-",v.Lights)
|
|
end
|
|
if not self.RouteNumberSetup or not self.RouteNumberSetup:find("W") then
|
|
self.GoodInvationSignal = 0
|
|
local index = 1
|
|
for k,v in ipairs(self.Lenses) do
|
|
if v ~= "M" then
|
|
for i = 1,#v do
|
|
if v[i] == "W" then self.GoodInvationSignal = index end
|
|
index = index + 1
|
|
end
|
|
end
|
|
end
|
|
else
|
|
self.GoodInvationSignal = -1
|
|
end
|
|
if self.Left then
|
|
self:SetModel(self.TrafficLightModels[self.SignalType or 0].ArsBoxMittor.model)
|
|
else
|
|
self:SetModel(self.TrafficLightModels[self.SignalType or 0].ArsBox.model)
|
|
end
|
|
self.PostInitalized = false
|
|
|
|
end
|
|
|
|
function ENT:OnRemove()
|
|
Metrostroi.UpdateSignalEntities()
|
|
Metrostroi.PostSignalInitialize()
|
|
end
|
|
|
|
function ENT:GetARS(ARSID,Force1_5,Force2_6)
|
|
if self.OverrideTrackOccupied then return ARSID == 2 end
|
|
if not self.ARSSpeedLimit then return false end
|
|
local nxt = self.ARSNextSpeedLimit == 2 and 0 or self.ARSNextSpeedLimit ~= 1 and self.ARSNextSpeedLimit
|
|
return self.ARSSpeedLimit == ARSID or ((self.TwoToSix and not Force1_5 or Force2_6) and nxt and nxt == ARSID and self.ARSSpeedLimit > nxt)
|
|
end
|
|
--[[ function ENT:GetRS()
|
|
if not self.TwoToSix or not self.ARSSpeedLimit then return false end
|
|
--if self.ARSSpeedLimit == 1 or self.ARSSpeedLimit == 2 then return false end
|
|
if self.ARSSpeedLimit <= 2 then return false end
|
|
return self.OverrideTrackOccupied or self.ARSSpeedLimit == 0 or (not self.ARSNextSpeedLimit or self.ARSNextSpeedLimit == 1) or self.ARSSpeedLimit <= self.ARSNextSpeedLimit
|
|
end--]]
|
|
|
|
function ENT:GetRS()
|
|
if self.OverrideTrackOccupied or not self.TwoToSix or not self.ARSSpeedLimit then return false end
|
|
--if self.ARSSpeedLimit == 1 or self.ARSSpeedLimit == 2 then return false end
|
|
if self.ARSSpeedLimit ~= 0 and self.ARSSpeedLimit== 2 then return false end
|
|
return (self.ARSSpeedLimit > 4 or self.ARSSpeedLimit == 4 and self.Approve0) and (not self.ARSNextSpeedLimit or self.ARSNextSpeedLimit >= self.ARSSpeedLimit)
|
|
end
|
|
|
|
function ENT:Get325HzAproove0()
|
|
if self.OverrideTrackOccupied or not self.ARSSpeedLimit then return false end
|
|
return self.ARSSpeedLimit == 0 and self.Approve0
|
|
end
|
|
|
|
function ENT:GetMaxARS()
|
|
local ARSCodes = self.Routes[1].ARSCodes
|
|
if not self.Routes[1] or not ARSCodes then return 1 end
|
|
return tonumber(ARSCodes[#ARSCodes]) or 1
|
|
end
|
|
function ENT:GetMaxARSNext()
|
|
local Routes = self.NextSignalLink and self.NextSignalLink.Routes or self.Routes
|
|
local ARSCodes = Routes[1] and Routes[1].ARSCodes
|
|
local code = tonumber(ARSCodes[#ARSCodes]) or 1
|
|
local This = self:GetMaxARS()
|
|
if not ARSCodes then return This end
|
|
if code > This then return This end
|
|
--if not ARSCodes then return 1 end
|
|
return tonumber(ARSCodes[#ARSCodes]) or 1
|
|
end
|
|
|
|
function ENT:CheckOccupation()
|
|
--print(self.FoundedAll)
|
|
--if not self.FoundedAll then return end
|
|
if not self.Close and not self.KGU then --not self.OverrideTrackOccupied and
|
|
if self.Node and self.TrackPosition then
|
|
self.Occupied,self.OccupiedBy,self.OccupiedByNow = Metrostroi.IsTrackOccupied(self.Node, self.TrackPosition.x,self.TrackPosition.forward,self.ARSOnly and "ars" or "light", self)
|
|
end
|
|
if self.Routes[self.Route] and self.Routes[self.Route].Manual then
|
|
self.Occupied = self.Occupied or not self.Routes[self.Route].IsOpened
|
|
end
|
|
if self.OccupiedByNowOld ~= self.OccupiedByNow then
|
|
self.InvationSignal = false
|
|
self.AODisabled = false
|
|
self.OccupiedByNowOld = self.OccupiedByNow
|
|
end
|
|
else
|
|
self.NextSignalLink = nil
|
|
self.Occupied = self.Close or self.KGU --self.OverrideTrackOccupied or
|
|
end
|
|
end
|
|
function ENT:ARSLogic(tim)
|
|
--print(self.FoundedAll)
|
|
--if not self.FoundedAll then return end
|
|
if not self.Routes or not self.NextSignals then return end
|
|
-- Check track occuping
|
|
if not self.Routes[self.Route or 1].Repeater then
|
|
self:CheckOccupation()
|
|
if self.Occupied then
|
|
if self.Routes[self.Route or 1].Manual then self.Routes[self.Route or 1].IsOpened = false end
|
|
end
|
|
if self.Occupied or not self.NextSignalLink or not self.NextSignalLink.FreeBS then
|
|
self.FreeBS = 0
|
|
else
|
|
self.FreeBS = math.min(30,self.NextSignalLink.FreeBS + 1) -- old 10 freebs - костыль
|
|
end
|
|
if self.FreeBS - (self.OldBSState or self.FreeBS) > 1 then
|
|
local Free = self.FreeBS
|
|
timer.Simple(tim+0.1,function()
|
|
if not IsValid(self) then return end
|
|
if self.NextSignalLink and self.NextSignalLink.FreeBS + 1 - self.OldBSState > 1 then
|
|
self.FreeBS = Free
|
|
self.OldBSState = Free
|
|
end
|
|
end)
|
|
self.FreeBS = self.OldBSState
|
|
end
|
|
self.OldBSState = self.FreeBS
|
|
if self.FreeBS == 1 then
|
|
self.OccupiedBy = self
|
|
elseif self.FreeBS > 1 then
|
|
self.AutostopEnt = nil
|
|
end
|
|
if self.OccupiedByNow ~= self.AutostopEnt and self.AutostopEnt ~= self.CurrentAutostopEnt then
|
|
self.AutostopEnt = nil
|
|
end
|
|
end
|
|
if self.OldRoute ~= self.Route then
|
|
self.InvationSignal = false
|
|
self.AODisabled = false
|
|
self.OldRoute = self.Route
|
|
end
|
|
--Removing NSL
|
|
self.NextSignalLink = nil
|
|
--Set the first route, if no switches in route or no switches
|
|
--or not self.Switches
|
|
if #self.Routes == 1 and (self.Routes[1].Switches == "" or not self.Routes[1].Switches) then
|
|
self.NextSignalLink = self.NextSignals[self.Routes[1].NextSignal]
|
|
self.Route = 1
|
|
else
|
|
local route
|
|
--Finding right route
|
|
for i = 1,#self.Routes do
|
|
|
|
--If all switches right - get this route!
|
|
if self.SwitchesFunction[i] and self.SwitchesFunction[i]() and (not self.Routes[i].Manual and not self.Routes[i].Emer or self.Routes[i].IsOpened) then
|
|
--if self.Route ~= i then
|
|
route = i
|
|
--self.NextSignalLink = nil
|
|
--end
|
|
elseif not self.SwitchesFunction[i] and (not self.Routes[i].Manual and not self.Routes[i].Emer or self.Routes[i].IsOpened) then
|
|
route = i
|
|
--self.NextSignalLink = nil
|
|
end
|
|
end
|
|
if self.Route ~= route and (not self.Routes[route] or not self.Routes[route].Emer) then
|
|
self.Route = route
|
|
self.NextSignalLink = false
|
|
else
|
|
if self.Route ~= route then self.Route = route end
|
|
self.NextSignalLink = self.Routes[route] and self.NextSignals[self.Routes[route].NextSignal]
|
|
end
|
|
end
|
|
if self.NextSignalLink == nil then
|
|
if self.Occupied then
|
|
self.NextSignalLink = self
|
|
self.FreeBS = 0
|
|
--self.Route = 1
|
|
end
|
|
end
|
|
if self.Routes[self.Route] then
|
|
if self.Routes[self.Route or 1].Repeater then
|
|
self.RealName = IsValid(self.NextSignalLink) and self.NextSignalLink.RealName or self.Name
|
|
else
|
|
self.RealName = self.Name
|
|
end
|
|
if self.Routes[self.Route or 1].Repeater then
|
|
self.RealName = IsValid(self.NextSignalLink) and self.NextSignalLink.Name or self.Name
|
|
self.ARSSpeedLimit = IsValid(self.NextSignalLink) and self.NextSignalLink.ARSSpeedLimit or 1
|
|
self.ARSNextSpeedLimit = IsValid(self.NextSignalLink) and self.NextSignalLink.ARSNextSpeedLimit or 1
|
|
self.FreeBS = IsValid(self.NextSignalLink) and self.NextSignalLink.FreeBS or 0
|
|
elseif self.Routes[self.Route].ARSCodes then
|
|
local ARSCodes = self.Routes[self.Route].ARSCodes
|
|
self.ARSNextSpeedLimit = IsValid(self.NextSignalLink) and self.NextSignalLink.ARSSpeedLimit or tonumber(ARSCodes[1])
|
|
self.ARSSpeedLimit = tonumber(ARSCodes[math.min(#ARSCodes, self.FreeBS+1)]) or 0
|
|
if self.AODisabled and self.ARSSpeedLimit ~= 2 then self.AODisabled = false end
|
|
if (self.InvationSignal or self.AODisabled) and self.ARSSpeedLimit == 2 then self.ARSSpeedLimit = 1 end
|
|
end
|
|
end
|
|
if self.NextSignalLink ~= false and (self.Occupied or not self.NextSignalLink or not self.NextSignalLink.FreeBS) then
|
|
if self.Routes[self.Route or 1].Manual then self.Routes[self.Route or 1].IsOpened = false end
|
|
end
|
|
end
|
|
|
|
function ENT:Think()
|
|
if self.PostInitalized then return end
|
|
--DEBUG
|
|
if Metrostroi.SignalDebugCV:GetBool() then
|
|
self:SetNW2Bool("Debug",true)
|
|
local next = self.NextSignalLink
|
|
local pos = self.TrackPosition
|
|
local prev = self.PrevSig
|
|
if next then
|
|
next.PrevSig = self
|
|
local nextpos = self.NextSignalLink.TrackPosition
|
|
self:SetNW2String("NextSignalName",next.Name)
|
|
if pos and nextpos then
|
|
self:SetNW2Float("DistanceToNext",nextpos.x - pos.x)
|
|
else
|
|
self:SetNW2Float("DistanceToNext",0)
|
|
end
|
|
self:SetNW2Int("NextPosID",nextpos and nextpos.path and nextpos.path.id or 0)
|
|
self:SetNW2Float("NextPos",nextpos and nextpos.x or 0)
|
|
else
|
|
self:SetNW2String("NextSignalName","N/A")
|
|
self:SetNW2Float("DistanceToNext",0)
|
|
self:SetNW2Float("NextPos",0)
|
|
self:SetNW2Float("NextPosID",0)
|
|
end
|
|
if prev then
|
|
local prevpos = prev.TrackPosition
|
|
if pos and prevpos then
|
|
self:SetNW2Float("DistanceToPrev",-prevpos.x + pos.x)
|
|
else
|
|
self:SetNW2Float("DistanceToPrev",0)
|
|
end
|
|
self:SetNW2String("PrevSignalName",self.PrevSig.Name)
|
|
self:SetNW2Int("PrevPosID",prevpos and prevpos.path and prevpos.path.id or 0)
|
|
self:SetNW2Float("PrevPos",prevpos and prevpos.x or 0)
|
|
else
|
|
self:SetNW2String("PrevSignalName","N/A")
|
|
self:SetNW2Int("PrevPosID",0)
|
|
self:SetNW2Float("PrevPos",0)
|
|
end
|
|
self:SetNW2Float("Pos",pos and pos.x or 0)
|
|
self:SetNW2Int("PosID",pos and pos.path and pos.path.id or 0)
|
|
|
|
self:SetNW2Bool("CurrentRoute",self.Route or -1)
|
|
self:SetNW2Bool("Occupied",self.Occupied)
|
|
self:SetNW2Bool("2/6",self.TwoToSix)
|
|
self:SetNW2Int("FreeBS",self.FreeBS)
|
|
self:SetNW2Bool("LinkedToController",self.Controllers ~= nil)
|
|
self:SetNW2Int("ControllersNumber",self.Controllers ~= nil and #self.Controllers or -1)
|
|
self:SetNW2Bool("BlockedByController",self.ControllerLogic)
|
|
for i=0,8 do
|
|
if i==3 or i==5 then continue end
|
|
self:SetNW2Bool("CurrentARS"..i,self:GetARS(i))
|
|
end
|
|
self:SetNW2Bool("CurrentARS325",self:GetRS())
|
|
self:SetNW2Bool("CurrentARS325_2",self:Get325HzAproove0())
|
|
end
|
|
if not self.ControllerLogic then
|
|
if not self.Routes or #self.Routes == 0 then
|
|
ErrorNoHalt(Format("Metrostroi:Signal %s don't have a routes!\n",self.Name))
|
|
return
|
|
end
|
|
if not self.Routes[self.Route or 1] then
|
|
ErrorNoHalt(Format("Metrostroi:Signal %s have a null %s route!!\n",self.Name,self.Route))
|
|
return
|
|
end
|
|
|
|
self.PrevTime = self.PrevTime or 0
|
|
if (CurTime() - self.PrevTime) > 1.0 then
|
|
self.PrevTime = CurTime()+math.random(0.5,1.5)
|
|
self:ARSLogic(self.PrevTime - CurTime())
|
|
end
|
|
self.RouteNumberOverrite = nil
|
|
local number = ""
|
|
if self.MU or self.ARSOnly or self.RouteNumberSetup and self.RouteNumberSetup ~= "" or self.RouteNumber and self.RouteNumber ~= "" then
|
|
if self.NextSignalLink then
|
|
if not self.NextSignalLink.Red and not self.Red then
|
|
self.RouteNumberOverrite = self.NextSignalLink.RouteNumberOverrite ~= "" and self.NextSignalLink.RouteNumberOverrite or self.NextSignalLink.RouteNumber
|
|
else
|
|
self.RouteNumberOverrite = self.RouteNumber
|
|
end
|
|
if (not self.Red or self.InvationSignal) and self.Routes[self.Route or 1].EnRou then
|
|
if self.NextSignalLink.RouteNumberOverrite then
|
|
number = number..self.NextSignalLink.RouteNumberOverrite
|
|
end
|
|
if self.NextSignalLink.RouteNumber and not self.AutoEnabled then
|
|
number = number..self.NextSignalLink.RouteNumber
|
|
end
|
|
end
|
|
--print(self.Name,self.NextSignalLink.RouteNumberOverrite)
|
|
self.RouteNumberOverrite = (self.RouteNumberOverrite or "")..number
|
|
else
|
|
self.RouteNumberOverrite = self.RouteNumber
|
|
end
|
|
end
|
|
if self.InvationSignal and self.GoodInvationSignal == -1 then
|
|
number = number.."W"
|
|
end
|
|
if self.KGU then number = number.."K" end
|
|
if number then self:SetNW2String("Number",number) end
|
|
|
|
if self.ARSOnly then
|
|
if self.Sprites then
|
|
for k,v in pairs(self.Sprites) do
|
|
SafeRemoveEntity(v)
|
|
self.Sprites[k] = nil
|
|
end
|
|
if self.ARSOnly and self.Sprites then
|
|
self.Sprites = nil
|
|
end
|
|
end
|
|
self:SetNW2String("Signal","")
|
|
self.AutoEnabled = not self.ARSOnly
|
|
return
|
|
end
|
|
|
|
self.AutoEnabled = false
|
|
self.Red = nil
|
|
if not self.Routes[self.Route or 1].Lights then return end
|
|
local Route = self.Routes[self.Route or 1]
|
|
local index = 1
|
|
local offset = self.RenderOffset[self.SignalType] or Vector(0,0,0)
|
|
self.Sig = ""
|
|
self.Colors = ""
|
|
for k,v in ipairs(self.Lenses) do
|
|
if self.Routes[self.Route or 1].Repeater and IsValid(self.NextSignalLink) and (not self.Routes[self.Route or 1].Lights or self.Routes[self.Route or 1].Lights == "") then
|
|
break
|
|
end
|
|
if v ~= "M" then
|
|
--get the some models data
|
|
local data = #v ~= 1 and self.TrafficLightModels[self.SignalType][#v-1] or self.TrafficLightModels[self.SignalType][self.Signal_IS]
|
|
if not data then continue end
|
|
for i = 1,#v do
|
|
--Get the LightID and check, is this light must light up
|
|
local LightID = IsValid(self.NextSignalLink) and math.min(#Route.LightsExploded,self.FreeBS+1) or 1
|
|
local AverageState = Route.LightsExploded[LightID]:find(tostring(index)) or ((v[i] == "W" and self.InvationSignal and self.GoodInvationSignal == index) and 1 or 0)
|
|
local MustBlink = (v[i] == "W" and self.InvationSignal and self.GoodInvationSignal == index) or (AverageState > 0 and Route.LightsExploded[LightID][AverageState+1] == "b") --Blinking, when next is "b" (or it's invasion signal')
|
|
self.Sig = self.Sig..(AverageState > 0 and (MustBlink and 2 or 1) or 0)
|
|
|
|
if AverageState > 0 then
|
|
if self.GoodInvationSignal ~= index then self.Colors = self.Colors..(MustBlink and v[i]:lower() or v[i]:upper()) end
|
|
if v[i] == "R" then
|
|
self.AutoEnabled = not self.NonAutoStop
|
|
self.Red = true
|
|
end
|
|
end
|
|
index = index + 1
|
|
end
|
|
end
|
|
end
|
|
else
|
|
local number = self.RouteNumberReplace or ""
|
|
--[[self.PrevTime = self.PrevTime or 0
|
|
if (CurTime() - self.PrevTime) > 1.0 then
|
|
self.PrevTime = CurTime()+math.random(0.5,1.5)
|
|
self:ARSLogic(self.PrevTime - CurTime())
|
|
self:CheckOccupation()
|
|
end]]
|
|
--[[
|
|
if self.MU or self.ARSOnly or self.RouteNumberSetup and self.RouteNumberSetup ~= "" or self.RouteNumber and self.RouteNumber ~= "" then
|
|
if self.NextSignalLink then
|
|
if not self.NextSignalLink.AutoEnabled and not self.AutoEnabled then
|
|
self.RouteNumberOverrite = self.NextSignalLink.RouteNumberOverrite ~= "" and self.NextSignalLink.RouteNumberOverrite or self.NextSignalLink.RouteNumber
|
|
else
|
|
self.RouteNumberOverrite = self.RouteNumber
|
|
end
|
|
if self.NextSignalLink.RouteNumberOverrite and not self.AutoEnabled and (self.Routes[self.Route or 1].EnRou or self.InvationSignal) then
|
|
number = number..self.NextSignalLink.RouteNumberOverrite
|
|
end
|
|
if self.NextSignalLink.RouteNumber and (self.Routes[self.Route or 1].EnRou and not self.AutoEnabled or self.InvationSignal) then
|
|
number = number..self.NextSignalLink.RouteNumber
|
|
end
|
|
--print(self.Name,self.NextSignalLink.RouteNumberOverrite)
|
|
self.RouteNumberOverrite = (self.RouteNumberOverrite or "")..number
|
|
else
|
|
self.RouteNumberOverrite = self.RouteNumber
|
|
end
|
|
end]]
|
|
if self.InvationSignal and self.GoodInvationSignal == -1 then
|
|
number = number.."W"
|
|
end
|
|
if self.KGU then number = number.."K" end
|
|
if number then self:SetNW2String("Number",number) end
|
|
local index = 1
|
|
self.Colors = ""
|
|
for k,v in ipairs(self.Lenses) do
|
|
if v ~= "M" then
|
|
--get the some models data
|
|
local data = #v ~= 1 and self.TrafficLightModels[self.SignalType][#v-1] or self.TrafficLightModels[self.SignalType][self.Signal_IS]
|
|
if not data then continue end
|
|
for i = 1,#v do
|
|
if (self.Sig[index] == "1" or self.Sig[index] == "2") then self.Colors = self.Colors..v[i]:lower() end
|
|
index = index + 1
|
|
end
|
|
end
|
|
end
|
|
end
|
|
if self.Controllers then
|
|
for k,v in pairs(self.Controllers) do
|
|
if self.Sig ~= v.Sig then
|
|
local Route = self.Routes[self.Route or 1]
|
|
local LightID = IsValid(self.NextSignalLink) and math.min(#Route.LightsExploded,self.FreeBS+1) or 1
|
|
local lights = Route.LightsExploded[LightID]
|
|
v:TriggerOutput("LenseEnabled",self,Route.LightsExploded[LightID])
|
|
v.Sig = self.Sig
|
|
end
|
|
if v.OldIS ~= self.InvationSignal then
|
|
if self.InvationSignal then
|
|
v:TriggerOutput("LenseEnabled",self,"I")
|
|
else
|
|
v:TriggerOutput("LenseDisabled",self,"I")
|
|
end
|
|
v.OldIS = self.InvationSignal
|
|
end
|
|
end
|
|
end
|
|
self:SetNW2String("Signal",self.Sig)
|
|
if not self.AutostopPresent then self:SetNW2Bool("Autostop",self.AutoEnabled) end
|
|
|
|
self:NextThink(CurTime() + 0.25)
|
|
return true
|
|
end
|
|
|
|
--Net functions
|
|
--Send update, if parameters have been changed
|
|
function ENT:SendUpdate(ply)
|
|
net.Start("metrostroi-signal")
|
|
net.WriteEntity(self)
|
|
net.WriteInt(self.SignalType or 0,3)
|
|
net.WriteString(self.Name or "NOT LOADED")
|
|
net.WriteString(self.ARSOnly and "ARSOnly" or self.LensesStr)
|
|
net.WriteString(self.SignalType == 0 and self.RouteNumberSetup or "")
|
|
net.WriteBool(self.Left)
|
|
net.WriteBool(self.Double)
|
|
net.WriteBool(self.DoubleL)
|
|
net.WriteBool(not self.NonAutoStop)
|
|
if ply then net.Send(ply) else net.Broadcast() end
|
|
end
|
|
|
|
--On receive update request, we send update
|
|
net.Receive("metrostroi-signal", function(_, ply)
|
|
local ent = net.ReadEntity()
|
|
if not IsValid(ent) or not ent.SendUpdate then return end
|
|
ent:SendUpdate(ply)
|
|
end)
|
|
|
|
Metrostroi.OptimisationPatch() |