-------------------------------------------------------------------------------- -- 81-722 BMCIK-01 system -------------------------------------------------------------------------------- -- Copyright (C) 2013-2018 Metrostroi Team & FoxWorks Aerospace s.r.o. -- Contains proprietary code. See license.txt for additional information. -------------------------------------------------------------------------------- Metrostroi.DefineSystem("81_722_BMCIK") TRAIN_SYSTEM.DontAccelerateSimulation = true TRAIN_SYSTEM.TriggerNames = { "SarmatUp", "SarmatDown", "SarmatEnter", "SarmatEsc", "SarmatF1", "SarmatF2", "SarmatF3", "SarmatF4", "SarmatPath", "SarmatLine", "SarmatZero", "SarmatStart", } function TRAIN_SYSTEM:Initialize() self.Triggers = {} for k,v in pairs(self.TriggerNames) do self.Train:LoadSystem(v,"Relay","Switch") self.Triggers[v] = false end self.LineOut = 0 self.UPOActive = 0 if TURBOSTROI then return end self.State = 0 self.Brightness = 1 self.NIIP = { DOORS_closed = 0, RUCHKA = 0, SPEED = 0, UPO_STATE = 0, Evacuation = 0, Vzlom_kabiny = 0, CabActive = 0 } self.BMTS = { State = 0, Text = "", Update = false } self.Announcer = { State = 0, CIKState = 0, Active = false, Line = 0, LimitStation = false, Path = false, PathSel = false, Station = 0, OnStation = false, Mode = 3, TrainTrain = false, BITTime = false, LineEnabled = false, Volumes = { Cabin = 5, Salon = 5, UPOCabin = 5, UPOSalon = 5, EmerCab = 5, V5 = 0 } } self.List = { Count = 0, Selected = 1, Offset = 0, States = {} } self.Cam = { {Link = nil,Ent = NULL}, {Link = nil,Ent = NULL}, {Link = nil,Ent = NULL}, {Link = nil,Ent = NULL}, Page = 0, Wagon = 0, Fullscreen = 0 } end function TRAIN_SYSTEM:Outputs() return {"UPOActive","LineOut"} end function TRAIN_SYSTEM:Inputs() return {} end if TURBOSTROI then return end -- CAN messages TRAIN_SYSTEM.CAN_ACTIVATE = 0x01 TRAIN_SYSTEM.CAN_CIKSTATE = 0x02 TRAIN_SYSTEM.CAN_BMTS_TEXT = 0x10 TRAIN_SYSTEM.CAN_CURR = 0x21 TRAIN_SYSTEM.CAN_NEXT = 0x22 TRAIN_SYSTEM.CAN_PATH = 0x23 TRAIN_SYSTEM.CAN_CLOSERING = 0x24 TRAIN_SYSTEM.CAN_VOLUMES = 0x25 TRAIN_SYSTEM.CAN_SPEED = 0x26 TRAIN_SYSTEM.CAN_BITTEXT = 0x30 TRAIN_SYSTEM.CAN_BITDOPMSG = 0x31 TRAIN_SYSTEM.CAN_BITTIME = 0x32 -- Buttons TRAIN_SYSTEM.Buttons = { { name = "Esc", id = 41, x = 10,y = 742, w = 218,h = 48, touch = function(self) if self.Cam.Page == 0 then return end if self.Cam.Fullscreen > 0 then self.Cam.Fullscreen = 0 else self.Cam.Page = 0 for i=1,4 do self.Cam[i].Link = nil self.Cam[i].Ent = NULL end end end, show = function(page) return true end }, { name = "<-", id = 42, x = 234,y = 742, w = 217,h = 48, touch = function(self) if self.Cam.Page == 0 then return end if self.Cam.Fullscreen > 0 then return end self.Cam.Page = self.Cam.Page - 1 if self.Cam.Page == 0 then self.Cam.Wagon = self.Cam.Wagon - 1 if self.Cam.Wagon == 0 then self.Cam.Wagon = self.Cam.WagNum end self.Cam.Page = self.Cam.Cameras[self.Cam.Wagon].Count end return true end, show = function(page) return true end }, { name = "->", id = 43, x = 457,y = 742, w = 218,h = 48, touch = function(self) if self.Cam.Page == 0 then return end if self.Cam.Fullscreen > 0 then return end self.Cam.Page = self.Cam.Page + 1 if self.Cam.Page > self.Cam.Cameras[self.Cam.Wagon].Count then self.Cam.Wagon = self.Cam.Wagon + 1 if self.Cam.Wagon > self.Cam.WagNum then self.Cam.Wagon = 1 end self.Cam.Page = 1 end return true end, show = function(page) return true end }, { name = "☼", id = 44, x = 911,y = 9, w = 119,h = 32, touch = function(self) self.Brightness = self.Brightness + 0.25 if self.Brightness > 1 then self.Brightness = 0.25 end self.Train:SetNW2Float("BMCIK:Brightness",self.Brightness) end, show = function(page) return true end }, -- Наружные камеры { name = "Левые", id = 1, x = 95,y = 183, w = 140,h = 60, touch = function(self) if self.Cam.Page > 0 then return end self.Cam.Wagon = 1 self.Cam.Page = 2 return true end, show = function(page) return page == 0 end }, { name = "Передние", id = 2, x = 241,y = 183, w = 140,h = 60, touch = function(self) if self.Cam.Page > 0 then return end self.Cam.Wagon = 1 self.Cam.Page = 1 return true end, show = function(page) return page == 0 end }, { name = "Вокруг", id = 3, x = 387,y = 183, w = 140,h = 60, touch = function(self) if self.Cam.Page > 0 then return end self.Cam.Wagon = 1 self.Cam.Page = 4 return true end, show = function(page) return page == 0 end }, { name = "Задние", id = 4, x = 533,y = 183, w = 140,h = 60, touch = function(self) if self.Cam.Page > 0 then return end self.Cam.Wagon = self.Cam.WagNum self.Cam.Page = 1 return true end, show = function(page) return page == 0 end }, { name = "Правые", id = 5, x = 679,y = 183, w = 140,h = 60, touch = function(self) if self.Cam.Page > 0 then return end self.Cam.Wagon = 1 self.Cam.Page = 3 return true end, show = function(page) return page == 0 end }, -- Камеры на постах машиниста { name = "Вагон 1", id = 21, x = 215,y = 463, w = 140,h = 60, touch = function(self) if self.Cam.Page > 0 then return end self.Cam.Wagon = 1 self.Cam.Page = 6 return true end, show = function(page) return page == 0 end }, { name = "Вагон %d", id = 22, x = 559,y = 463, w = 140,h = 60, touch = function(self) if self.Cam.Page > 0 then return end self.Cam.Wagon = self.Cam.WagNum self.Cam.Page = 3 return true end, show = function(page) return page == 0 end }, -- Путевые камеры { name = "Вагон 1", id = 31, x = 215,y = 603, w = 140,h = 60, touch = function(self) if self.Cam.Page > 0 then return end self.Cam.Wagon = 1 self.Cam.Page = 5 return true end, show = function(page) return page == 0 end }, { name = "Вагон %d", id = 32, x = 559,y = 603, w = 140,h = 60, touch = function(self) if self.Cam.Page > 0 then return end self.Cam.Wagon = self.Cam.WagNum self.Cam.Page = 2 return true end, show = function(page) return page == 0 end }, } TRAIN_SYSTEM.Buttons.Count = #TRAIN_SYSTEM.Buttons TRAIN_SYSTEM.CamConfig = { -- Dummy [0] = { Count = 0, { PageName = "", Count = 4, {"",Vector(0,0,0),Angle(0,0,0)}, {"",Vector(0,0,0),Angle(0,0,0)}, {"",Vector(0,0,0),Angle(0,0,0)}, {"",Vector(0,0,0),Angle(0,0,0)} }, }, -- 722 Head { Count = 8, { PageName = "Передние зеркала", Count = 2, { "[1] Левый борт, переднее зеркало", Vector(425, 65,40),Angle(10, 170,0) }, { "[2] Правый борт, переднее зеркало", Vector(425,-65,40),Angle(10,-170,0) } }, { Count = 2, PageName = "Левые зеркала", { "[1] Левый борт, переднее зеркало", Vector(425, 65,40),Angle(10, 170,0) }, { "[2] Левый борт, заднее зеркало", Vector(425,-65,40),Angle(10,-170,0), lastWag = true } }, { PageName = "Правые зеркала", Count = 2, { "[1] Правый борт, переднее зеркало", Vector(425,-65,40), Angle(10,-170,0) }, { "[2] Правый борт, заднее зеркало", Vector(425,65,40),Angle(10,170,0), lastWag = true } }, { PageName = "Бортовые зеркала", Count = 4, { "[1] Левый борт, переднее зеркало", Vector(425,65,40),Angle(10,170,0) }, { "[2] Правый борт, переднее зеркало", Vector(425,-65,40),Angle(10,-170,0) }, { "[3] Левый борт, заднее зеркало", Vector(425,-65,40),Angle(10,-170,0), lastWag = true }, { "[4] Правый борт, заднее зеркало", Vector(425,65,40),Angle(10,170,0), lastWag = true } }, { PageName = "Путевые камеры", Count = 1, { "[1] Передняя путевая камера", Vector(490,10,-8),Angle(5,0,0) } }, { PageName = "Кабина машиниста", Count = 1, { "[1] Передняя кабина", Vector(410,35,36.5),Angle(33,-15,0) } }, { PageName = "Салонные камеры", Count = 4, { "[1] Камера в БИТ", Vector(375,-14,45), Angle(20,180,0) }, { "[2] Камера в БИТ", Vector(5,-14,49), Angle(24,0,0) }, { "[3] Камера в БИТ", Vector(-450,14,49), Angle(20,0,0) }, { "[4] Камера в БИТ", Vector(-8,14,49), Angle(24,180,0) } }, { PageName = "Салонные камеры", Count = 2, { "[1] Камера в БЭС", Vector(150,-50,20), Angle(5,95,0), wide = true }, { "[2] Камера в БЭС", Vector(-156, 50,20), Angle(5,-85,0), wide = true } } }, -- 722 Back { Count = 6, { PageName = "Задние зеркала", Count = 2, { "[1] Левый борт, заднее зеркало", Vector(425,-65,40), Angle(10,-170,0) }, { "[2] Правый борт, заднее зеркало", Vector(425,65,40), Angle(10,170,0) } }, { PageName = "Путевые камеры", Count = 1, { "[1] Задняя путевая камера", Vector(490,10,-8), Angle(5,0,0) } }, { PageName = "Кабина машиниста", Count = 1, { "[1] Задняя кабина", Vector(410,35,36.5), Angle(33,-15,0) } }, { PageName = "Салонные камеры", Count = 4, { "[1] Левое зеркало", Vector(425,-65,40), Angle(10,-170,0) }, { "[2] Правое зеркало", Vector(425, 65,40), Angle(10, 170,0) }, { "[3] Путевая камера", Vector(490,10,-8), Angle(5,0,0) }, { "[4] Камера в кабине машиниста", Vector(410,35,36.5), Angle(33,-15,0) } }, { PageName = "Салонные камеры", Count = 4, { "[1] Камера в БИТ", Vector(-450,14,49), Angle(20,0,0) }, { "[2] Камера в БИТ", Vector(-8,14,49), Angle(24,180,0) }, { "[3] Камера в БИТ", Vector(375,-14,45), Angle(20,180,0) }, { "[4] Камера в БИТ", Vector(5,-14,49), Angle(24,0,0) } }, { PageName = "Салонные камеры", Count = 2, { "[1] Камера в БЭС", Vector(150,-50,20), Angle(5,95,0), wide = true }, { "[2] Камера в БЭС", Vector(-156, 50,20), Angle(5,-85,0), wide = true } } }, -- 723/724 Intermediate { Count = 2, { PageName = "Салонные камеры", Count = 4, { "[1] Камера в БИТ", Vector(450,-14,49), Angle(20,180,0) }, { "[2] Камера в БИТ", Vector(5,-14,49), Angle(24,0,0) }, { "[3] Камера в БИТ", Vector(-450,14,49), Angle(20,0,0) }, { "[4] Камера в БИТ", Vector(-8,14,49), Angle(24,180,0) } }, { PageName = "Салонные камеры", Count = 2, { "[1] Камера в БЭС", Vector(150,-50,20), Angle(5,95,0), wide = true }, { "[2] Камера в БЭС", Vector(-156, 50,20), Angle(5,-85,0), wide = true } } } } TRAIN_SYSTEM.SettingsList = { {"Ввод номера маршрута",nil}, {"Режимы работы информатора","AnnModeList"}, {"Режимы работы СОСТАВ-СОСТАВ",nil}, {"Настройка громкости","AnnVolumeList"}, {"Информация","InfoList"}, {"Диагностика","DiagList"}, {"Язык","LangList"}, {"Время на БИТ","BITClockList"} } TRAIN_SYSTEM.AnnModeList = { "Режим 'Информатор'", "Режим 'УПО+Информатор'", "Режим 'УПО+Информатор+Пуск'", "Режим 'УПО'" } TRAIN_SYSTEM.AnnVolumeList = { {"Громкость инф. в кабине","Cabin",0,10}, {"Громкость инф. в салоне","Salon",1,10}, {"Громкость УПО в кабине","UPOCabin",0,10}, {"Громкость УПО в салоне","UPOSalon",1,10}, {"Громкость ЭКСТР./МЕЖКАБ.","EmerCab",0,10}, {"Увеличение при V>5 на","V5",0,10} } TRAIN_SYSTEM.InfoList = { {"MIES firmware version 20181203",nil}, {"NIIP DOORS_closed= ","BMCIK:AddInfoNIIPDoors"}, {"NIIP RUCHKA= ",nil}, {"NIIP SPEED= ","BMCIK:AddInfoNIIPSpeed"}, {"NIIP UPO_STATE= ","BMCIK:AddInfoUPO"}, {"NIIP Evacuation= ",nil}, {"NIIP Vzlom_kabiny= ",nil}, {"Video sended= ","BMCIK:AddInfoVideo"}, {"AVT.State.State_byte= ",nil}, {"AVT.Now_S.code= ",nil}, {"AVT.Next_S.code= ",nil}, {"AVT.Final_S.code= ",nil}, {"AVT.Met= ",nil} } TRAIN_SYSTEM.DiagList = { "Advanced LAN diagnostics", "Advanced CAN diagnostics", "BMCIK 0/0", "MIES 0/0", "MDU 0/0", "MAR 0/0", "BES LAN 0/0", "BES CAN 0/0", "BNT(BUM) 0/0", "BIT 0/0", "BVK 0/0", "BMTS 0/0" } TRAIN_SYSTEM.LangList = { "Russian", -- "English", -- "Hungarian" } TRAIN_SYSTEM.BITClockList = { "Время выключено", "Время включено" } TRAIN_SYSTEM.CIKStatesNames = { [0] = "Готов", [1] = "Воспроизведение...", [2] = "Межкабинная связь активна", [3] = "Громкая связь", -- [4] = "Нет связи", -- [5] = "Связь восстановлена", -- [6] = "Линия свободна" } TRAIN_SYSTEM.HeaderNames = { [0] = "---", [1] = "---", [11] = "Предупредительные\nсообщения", [12] = "Ограничение маршрута", [13] = "Дополнительные сообщения", [14] = "Экстренные сообщения", [15] = "Выбор линии", [2] = "Меню настройки блока\nСБУЦИК", [21] = "Меню настройки блока\nСБУЦИК", [22] = "Режимы работы\nинформатора", [23] = "Режимы работы блока\nСБУЦИК", [24] = "Настройка громкости", [25] = "Additional information", [26] = "Диагностика (0%)", [27] = "Язык", [28] = "Отображение времени на\nБИТ" } local function setBitValue(targetVar, value, offset, bitCount) value = bit.band(value,bit.lshift(1,bitCount)-1) return bit.bor(targetVar,bit.lshift(value,offset)) end local function getBitValue(value, offset, bitCount) local mask = bit.lshift(bit.lshift(1,bitCount)-1,offset) return bit.rshift(bit.band(value,mask),offset) end -- Announcer functions function TRAIN_SYSTEM:Announcer_Reset(resetAnn) local Announcer = self.Announcer self:Announcer_Stop() self:Announcer_CabStop() Announcer.State = 0 Announcer.CIKState = 0 Announcer.Active = false if resetAnn then Announcer.Line = 0 Announcer.Volumes.Cabin = 5 Announcer.Volumes.Salon = 5 Announcer.Volumes.UPOCabin = 5 Announcer.Volumes.UPOSalon = 5 Announcer.Volumes.EmerCab = 5 Announcer.Volumes.V5 = 0 Announcer.BITTime = false end Announcer.LimitStation = false Announcer.Path = false Announcer.PathSel = false Announcer.Station = 0 Announcer.OnStation = false Announcer.Mode = 3 Announcer.TrainTrain = false Announcer.LineEnabled = false self.Train:SetNW2Int("BMCIK:Announcer",0) self.Train:SetNW2Bool("BMCIK:LineEnabled",false) end function TRAIN_SYSTEM:Announcer_Activate(forceActive) local Announcer = self.Announcer if (not forceActive and Announcer.Active) or Announcer.Line == 0 then return end -- TODO: Try to implement better logic of UPO noise sync local Train = self.Train local noiseVolume = Train.UPONoiseVolume local upoVolume = Train.UPOVolume local wagList = Train.WagonList for i=1,#wagList do wagList[i]:SetNW2Float("UPONoiseVolume",noiseVolume) wagList[i]:SetNW2Float("UPOVolume",upoVolume) end self:Announcer_FindLimitStations() Announcer.LimitStation = false self:Announcer_Zero() self:Announcer_SetState(1,#Metrostroi.SarmatUPOSetup[Train:GetNW2Int("Announcer")][Announcer.Line]*2) end function TRAIN_SYSTEM:Announcer_SetState(state,count) local Announcer = self.Announcer self:List_Save(Announcer.State) Announcer.PrevState = Announcer.State Announcer.State = state self:List_Reset(count) end function TRAIN_SYSTEM:Announcer_FindLimitStations() local Announcer = self.Announcer local lTbl = Metrostroi.SarmatUPOSetup[self.Train:GetNW2Int("Announcer")][Announcer.Line] Announcer.LastStations = {} if lTbl.Loop then for i=1,#lTbl do if lTbl[i].arrlast then table.insert(Announcer.LastStations,i) end end else for i=2,#lTbl-1 do if lTbl[i].arrlast then table.insert(Announcer.LastStations,i) end end end end function TRAIN_SYSTEM:Announcer_Zero() local Announcer = self.Announcer local Train = self.Train local lTbl = Metrostroi.SarmatUPOSetup[Train:GetNW2Int("Announcer")][Announcer.Line] if Announcer.Line < 1 then return end self:Announcer_Stop() Announcer.Active = true Announcer.Path = Announcer.PathSel Announcer.Station = Announcer.Path and #lTbl or 1 Announcer.OnStation = false Announcer.AVTDepart = false Train:CANWrite("BMCIK",nil,"BNT",nil,self.CAN_CLOSERING,false) Train:CANWrite("BMCIK",Train:GetWagonNumber(),"BMCIK",nil,self.CAN_ACTIVATE) Train:CANWrite("BMCIK",nil,"BNT",nil,self.CAN_ACTIVATE) Train:CANWrite("BMCIK",nil,"BIT",nil,self.CAN_ACTIVATE) Train:CANWrite("BMCIK",nil,"BNT",nil,self.CAN_VOLUMES,{Announcer.Volumes.Salon,Announcer.Volumes.UPOSalon,Announcer.Volumes.V5}) self:BMTS_Update() self:CANUpdate() end function TRAIN_SYSTEM:Announcer_Prev() local Announcer = self.Announcer local lTbl = Metrostroi.SarmatUPOSetup[self.Train:GetNW2Int("Announcer")][Announcer.Line] if Announcer.OnStation then Announcer.OnStation = false else if Announcer.Path then if #lTbl > Announcer.Station then Announcer.Station = Announcer.Station+1 Announcer.OnStation = true end else if Announcer.Station > 1 then Announcer.Station = Announcer.Station-1 Announcer.OnStation = true end end end end function TRAIN_SYSTEM:Announcer_Next(returnToStart) local Announcer = self.Announcer local lTbl = Metrostroi.SarmatUPOSetup[self.Train:GetNW2Int("Announcer")][Announcer.Line] local maxStation = Announcer.LimitStation or (Announcer.Path and 1 or #lTbl) if Announcer.OnStation then if Announcer.Path then if Announcer.Station > maxStation then Announcer.Station = Announcer.Station-1 Announcer.OnStation = false elseif returnToStart and maxStation == Announcer.Station then Announcer.Station = #lTbl Announcer.OnStation = false return true end else if maxStation > Announcer.Station then Announcer.Station = Announcer.Station+1 Announcer.OnStation = false elseif returnToStart and maxStation == Announcer.Station then Announcer.Station = 1 Announcer.OnStation = false return true end end else Announcer.OnStation = true local last = not lTbl.Loop and Announcer.Station == (Announcer.Path and 1 or #lTbl) if Announcer.LimitStation then last = Announcer.LimitStation == Announcer.Station end Announcer.CurrentLast = last end end function TRAIN_SYSTEM:Announcer_Queue(msg) local AnnouncerSys = self.Train.Announcer if msg and type(msg) ~= "table" then AnnouncerSys:Queue{msg} else AnnouncerSys:Queue(msg) end end function TRAIN_SYSTEM:Announcer_CabPlay() if self.LineOut > 0 then return end local Announcer = self.Announcer local lTbl = Metrostroi.SarmatUPOSetup[self.Train:GetNW2Int("Announcer")][Announcer.Line] if not lTbl then return end local sTbl = lTbl[Announcer.Station] Announcer.CabPlay = true self.Train:CANWrite("BMCIK",nil,"BNT",nil,self.CAN_VOLUMES,{0,0,0}) self.Train.Announcer.AnnounceTimer = CurTime()+0.2 -- Silent sound fix at begin playing self:Announcer_Queue("tone") local message local last = not lTbl.Loop and Announcer.Station == (Announcer.Path and 1 or #lTbl) if Announcer.LimitStation then last = Announcer.LimitStation == Announcer.Station end if Announcer.OnStation then if sTbl.odz then self:Announcer_Queue(sTbl.odz) end message = sTbl.dep and sTbl.dep[Announcer.Path and 2 or 1] else if last then message = sTbl.arrlast and sTbl.arrlast[Announcer.Path and 2 or 1] else message = sTbl.arr and sTbl.arr[Announcer.Path and 2 or 1] end end if not message then return end self:Announcer_Queue(message) end function TRAIN_SYSTEM:Announcer_CabStop() local Announcer = self.Announcer if not Announcer.CabPlay then return end Announcer.CabPlay = false self.Train:CANWrite("BMCIK",nil,"BNT",nil,self.CAN_VOLUMES,{Announcer.Volumes.Salon,Announcer.Volumes.UPOSalon,Announcer.Volumes.V5}) end function TRAIN_SYSTEM:Announcer_Play() local Announcer = self.Announcer if Announcer.UPOLock then return end if Announcer.Mode > 3 then return end local lTbl = Metrostroi.SarmatUPOSetup[self.Train:GetNW2Int("Announcer")][Announcer.Line] if not lTbl then return end local sTbl = lTbl[Announcer.Station] self:Announcer_Stop() self:Announcer_Queue("tone") local message local last = not lTbl.Loop and Announcer.Station == (Announcer.Path and 1 or #lTbl) if Announcer.LimitStation then last = Announcer.LimitStation == Announcer.Station end if Announcer.OnStation then if sTbl.odz then self:Announcer_Queue(sTbl.odz) end message = sTbl.dep and sTbl.dep[Announcer.Path and 2 or 1] else if last then message = sTbl.arrlast and sTbl.arrlast[Announcer.Path and 2 or 1] self:Announcer_Queue(-1) else message = sTbl.arr and sTbl.arr[Announcer.Path and 2 or 1] end end Announcer.CurrentLast = last if not message then return end self:Announcer_Queue(message) end function TRAIN_SYSTEM:Announcer_Stop() self:Announcer_CabStop() self.LineOut = 0 self.UPOActive = 0 self.Announcer.UPOLock = false self.Train.Announcer.AnnounceTimer = CurTime()+0.2 -- Silent sound fix at begin playing self.Train.Announcer:TriggerInput("Reset","AnnouncementsSarmatUPO") end -- Cameras control functions function TRAIN_SYSTEM:Cam_Scan() local Cam = self.Cam local Train = self.Train local wagList = Train.WagonList Cam.WagNum = #wagList Cam.Cameras = {} local lastWag = wagList[Cam.WagNum] for w=1,Cam.WagNum do local iWag = wagList[w] local iWagType = w==1 and 1 or (iWag.SubwayTrain.WagType==1 and w==Cam.WagNum) and 2 or 3 local wagCamTbl = self.CamConfig[iWagType] Cam.Cameras[w] = { wagEnt = iWag, wagNum = iWag:GetWagonNumber(), wagType = iWagType, Count = wagCamTbl.Count } for page=1,wagCamTbl.Count do Cam.Cameras[w][page] = {} for iCam=1,wagCamTbl[page].Count do Cam.Cameras[w][page][iCam] = wagCamTbl[page][iCam].lastWag and lastWag or iWag end end end Cam.TrainLen = Cam.WagNum*20 Cam.LoadingTimer = nil Train:SetNW2Int("BMCIK:WagNum",Cam.WagNum) end function TRAIN_SYSTEM:Cam_Open(wagon,page) local Cam = self.Cam if Cam.Page > 0 then return end Cam.AutoOpen = true Cam.Distance = 0 Cam.Wagon = wagon Cam.Page = page for i=1,4 do Cam[i].Link = CurTime()+math.Rand(0.2,1) Cam[i].Ent = Cam.Cameras[Cam.Wagon][Cam.Page][i] if i > #Cam.Cameras[Cam.Wagon][Cam.Page] then Cam[i].Link = nil Cam[i].Ent = NULL end end local Train = self.Train Train:SetNW2Int("BMCIK:CamWagIndex",Cam.Wagon) Train:SetNW2Int("BMCIK:CamType",Cam.Cameras[Cam.Wagon].wagType) Train:SetNW2Int("BMCIK:CamWagNumber",Cam.Cameras[Cam.Wagon].wagNum) end function TRAIN_SYSTEM:Cam_Close() local Cam = self.Cam Cam.Page = 0 for i=1,4 do Cam[i].Link = nil Cam[i].Ent = NULL end local Train = self.Train Train:SetNW2Int("BMCIK:CamWagIndex",0) Train:SetNW2Int("BMCIK:CamType",0) Train:SetNW2Int("BMCIK:CamWagNumber",0) end function TRAIN_SYSTEM:Cam_Reset() local Cam = self.Cam Cam.Page = 0 Cam.Wagon = 0 Cam.Fullscreen = 0 Cam.AutoOpen = false Cam[1] = {Link = nil,Ent = NULL} Cam[2] = {Link = nil,Ent = NULL} Cam[3] = {Link = nil,Ent = NULL} Cam[4] = {Link = nil,Ent = NULL} end -- List functions function TRAIN_SYSTEM:List_Save(state) local List = self.List List.States[state] = {Count = List.Count,Selected = List.Selected,Offset = List.Offset} end function TRAIN_SYSTEM:List_Load(state) local List = self.List if not List.States[state] then return end local saveState = List.States[state] saveState.Selected = math.min(saveState.Selected,saveState.Count) local dOffset = saveState.Count - saveState.Offset - 21 if dOffset < 0 then saveState.Offset = math.max(0,saveState.Offset + dOffset) end List.Count = saveState.Count List.Selected = saveState.Selected List.Offset = saveState.Offset List.States[state] = nil end function TRAIN_SYSTEM:List_Set(state, sel) local List = self.List if state and self.Announcer.State ~= state and List.States[state] then List = List.States[state] end if sel == List.Selected or sel > List.Count then return end List.Selected = sel local cursorPos = List.Selected - List.Offset local dOffset if cursorPos < 1 then dOffset = cursorPos - 1 elseif cursorPos > 21 then dOffset = cursorPos - 21 end if dOffset then List.Offset = math.Clamp(List.Offset + dOffset,0,List.Count-21) end end function TRAIN_SYSTEM:List_GetSelectedItem() return self.List.Selected end function TRAIN_SYSTEM:List_Prev(state) local List = self.List if state and self.Announcer.State ~= state and List.States[state] then List = List.States[state] end if List.Count < 2 then return end local lastSel = List.Selected List.Selected = math.max(1,List.Selected - 1) if List.Selected-List.Offset == 0 and List.Selected ~= lastSel then List.Offset = List.Offset-1 end end function TRAIN_SYSTEM:List_Next(state) local List = self.List if state and self.Announcer.State ~= state and List.States[state] then List = List.States[state] end if List.Count < 2 then return end local lastSel = List.Selected List.Selected = math.min(List.Count,List.Selected + 1) if List.Selected-List.Offset > 21 and List.Selected ~= lastSel then List.Offset = List.Offset+1 end end function TRAIN_SYSTEM:List_Reset(count) local List = self.List List.Selected = 1 List.Offset = 0 List.ListTimer = nil List.ListTimerDir = nil List.Count = count or 0 end function TRAIN_SYSTEM:CANReceive(source,sourceid,target,targetid,textdata,numdata) if textdata == self.CAN_BMTS_TEXT then self.BMTS.Text = numdata self.BMTS.Update = true return end if sourceid == self.Train:GetWagonNumber() then return end if textdata == self.CAN_ACTIVATE then if self.Announcer.Active then self.Announcer.Active = false self.Announcer.AVTDepart = false self:Cam_Close() end end if textdata == self.CAN_CIKSTATE then self.Announcer.CIKStateIntercab = numdata end end function TRAIN_SYSTEM:TriggerInput(name,value) if not self.Announcer.Active then return end if name == "OpenDoors" then if value == 0x4C then self:Cam_Open(1,2) elseif value == 0x52 then self:Cam_Open(1,3) end end local Announcer = self.Announcer if name == "CheckUPO" then if self.UPOActive == 0 or self.LineOut>0 or math.random()>0.95 then return false end if not Announcer.OnStation then self:Announcer_Next() self:List_Next(1) self:CANUpdate() end return true end if name == "ClosedDoors" then self.Train:CANWrite("BMCIK",nil,"BNT",nil,self.CAN_CLOSERING,false) end if name == "OpenDoors" then self.Train:CANWrite("BMCIK",nil,"BNT",nil,self.CAN_CLOSERING,false) if Announcer.AVTDepart then Announcer.AVTDepart = false self:CANUpdate() return end if not Announcer.OnStation then self:Announcer_Play() self:Announcer_Next() self:List_Next(1) self:CANUpdate() end end if name == "CloseDoorsAVT" then Announcer.AVTDepart = Announcer.OnStation if Announcer.AVTDepart then self:Announcer_Play() self:CANUpdate() end self.Train:CANWrite("BMCIK",nil,"BNT",nil,self.CAN_CLOSERING,true) end end function TRAIN_SYSTEM:CANUpdate() local Announcer = self.Announcer local lTbl = Metrostroi.SarmatUPOSetup[self.Train:GetNW2Int("Announcer")][Announcer.Line] local lTblCount = #lTbl local ledTbl = lTbl.LED or {} local currLed, nextLed = 0,0 local station = Announcer.Station if Announcer.AVTDepart then if Announcer.Path then station = station - 1 if station < 1 then station = #ledTbl end else station = station + 1 if station > #ledTbl then station = 1 end end end for i=(Announcer.Path and #ledTbl or 1),station,(Announcer.Path and -1 or 1) do currLed = currLed + (ledTbl[i] or 0) end if Announcer.AVTDepart or not Announcer.OnStation then nextLed = ledTbl[station] or 0 currLed = currLed - nextLed end local sTbl = lTbl[station] local first,sTblPrev,sTblNext if lTbl.Loop and not Announcer.Limit then first = 0 if Announcer.Path then sTblNext = ((station-1) < 1) and lTbl[lTblCount] or lTbl[station-1] sTblPrev = ((station+1) > lTblCount) and lTbl[1] or lTbl[station+1] else sTblPrev = ((station-1) < 1) and lTbl[lTblCount] or lTbl[station-1] sTblNext = ((station+1) > lTblCount) and lTbl[1] or lTbl[station+1] end else if Announcer.Path then first = lTblCount sTblPrev = station < lTblCount and lTbl[station+1] sTblNext = station > 1 and lTbl[station-1] else first = 1 sTblPrev = station > 1 and lTbl[station-1] sTblNext = station < lTblCount and lTbl[station+1] end end local bitText = "---" local bitLeft,bitRight local bitLoop = 1 if not Announcer.AVTDepart and Announcer.OnStation then if Announcer.CurrentLast then bitLeft = "" bitRight = Format("%s >",sTbl[2]) bitLoop = 4 bitText = Format("%%rПоезд прибыл\n%%rна конечную станцию\n%%r%s",sTbl[2]) if sTbl.right_doors then bitText = bitText..",\n%%rвыход\n%%rна правую сторону.\n" bitLoop = bitLoop + 2 else bitText = bitText..".\n" end else bitLeft = sTblPrev and sTblPrev[2] or "" bitRight = sTblNext and Format("%s >",sTblNext[2]) bitLoop = 5 bitText = Format("%%yСтанция\n%%y%s",sTbl[2]) if sTbl.right_doors then bitText = bitText..",\n%%yвыход\n%%yна правую сторону.\n" bitLoop = bitLoop + 2 else bitText = bitText..".\n" end bitText = bitText..Format("%%yСледующая станция\n%%y%s",sTblNext[2]) if sTblNext and sTblNext.right_doors then bitText = bitText..",\n%%yвыход\n%%yна правую сторону.\n" bitLoop = bitLoop + 2 else bitText = bitText..".\n" end end if sTbl.messagearr then bitLoop = bitLoop + #string.Explode("\n",sTbl.messagearr) bitText = bitText..(sTbl.messagearr).."\n" end bitText = bitText.."\n." elseif Announcer.AVTDepart or station ~= first then bitLeft = sTblPrev and sTblPrev[2] bitRight = Format("%s >",sTbl[2]) bitLoop = 5 bitText = Format("%%rОсторожно,\n%%rдвери закрываются!\n%%yСледующая станция\n%%y%s",sTbl[2]) if sTbl.right_doors then bitText = bitText..",\n%%yвыход\n%%yна правую сторону.\n" bitLoop = bitLoop + 2 else bitText = bitText..".\n" end if sTblPrev and sTblPrev.messagedep then bitLoop = bitLoop + #string.Explode("\n",sTblPrev.messagedep) bitText = bitText..(sTblPrev.messagedep).."\n" end bitText = bitText.."\n." end self.Train:CANWrite("BMCIK",nil,"BNT",nil,self.CAN_CURR,currLed) self.Train:CANWrite("BMCIK",nil,"BNT",nil,self.CAN_NEXT,nextLed) self.Train:CANWrite("BMCIK",nil,"BNT",nil,self.CAN_PATH,Announcer.Path) self.Train:CANWrite("BMCIK",nil,"BIT",nil,self.CAN_BITTEXT,{Text = string.Explode("\n",bitText), Left = bitLeft, Right = bitRight, Loop = bitLoop}) end function TRAIN_SYSTEM:BMTS_Update() local lTbl = Metrostroi.SarmatUPOSetup[self.Train:GetNW2Int("Announcer")][self.Announcer.Line] local bmtsText = lTbl[self.Announcer.LimitStation or (self.Announcer.Path and 1 or #lTbl)][2] if lTbl.Loop and not self.Announcer.LimitStation then bmtsText = "КОЛЬЦЕВОЙ" end self.Train:CANWrite("BMCIK",nil,"BMCIK",nil,self.CAN_BMTS_TEXT,bmtsText) end local function InRange(px,py,x,y,w,h) return (px >= x and px <= (x+w) and py >= y and py <= (y+h)) end function TRAIN_SYSTEM:Touch(value,x,y) if self.State < 1 then return end local btnID = 0 local newPage = false if self.Cam.Page > 0 then if not value and self.Cam.Fullscreen == 0 then local camCountPage = #self.Cam.Cameras[self.Cam.Wagon][self.Cam.Page] if camCountPage == 4 then if InRange(x,y,24,58,430,328,"[1]") then self.Cam.Fullscreen = 1 elseif InRange(x,y,460,58,430,328,"[2]") then self.Cam.Fullscreen = 2 elseif InRange(x,y,24,392,430,328,"[3]") then self.Cam.Fullscreen = 3 elseif InRange(x,y,460,392,430,328,"[4]") then self.Cam.Fullscreen = 4 end elseif camCountPage == 2 then if InRange(x,y,24,58,430,662,"[1]") then self.Cam.Fullscreen = 1 elseif InRange(x,y,460,58,430,662,"[2]") then self.Cam.Fullscreen = 2 end end end else local wagNum = self.Cam.WagNum for i=1,wagNum do if (wagNum == 8 and InRange(x,y,350+(i-wagNum/2)*110,323,104,60)) or (wagNum == 7 and InRange(x,y,334+(i-wagNum/2)*126,323,120,60)) or (wagNum <= 6 and InRange(x,y,313+(i-wagNum/2)*147,323,141,60)) then btnID = 10 + i if not value then self.Cam.Wagon = i self.Cam.Page = self.Cam.Cameras[i].wagType == 1 and 7 or self.Cam.Cameras[i].wagType == 2 and 5 or 1 newPage = true end end end end for i=1,#self.Buttons do local btn = self.Buttons[i] if btn.show(self.Cam.Page) and InRange(x,y,btn.x,btn.y,btn.w,btn.h) then if not value and btn.touch then newPage = btn.touch(self) end btnID = btn.id end end if newPage then self.Cam.AutoOpen = false for i=1,4 do self.Cam[i].Link = CurTime()+math.Rand(0.2,1) self.Cam[i].Ent = self.Cam.Cameras[self.Cam.Wagon][self.Cam.Page][i] if i > #self.Cam.Cameras[self.Cam.Wagon][self.Cam.Page] then self.Cam[i].Link = nil self.Cam[i].Ent = NULL end end self.Train:SetNW2Int("BMCIK:CamWagIndex",self.Cam.Wagon) self.Train:SetNW2Int("BMCIK:CamType",self.Cam.Cameras[self.Cam.Wagon].wagType) self.Train:SetNW2Int("BMCIK:CamWagNumber",self.Cam.Cameras[self.Cam.Wagon].wagNum) end self.Train:SetNW2Int("BMCIK:IDTouched",btnID or 0) end function TRAIN_SYSTEM:Trigger(name,value) name = name:gsub("Sarmat","") if name ~= "Up" and name ~= "Down" and not value then return end local Train = self.Train local annTbl = Metrostroi.SarmatUPOSetup[Train:GetNW2Int("Announcer")] local Announcer = self.Announcer local annState = Announcer.State local selected = self:List_GetSelectedItem() if annState == 1 then if name == "Up" or name == "Down" or name == "Enter" or name == "Start" then Announcer.AVTDepart = false end end if annState == 12 and name == "Esc" then if Announcer.PrevLimitStation ~= Announcer.LimitStation then if Announcer.LimitStation then self.List.States[1].Count = (Announcer.Path and (#annTbl[Announcer.Line] - Announcer.LimitStation + 1) or Announcer.LimitStation)*2 local lastStation = Announcer.Station if Announcer.Path then Announcer.Station = math.max(Announcer.Station,Announcer.LimitStation) else Announcer.Station = math.min(Announcer.Station,Announcer.LimitStation) end if lastStation ~= Announcer.Station then Announcer.OnStation = true end else self.List.States[1].Count = #annTbl[Announcer.Line]*2 end self:BMTS_Update() Announcer.PrevLimitStation = nil end end if annState == 23 and Announcer.TrainTrain and (name == "Esc" or name == "Zero") then Announcer.TrainTrain = false return end ---- ▲ if name == "Up" then if value then self:List_Prev() if annState == 1 then self:Announcer_Prev() end if self.ListTimerDir == nil then self.ListTimer = CurTime()+0.4 self.ListTimerDir = false end else self.ListTimer = nil self.ListTimerDir = nil end ---- ▼ elseif name == "Down" then if value then self:List_Next() if annState == 1 then self:Announcer_Next() end if self.ListTimerDir == nil then self.ListTimer = CurTime()+0.4 self.ListTimerDir = true end else self.ListTimer = nil self.ListTimerDir = nil end ---- Enter elseif name == "Enter" then if annState == 0 then return end if annState == 1 then self:Announcer_CabPlay() elseif annState == 2 then Announcer.PrevState2 = Announcer.PrevState local sTbl = self[self.SettingsList[selected][2]] self:Announcer_SetState(20+selected,sTbl and #sTbl or 1) if selected == 5 then local Cam = self.Cam local videoSended = (Cam[1].Link==true or Cam[2].Link==true or Cam[3].Link==true or Cam[4].Link==true) and 1 or 0 Train:SetNW2Int("BMCIK:AddInfoNIIPDoors",self.NIIP.DOORS_closed) Train:SetNW2Int("BMCIK:AddInfoNIIPSpeed",self.NIIP.SPEED) Train:SetNW2Int("BMCIK:AddInfoUPO",self.UPOActive) Train:SetNW2Int("BMCIK:AddInfoVideo",videoSended) end elseif annState > 10 and annState < 20 then if annState == 12 then local selLast = Announcer.LastStations[selected] if Announcer.LimitStation == selLast then Announcer.LimitStation = false else Announcer.LimitStation = selLast end elseif annState == 15 then if Announcer.Active and selected == Announcer.Line then self:List_Load(1) Announcer.State = 1 return end Announcer.Line = selected self:Announcer_Activate(true) end elseif annState > 20 then if annState == 22 then Announcer.Mode = selected elseif annState == 23 then if not Announcer.TrainTrain then Announcer.TrainTrain = true end elseif annState == 24 then local selItem = self.AnnVolumeList[selected] local volumes = self.Announcer.Volumes volumes[selItem[2]] = volumes[selItem[2]] + 1 if volumes[selItem[2]] > selItem[4] then volumes[selItem[2]] = selItem[3] end -- -- from 0 to N with a resolution of 10. The value of N can be calculated using the formula N = 100 - P, -- -- where P - is the value of the volume level set in the line «Громкость инф. в салоне». -- -- TODO: See how it works in 81-765 and do it by analogy self.Train:CANWrite("BMCIK",nil,"BNT",nil,self.CAN_VOLUMES,{volumes.Salon,volumes.UPOSalon,volumes.V5}) elseif annState == 28 then Announcer.BITTime = selected == 2 self.Train:CANWrite("BMCIK",nil,"BIT",nil,self.CAN_BITTIME,Announcer.BITTime) end end ---- Esc elseif name == "Esc" then if annState == 1 then -- Single click delay if not self.EscBtnTimer then self.EscBtnTimer = CurTime() + 0.3 return end -- Double click self.EscBtnTimer = nil self:Announcer_SetState(14,1) return end if not Announcer.PrevState then return end self:List_Load(Announcer.PrevState) Announcer.State = Announcer.PrevState Announcer.PrevState = Announcer.PrevState2 Announcer.PrevState2 = nil ---- F1 elseif name == "F1" then if annState ~= 1 then return end self:Announcer_SetState(11,1) ---- F2 elseif name == "F2" then if annState ~= 1 then return end Announcer.PrevLimitStation = Announcer.LimitStation self:Announcer_SetState(12,#Announcer.LastStations) ---- F3 elseif name == "F3" then if annState ~= 1 then return end self:Announcer_SetState(13,1) ---- F4 elseif name == "F4" then if annState > 1 then return end self:Announcer_SetState(2,#self.SettingsList) ---- ПУТЬ elseif name == "Path" then if Announcer.Line == 0 then return end Announcer.PathSel = not Announcer.PathSel --- >0< elseif name == "Zero" then if annState > 1 then return end -- Single click delay if not self.ZeroBtnTimer then self.ZeroBtnTimer = CurTime() + 0.3 return end -- Double click self.ZeroBtnTimer = nil local prevClear = annState == 0 if annTbl then self:Announcer_SetState(15,#annTbl) end if prevClear then Announcer.PrevState = nil end ---- ЛИНИЯ elseif name == "Line" then Announcer.LineEnabled = not Announcer.LineEnabled ---- ПУСК elseif name == "Start" then if annState == 1 and Announcer.Mode == 3 then self:Announcer_Play() self:Announcer_Next() self:List_Next() -- if self:Announcer_Next(true) then -- self:List_Set(1,1) -- else -- self:List_Next(1) -- end self:CANUpdate() end end end function TRAIN_SYSTEM:Think(dT) local Train = self.Train -- BMCIK-01 logic local Power = Train.Electric.Power > 0 and (Train.SF16.Value + Train.SF17.Value) > 0 if Power then local Cam = self.Cam local Announcer = self.Announcer if self.State > 0 then ---- Buttons -------------------- local valBtn = false for k,v in pairs(self.TriggerNames) do valBtn = Train[v].Value > 0.5 if Train[v] and (valBtn) ~= self.Triggers[v] then self:Trigger(v,valBtn) self.Triggers[v] = valBtn end end if self.ZeroBtnTimer and CurTime() > self.ZeroBtnTimer then self.ZeroBtnTimer = nil if Announcer.State == 0 then self:Announcer_Activate() elseif Announcer.State == 1 then self:Announcer_Zero() local lTbl = Metrostroi.SarmatUPOSetup[Train:GetNW2Int("Announcer")][Announcer.Line] local countSt = Announcer.LimitStation and (Announcer.Path and #lTbl - Announcer.LimitStation + 1 or Announcer.LimitStation) or #lTbl self:List_Reset(countSt*2) end end if self.EscBtnTimer and CurTime() > self.EscBtnTimer then self.EscBtnTimer = nil end ---- BUKP CAN ------------------- if CurTime() > self.CAN_SU then self.CAN_SU = CurTime()+0.1 local BUKP = Train.BUKP local niipSpeed = math.floor(BUKP.Speed) if self.NIIP.SPEED ~= niipSpeed then Train:CANWrite("BMCIK",nil,"BNT",nil,self.CAN_SPEED,niipSpeed) self.NIIP.SPEED = niipSpeed end self.NIIP.DOORS_closed = BUKP.LSD and 1 or 0 local cabAcitve = Train.Electric.CabActive if self.NIIP.CabActive ~= cabAcitve then if cabAcitve > 0 then -- ПГК self:Announcer_Activate() end self.NIIP.CabActive = cabAcitve end end ---- Cameras -------------------- if Cam.Page > 0 then local wags = {false,false,false,false} local wagList = Train.WagonList for i=1,Cam.WagNum do local iWag = wagList[i] if Cam[1].Link and Cam[1].Ent == iWag then wags[1] = true end if Cam[2].Link and Cam[2].Ent == iWag then wags[2] = true end if Cam[3].Link and Cam[3].Ent == iWag then wags[3] = true end if Cam[4].Link and Cam[4].Ent == iWag then wags[4] = true end end local camC = 0 for i=1,4 do local iCam = Cam[i] if iCam.Link == true then Train:SetNW2Entity("BMCIK:CamE"..i,iCam.Ent) if not wags[i] or iCam.Ent.Electric.Power < 1 then iCam.Link = false end else if iCam.Link and CurTime() > iCam.Link then iCam.Link = wags[i] end end camC = setBitValue(camC,iCam.Link==true and 1 or 0,i-1,1) end camC = setBitValue(camC,Cam.Fullscreen,4,3) Train:SetNW2Int("BMCIK:Cam",camC) if Cam.AutoOpen then Cam.Distance = Cam.Distance + self.NIIP.SPEED*dT/3.6 if Cam.Distance > Cam.TrainLen then self:Cam_Close() Cam.AutoOpen = nil Cam.Distance = nil end end end Train:SetNW2Int("BMCIK:CamPage",Cam.Page) ---- Announcer ------------------ local annPlaying = Train:GetNW2Bool("AnnouncerPlaying") if Announcer.State > 0 then if Announcer.Active then if Announcer.AVTDepart then if self.NIIP.SPEED > 3 then if self:Announcer_Next(true) then self:List_Set(1,1) else self:List_Next(1) end Announcer.AVTDepart = false end end if Announcer.CabPlay and not annPlaying and #Train.Announcer.Schedule == 0 then self:Announcer_CabStop() end self.LineOut = (Train.Announcer.AnnTable=="AnnouncementsSarmatUPO" and annPlaying) and 1 or 0 self.UPOActive = Announcer.Mode > 1 and 1 or 0 if self.UPOActive > 0 then Announcer.UPOLock = Train.UPO.LineOut > 0 end Train:SetNW2Int("BMCIK:VolCab",Announcer.UPOLock and Announcer.Volumes.UPOCabin or Announcer.Volumes.Cabin) else if Announcer.State == 1 or (Announcer.State > 10 and Announcer.State < 20 and Announcer.State ~= 15) then self:Announcer_Stop() Train:SetNW2Int("BMCIK:VolCab",0) Announcer.State = 0 end end if self.ListTimer and CurTime() > self.ListTimer then if self.ListTimerDir then self:List_Next() if Announcer.State == 1 then self:Announcer_Next() end else self:List_Prev() if Announcer.State == 1 then self:Announcer_Prev() end end self.ListTimer = CurTime()+0.2 end if Announcer.State > 20 then if Announcer.State == 22 then Train:SetNW2Int("BMCIK:AnnMode",Announcer.Mode) elseif Announcer.State == 23 then Train:SetNW2Bool("BMCIK:TrainTrain",Announcer.TrainTrain) elseif Announcer.State == 24 then local volumes = 0 local annVolumes = Announcer.Volumes volumes = setBitValue(volumes,annVolumes.Cabin,0,4) volumes = setBitValue(volumes,annVolumes.Salon,4,4) volumes = setBitValue(volumes,annVolumes.UPOCabin,8,4) volumes = setBitValue(volumes,annVolumes.UPOSalon,12,4) volumes = setBitValue(volumes,annVolumes.EmerCab,16,4) volumes = setBitValue(volumes,annVolumes.V5,20,4) Train:SetNW2Int("BMCIK:VolumesPage",volumes) elseif Announcer.State == 28 then Train:SetNW2Bool("BMCIK:BITTime",Announcer.BITTime) end end Train:SetNW2Int("BMCIK:ListSelect",self.List.Selected) Train:SetNW2Int("BMCIK:ListOffset",self.List.Offset) else Announcer.Active = false self.LineOut = annPlaying and 1 or 0 self.UPOActive = 0 end local cikState = 0 if Train.Microphone.Value > 0 then if Announcer.LineEnabled then cikState = 3 -- Громкая связь else cikState = 2 -- Межкабинная связь активна end elseif self.LineOut + Train.UPO.LineOut > 0 then cikState = 1 -- Воспроизведение... else cikState = 0 -- Готов end if Announcer.CIKStateIntercab then cikState = Announcer.CIKStateIntercab end if Announcer.CIKState ~= cikState then if not Announcer.CIKStateIntercab then Train:CANWrite("BMCIK",Train:GetWagonNumber(),"BMCIK",nil,self.CAN_CIKSTATE,cikState > 1 and cikState or nil) end if Announcer.Active and cikState == 3 and self.LineOut then self:Announcer_Stop() end Announcer.CIKState = cikState end local ann = 0 ann = setBitValue(ann,Announcer.State,0,6) ann = setBitValue(ann,Announcer.CIKState,6,4) ann = setBitValue(ann,Announcer.Line,10,8) ann = setBitValue(ann,Announcer.LimitStation or 0,18,12) ann = setBitValue(ann,Announcer.Path and 1 or 0,30,1) ann = setBitValue(ann,Announcer.PathSel and 1 or 0,31,1) Train:SetNW2Int("BMCIK:Announcer",ann) Train:SetNW2Bool("BMCIK:LineEnabled",Announcer.LineEnabled) elseif self.State < 0 then if CurTime() > self.LoadingTimer then if self.State == -6 then self.State = -5 self.LoadingTimer = CurTime()+math.Rand(0.9,1.5) elseif self.State == -5 then self.State = -4 self.LoadingTimer = CurTime()+2 elseif self.State == -4 then self.State = -3 self.LoadingTimer = CurTime()+math.Rand(9,12) elseif self.State == -3 then self.State = -2 self.LoadingTimer = CurTime()+math.Rand(1,3) elseif self.State == -2 then self.State = -1 self.LoadingTimer = CurTime()+math.Rand(2,3) elseif self.State == -1 then self.State = 1 self.CAN_SU = CurTime() self:Cam_Scan() end end if self.State == -4 then Train:SetNW2Int("BMCIK:GRUBTimeout",self.LoadingTimer - CurTime() + 1) end else self.State = -6 self.LoadingTimer = CurTime()+math.Rand(5,7) -- self.State = -2 -- self.LoadingTimer = CurTime()+3 end else if self.State ~= 0 then self:MemReset() self.State = 0 end end -- BMTS-07 logic local BMTSPower = Train.Electric.Power > 0 and Train.SF18.Value > 0 local BMTS = self.BMTS if BMTSPower and Train.SF18.Value > 0 then if BMTS.State == 0 then BMTS.State = -1 BMTS.Loading = CurTime()+5 BMTS.Update = true elseif self.BMTS.State == -1 then if CurTime() > BMTS.Loading then BMTS.State = 1 BMTS.Text = "" BMTS.Loading = nil BMTS.Update = true end end else if BMTS.State ~= 0 then BMTS.State = 0 BMTS.Text = "" BMTS.Update = true end end Train:SetNW2Int("BMCIK:State",self.State) if BMTS.Update then BMTS.Update = false Train:SetNW2Int("BMTS:State",BMTS.State) Train:SetNW2String("BMTS:Text",BMTS.Text) end end function TRAIN_SYSTEM:MemReset(resetAnn) self.ZeroBtnTimer = nil self.EscBtnTimer = nil self.Brightness = 1 self.NIIP.CabActive = false self:Cam_Reset() self:Announcer_Reset(resetAnn) self:List_Reset() self.Train:SetNW2Int("BMCIK:IDTouched",0) self.Train:SetNW2Float("BMCIK:Brightness",1) self.Train:SetNW2Int("BMCIK:VolCab",0) end if SERVER then return end local font20 = "Metrostroi_Dejavu20" local font21 = "Metrostroi_Dejavu21" local font28 = "Metrostroi_Dejavu28" -- Create fonts local function createFont(name,font,size,weight,noAA) surface.CreateFont("Metrostroi_"..name, { font = font, size = size, weight = weight or 400, blursize = 0, antialias = not noAA, underline = false, italic = false, strikeout = false, symbol = false, rotary = false, shadow = false, additive = false, outline = false, extended = true, }) end createFont("Dejavu20","Dejavu Sans",20) createFont("Dejavu21","Dejavu Sans",21) createFont("Dejavu22","Dejavu Sans",22) createFont("Dejavu26","Dejavu Sans",26) createFont("Dejavu28","Dejavu Sans",28) createFont("BMTS1","Arial",14,800,true) createFont("BMTS2","Arial",17,800,true) createFont("BMTS3","Arial",22,800,true) createFont("BMTS4","Arial",30,800,true) local function drawText(text,x,y,xalign,yalign) if (xalign or yalign) then local w,h = surface.GetTextSize( text ) if (xalign == TEXT_ALIGN_CENTER) then x = x - w / 2 elseif (xalign == TEXT_ALIGN_RIGHT) then x = x - w end if (yalign == TEXT_ALIGN_CENTER) then y = y - h / 2 elseif (yalign == TEXT_ALIGN_BOTTOM) then y = y - h end end surface.SetTextPos(x,y) surface.DrawText(text) end local scx,scy = 1,1 -- Multipliers for fix RT draw on screen function TRAIN_SYSTEM:ClientInitialize() scx,scy = math.max(ScrW()/2048,1),math.max(ScrH()/1024,1) self.Cams = { {self.Train:CreateRT("722BVK1",512,512),0}, {self.Train:CreateRT("722BVK2",512,512),0}, {self.Train:CreateRT("722BVK3",512,512),0}, {self.Train:CreateRT("722BVK4",512,512),0} } self.HeaderNames = table.Copy(self.HeaderNames) self.List = { Selected = 0, Offset = 0 } self.BMTS = { State = 0, Text = "", Update = true } end local BMTSPixels = surface.GetTextureID("models/metrostroi_train/81-722/screens/sarmat_upo/bmts") function TRAIN_SYSTEM:ClientThink(dT) -- БМЦИК-01 ЦИКВ.465122.049 if self.Train:ShouldDrawPanel("BMCIK") then render.PushRenderTarget(self.Train.BMCIKScr,0,0,2048, 1024) render.Clear(0, 0, 0, 0) cam.Start2D() render.SetScissorRect(0,0,1280,800,true) surface.SetDrawColor(0,0,0) surface.DrawRect(0,0,1280,800) local state = self.Train:GetNW2Int("BMCIK:State",0) self:BMCIK01(self.Train,state) if state ~= 0 then surface.SetDrawColor(20,20,90,8) surface.DrawRect(0,0,1280,800) end render.SetScissorRect(0,0,0,0,false) cam.End2D() render.PopRenderTarget() end -- БМТС-07 ЦИКВ.402261.031 if self.Train:ShouldDrawPanel("BMTS") then local BMTSText = self.Train:GetNW2String("BMTS:Text","") local BMTSState = self.Train:GetNW2Int("BMTS:State",0) if self.BMTS.State ~= BMTSState then self.BMTS.State = BMTSState self.BMTS.Update = true end if self.BMTS.State > 0 and self.BMTS.Text ~= BMTSText then self.BMTS.Text = BMTSText self.BMTS.Update = true end if self.BMTS.Update then render.PushRenderTarget(self.Train.BMTSScr,0,0,512,128) render.Clear(0, 0, 0, 0) cam.Start2D() self:BMTS07(self.Train) render.OverrideBlend(true,BLEND_ZERO,BLEND_ONE,BLENDFUNC_ADD,BLEND_ZERO,BLEND_ZERO,BLENDFUNC_MIN) surface.SetDrawColor(255,255,255,200) surface.SetTexture(BMTSPixels) surface.DrawTexturedRectRotated(256,64,512,128,0) render.OverrideBlend(false) cam.End2D() render.PopRenderTarget() self.BMTS.Update = false end end end local sarmatLogo = surface.GetTextureID("models/metrostroi_train/81-722/screens/sarmat_upo/sarmat_logo") local grubMenu = surface.GetTextureID("models/metrostroi_train/81-722/screens/sarmat_upo/grub") function TRAIN_SYSTEM:BMCIK01(Train,state) if state == 0 then return end if state == -4 then local grubTimeout = Train:GetNW2Int("BMCIK:GRUBTimeout",0) surface.SetTexture(grubMenu) surface.SetDrawColor(255,255,255) local mat = Matrix() mat:SetScale(Vector(2,1.667)) cam.PushModelMatrix(mat) surface.DrawTexturedRect(0,0,1024,512) surface.DrawTexturedRectUV(482,398,8,12,0.625+grubTimeout*0.0078125,0,0.6328125+grubTimeout*0.0078125,0.0234375) cam.PopModelMatrix() elseif state == -3 then if (CurTime()%0.5 > 0.25) then surface.SetTextColor(255,255,255) surface.SetFont(font28) drawText("_",2,2) end elseif state == -2 then draw.SimpleText("_",font28,2,16, Color(255,255,255),TEXT_ALIGN_LEFT,TEXT_ALIGN_CENTER) surface.SetTexture(sarmatLogo) surface.SetDrawColor(250,190,0) surface.DrawTexturedRectRotated(955,685,640,320,0) elseif state == 1 then self:BMCIK01State1(Train) surface.SetAlphaMultiplier(1-self.Train:GetNW2Float("BMCIK:Brightness",1)^1.2) surface.SetDrawColor(Color(8,8,8)) surface.DrawRect(0,0,1280,800,0) surface.SetAlphaMultiplier(1) end end function TRAIN_SYSTEM:BMCIK01State1(Train) self.WagNum = Train:GetNW2Int("BMCIK:WagNum",0) self:BMCIK01GUICameras(Train) self:BMCIK01GUIAnnouncer(Train) surface.SetFont(font28) surface.SetTextColor(255,255,255) drawText(os.date("!%d.%m.%y %H:%M:%S",Metrostroi.GetSyncTime()),681,742) drawText("Ver. 6",681,768) end local function drawButton(x,y,w,h,text,touched) draw.RoundedBox(8,x,y,w,h,Color(255,255,255)) draw.RoundedBox(6,x+2,y+2,w-4,h-4,touched and Color(83,83,83) or Color(35,35,35)) drawText(text,x+w/2,y+h/2,TEXT_ALIGN_CENTER,TEXT_ALIGN_CENTER) end local BMCIKPos = Vector(472,37.4,-9) local camFrame = surface.GetTextureID("models/metrostroi_train/81-722/screens/sarmat_upo/cam_frame") function TRAIN_SYSTEM:BMCIK01GUICameras(Train) local wagNum = self.WagNum local camPage = Train:GetNW2Int("BMCIK:CamPage",0) local touchId = Train:GetNW2Int("BMCIK:IDTouched",0) surface.SetFont(font28) surface.SetTextColor(255,255,255) for i=1,self.Buttons.Count do local btn = self.Buttons[i] if btn.show(camPage) then drawButton(btn.x,btn.y,btn.w,btn.h,Format(btn.name,wagNum),touchId == btn.id) end end if camPage == 0 then drawText("Система видеонаблюдения",457,32,TEXT_ALIGN_CENTER,TEXT_ALIGN_CENTER) for i=1,self.Buttons.Count do local btn = self.Buttons[i] drawButton(btn.x,btn.y,btn.w,btn.h,Format(btn.name,wagNum),touchId == btn.id) end drawText("Наружные камеры",457,129,TEXT_ALIGN_CENTER,TEXT_ALIGN_CENTER) drawText("1",74,185) drawText(wagNum,74,213) drawText("Вагон 1",311,163,TEXT_ALIGN_CENTER,TEXT_ALIGN_CENTER) drawText("Все вагоны",457,163,TEXT_ALIGN_CENTER,TEXT_ALIGN_CENTER) drawText("Вагон "..wagNum,603,163,TEXT_ALIGN_CENTER,TEXT_ALIGN_CENTER) drawText("1",825,185) drawText(wagNum,825,213) drawText("Камеры в салонах",457,303,TEXT_ALIGN_CENTER,TEXT_ALIGN_CENTER) for i=1,wagNum do if wagNum == 8 then drawButton(350+(i-wagNum/2)*110,323,104,60,"Вагон "..i,touchId == 10+i) elseif wagNum == 7 then drawButton(334+(i-wagNum/2)*126,323,120,60,"Вагон "..i,touchId == 10+i) else drawButton(313+(i-wagNum/2)*147,323,141,60,"Вагон "..i,touchId == 10+i) end end drawText("Камеры на постах машиниста",457,443,TEXT_ALIGN_CENTER,TEXT_ALIGN_CENTER) drawText("Путевые камеры",457,583,TEXT_ALIGN_CENTER,TEXT_ALIGN_CENTER) else -- Номер вагона, тип вагона, бортовой номер local camWagIndex = Train:GetNW2Int("BMCIK:CamWagIndex",0) local camWagType = Train:GetNW2Int("BMCIK:CamType",0) local camWagNum = Train:GetNW2Int("BMCIK:CamWagNumber",0) local camCurrConf = self.CamConfig[camWagType][camPage] or self.CamConfig[0][1] surface.SetFont("Metrostroi_Dejavu26") local headerCurr = Format("Вагон %d [%d] - %s - страница %d/%d",camWagIndex,camWagNum,camCurrConf.PageName,camPage,self.CamConfig[camWagType].Count) local headerCurrW = surface.GetTextSize(headerCurr) surface.SetDrawColor(255,255,255) surface.SetTexture(camFrame) surface.DrawTexturedRectRotated(530,542,1024,1024,0) surface.SetDrawColor(0,0,0) surface.DrawRect(457 - ((headerCurrW+10)/2-0.5),30,headerCurrW+10,1) drawText(headerCurr,457 - headerCurrW/2,20) local CamNW2 = Train:GetNW2Int("BMCIK:Cam",0) local Cam1 = getBitValue(CamNW2,0,1) > 0 local Cam2 = camCurrConf.Count > 1 and getBitValue(CamNW2,1,1) > 0 local Cam3 = camCurrConf.Count > 2 and getBitValue(CamNW2,2,1) > 0 local Cam4 = camCurrConf.Count > 3 and getBitValue(CamNW2,3,1) > 0 local camTbl if Cam1 then camTbl = camCurrConf[1] Metrostroi.RenderCamOnRT(Train,BMCIKPos,"Cam1",0.1+0.15*math.random(),self.Cams[1][1],Train:GetNW2Entity("BMCIK:CamE1"),camTbl[2],camTbl[3],512,512,not camTbl.wide and 1.4,not camTbl.wide and 74,not camTbl.wide and 74) self.Cams[1][2] = Metrostroi.CamQueue[1] and (Metrostroi.CamQueue[1][3]:EndsWith("1") and math.floor(1/Metrostroi.CamQueue[1][4])) or self.Cams[1][2] end if Cam2 then camTbl = camCurrConf[2] Metrostroi.RenderCamOnRT(Train,BMCIKPos,"Cam2",0.1+0.15*math.random(),self.Cams[2][1],Train:GetNW2Entity("BMCIK:CamE2"),camTbl[2],camTbl[3],512,512,not camTbl.wide and 1.4,not camTbl.wide and 74,not camTbl.wide and 74) self.Cams[2][2] = Metrostroi.CamQueue[1] and (Metrostroi.CamQueue[1][3]:EndsWith("2") and math.floor(1/Metrostroi.CamQueue[1][4])) or self.Cams[2][2] end if Cam3 then camTbl = camCurrConf[3] Metrostroi.RenderCamOnRT(Train,BMCIKPos,"Cam3",0.1+0.15*math.random(),self.Cams[3][1],Train:GetNW2Entity("BMCIK:CamE3"),camTbl[2],camTbl[3],512,512,not camTbl.wide and 1.4,not camTbl.wide and 74,not camTbl.wide and 74) self.Cams[3][2] = Metrostroi.CamQueue[1] and (Metrostroi.CamQueue[1][3]:EndsWith("3") and math.floor(1/Metrostroi.CamQueue[1][4])) or self.Cams[3][2] end if Cam4 then camTbl = camCurrConf[4] Metrostroi.RenderCamOnRT(Train,BMCIKPos,"Cam4",0.1+0.15*math.random(),self.Cams[4][1],Train:GetNW2Entity("BMCIK:CamE4"),camTbl[2],camTbl[3],512,512,not camTbl.wide and 1.4,not camTbl.wide and 74,not camTbl.wide and 74) self.Cams[4][2] = Metrostroi.CamQueue[1] and (Metrostroi.CamQueue[1][3]:EndsWith("4") and math.floor(1/Metrostroi.CamQueue[1][4])) or self.Cams[4][2] end local camFullScreen = getBitValue(CamNW2,4,3) surface.SetFont(font20) if camFullScreen > 0 then local tCam = getBitValue(CamNW2,camFullScreen-1,1) > 0 if tCam then render.DrawTextureToScreenRect(self.Cams[camFullScreen][1],scx*24,scy*58,scx*866,scy*662) surface.SetTextColor(200,0,0) drawText("fps = "..(self.Cams[camFullScreen][2]),26,78) surface.SetTextColor(0,200,0) drawText("link",888,698,TEXT_ALIGN_RIGHT) else surface.SetTextColor(200,0,0) drawText("no link",888,698,TEXT_ALIGN_RIGHT) end Metrostroi.DrawRectOutline(24,58,867,663,Color(176,176,176)) surface.SetTextColor(250,200,0) drawText(camCurrConf[camFullScreen][1],26,58) elseif camCurrConf.Count == 4 then -- Top left if Cam1 then render.DrawTextureToScreenRect(self.Cams[1][1],scx*24,scy*58,scx*430,scy*328) surface.SetTextColor(200,0,0) drawText("fps = "..(self.Cams[1][2]),26,78) surface.SetTextColor(0,200,0) drawText("link",451,364,TEXT_ALIGN_RIGHT) else surface.SetTextColor(200,0,0) drawText("no link",451,364,TEXT_ALIGN_RIGHT) end -- Top right if Cam2 then render.DrawTextureToScreenRect(self.Cams[2][1],scx*460,scy*58,scx*430,scy*328) surface.SetTextColor(200,0,0) drawText("fps = "..(self.Cams[2][2]),462,78) surface.SetTextColor(0,200,0) drawText("link",888,364,TEXT_ALIGN_RIGHT) else surface.SetTextColor(200,0,0) drawText("no link",888,364,TEXT_ALIGN_RIGHT) end -- Bottom left if Cam3 then render.DrawTextureToScreenRect(self.Cams[3][1],scx*24,scy*392,scx*430,scy*328) surface.SetTextColor(200,0,0) drawText("fps = "..(self.Cams[3][2]),26,414) surface.SetTextColor(0,200,0) drawText("link",451,698,TEXT_ALIGN_RIGHT) else surface.SetTextColor(200,0,0) drawText("no link",451,698,TEXT_ALIGN_RIGHT) end -- Bottom right if Cam4 then render.DrawTextureToScreenRect(self.Cams[4][1],scx*460,scy*392,scx*430,scy*328) surface.SetTextColor(200,0,0) drawText("fps = "..(self.Cams[4][2]),462,414) surface.SetTextColor(0,200,0) drawText("link",888,698,TEXT_ALIGN_RIGHT) else surface.SetTextColor(200,0,0) drawText("no link",888,698,TEXT_ALIGN_RIGHT) end Metrostroi.DrawRectOutline(24,58,431,329,Color(176,176,176)) Metrostroi.DrawRectOutline(460,58,431,329,Color(176,176,176)) Metrostroi.DrawRectOutline(24,392,431,329,Color(176,176,176)) Metrostroi.DrawRectOutline(460,392,431,329,Color(176,176,176)) surface.SetTextColor(250,200,0) drawText(camCurrConf[1][1],26,58) drawText(camCurrConf[2][1],462,58) drawText(camCurrConf[3][1],26,394) drawText(camCurrConf[4][1],462,394) elseif camCurrConf.Count == 2 then -- Left if Cam1 then render.DrawTextureToScreenRect(self.Cams[1][1],scx*24,scy*58,scx*430,scy*662) surface.SetTextColor(200,0,0) drawText("fps = "..(self.Cams[1][2]),26,78) surface.SetTextColor(0,200,0) drawText("link",451,698,TEXT_ALIGN_RIGHT) else surface.SetTextColor(200,0,0) drawText("no link",451,698,TEXT_ALIGN_RIGHT) end -- Right if Cam2 then render.DrawTextureToScreenRect(self.Cams[2][1],scx*460,scy*58,scx*430,scy*662) surface.SetTextColor(200,0,0) drawText("fps = "..(self.Cams[2][2]),462,78) surface.SetTextColor(0,200,0) drawText("link",888,698,TEXT_ALIGN_RIGHT) else surface.SetTextColor(200,0,0) drawText("no link",888,698,TEXT_ALIGN_RIGHT) end Metrostroi.DrawRectOutline(24,58,431,663,Color(176,176,176)) Metrostroi.DrawRectOutline(460,58,431,663,Color(176,176,176)) surface.SetTextColor(250,200,0) drawText(camCurrConf[1][1],26,58) drawText(camCurrConf[2][1],462,58) else if Cam1 then render.DrawTextureToScreenRect(self.Cams[1][1],scx*24,scy*58,scx*866,scy*662) surface.SetTextColor(200,0,0) drawText("fps = "..(self.Cams[1][2]),26,78) surface.SetTextColor(0,200,0) drawText("link",888,698,TEXT_ALIGN_RIGHT) else surface.SetTextColor(200,0,0) drawText("no link",888,698,TEXT_ALIGN_RIGHT) end Metrostroi.DrawRectOutline(24,58,867,663,Color(176,176,176)) surface.SetTextColor(250,200,0) drawText(camCurrConf[1][1],26,58) end end end local listCursor = surface.GetTextureID("models/metrostroi_train/81-722/screens/sarmat_upo/list_cursor") function TRAIN_SYSTEM:DrawListLine(text,pos,selected) pos = pos - self.List.Offset if selected then surface.SetTexture(listCursor) surface.SetDrawColor(176,176,176) surface.DrawTexturedRectRotated(1174,132+(pos-1)*24,512,32,0) surface.SetTextColor(0,0,0) else surface.SetTextColor(255,255,255) end drawText(tostring(text),selected and 924 or 920,94+pos*24) end local annFrame = surface.GetTextureID("models/metrostroi_train/81-722/screens/sarmat_upo/ann_frame") local lineFrame = surface.GetTextureID("models/metrostroi_train/81-722/screens/sarmat_upo/line_frame") local trainTrainMsg = surface.GetTextureID("models/metrostroi_train/81-722/screens/sarmat_upo/traintrain_msg") function TRAIN_SYSTEM:BMCIK01GUIAnnouncer(Train) local listSelected = Train:GetNW2Int("BMCIK:ListSelect"); self.List.Selected = listSelected; local listOffset = Train:GetNW2Int("BMCIK:ListOffset"); self.List.Offset = listOffset; local annNW2 = Train:GetNW2Int("BMCIK:Announcer") local annState = getBitValue(annNW2,0,6) local annLine = getBitValue(annNW2,10,8) local annLimit = getBitValue(annNW2,18,12); annLimit = annLimit > 0 and annLimit local annPath = getBitValue(annNW2,30,1) > 0 local annPathSel = getBitValue(annNW2,31,1) > 0 local annTbl = Metrostroi.SarmatUPOSetup[Train:GetNW2Int("Announcer")] local lTbl = annTbl and annTbl[annLine] local lTblCount = lTbl and #lTbl or 0 surface.SetFont(font28) surface.SetTextColor(255,255,255) drawText("линия",1054,11) drawText(lTbl and "ПУТЬ "..(annPathSel and 2 or 1) or "---",1213,25,TEXT_ALIGN_CENTER,TEXT_ALIGN_CENTER) surface.SetTexture(lineFrame) if Train:GetNW2Bool("BMCIK:LineEnabled") then surface.SetDrawColor(0,255,0) surface.SetTextColor(0,255,0) else surface.SetDrawColor(59,59,59) surface.SetTextColor(59,59,59) end surface.DrawTexturedRectRotated(1096,25,128,32,0) drawText("линия",1053,10) -- Header surface.SetTextColor(255,255,255) if annState < 2 then local lNameHeader = "---" if lTbl then if lTbl.Name then lNameHeader = "Линия: "..lTbl.Name else local fSt = annPath and 1 or lTblCount local lSt = annLimit or (annPath and 1 or lTblCount) lNameHeader = Format("Линия: %s-%s",lTbl[fSt][2],lTbl[lSt][2]) -- "Линия: " = 92px end if surface.GetTextSize(lNameHeader) > 355 then lNameHeader = lNameHeader:gsub("-","-\n",1) end end self.HeaderNames[0] = lNameHeader self.HeaderNames[1] = self.HeaderNames[0] end local textHeader = string.Explode("\n",self.HeaderNames[annState]) for i=1,#textHeader do drawText(textHeader[i],1091,78-(#textHeader-1)*14+(i-1)*28,TEXT_ALIGN_CENTER,TEXT_ALIGN_CENTER) end -- White frame if annState > 0 and annState ~= 21 then surface.SetDrawColor(255,255,255) surface.SetTexture(annFrame) surface.DrawTexturedRectRotated(1169,623,512,1024,0) end -- Lists render.SetScissorRect(918,116,1264,637,true) surface.SetFont(font21) if annState == 0 then surface.SetFont(font28) drawText("Блок неактивен",992,112) elseif annState == 1 then if annPath then for i=lTblCount,1,-1 do if annLimit and i < annLimit then break end local iPos=(lTblCount-i+1)*2 self:DrawListLine(lTbl[i][2],iPos-1,listSelected==(iPos-1)) self:DrawListLine(lTbl[i][2].." отп",iPos,listSelected==iPos) end else for i=1,lTblCount do if annLimit and i > annLimit then break end local iPos=i*2 self:DrawListLine(lTbl[i][2],i*2-1,listSelected==(i*2-1)) self:DrawListLine(lTbl[i][2].." отп",i*2,listSelected==(i*2)) end end elseif annState > 10 and annState < 20 then if annState == 11 then -- Предупредительные сообщения self:DrawListLine("Нет сообщений",1,true) elseif annState == 12 then -- Ограничения маршрута local iLast = 1 if lTbl.Loop then for i=1,lTblCount do if lTbl[i].arrlast then self:DrawListLine((annLimit == i and "☑ " or "☐ ")..lTbl[i][2],iLast,listSelected==iLast) iLast = iLast + 1 end end else for i=2,lTblCount-1 do if lTbl[i].arrlast then self:DrawListLine((annLimit == i and "☑ " or "☐ ")..lTbl[i][2],iLast,listSelected==iLast) iLast = iLast + 1 end end end elseif annState == 13 then -- Дополнительные сообщения self:DrawListLine("Нет сообщений",1,true) elseif annState == 14 then -- Экстренные сообщение self:DrawListLine("Нет сообщений",1,true) elseif annState == 15 then -- Выбор линии for i=1,#annTbl do local lName = annTbl[i].Name or Format("%s-%s",annTbl[i][1][2],annTbl[i][#annTbl[i]][2]) self:DrawListLine(lName,i,listSelected==i) end end elseif annState == 2 then -- Меню настройки блока СБУЦИК for i=1,#self.SettingsList do self:DrawListLine(self.SettingsList[i][1],i,listSelected==i) end elseif annState > 20 then if annState == 21 then -- Ввод номера маршрута surface.SetFont(font28) drawText("Ввод номера маршрута",945,112) elseif annState == 22 then -- Режимы работы информатора local mode = Train:GetNW2Int("BMCIK:AnnMode",0) for i=1,#self.AnnModeList do self:DrawListLine((mode == i and "☑ " or "☐ ")..self.AnnModeList[i],i,listSelected==i) end elseif annState == 23 then -- Режимы работы СОСТАВ-СОСТАВ local mode = Train:GetNW2Bool("BMCIK:TrainTrain") self:DrawListLine((mode and "☑ " or "☐ ").."Режим 'Состав-Состав'",1,true) if mode then render.SetScissorRect(0,0,0,0,false) surface.SetDrawColor(255,255,255) surface.DrawRect(900,400,378,250) surface.SetTexture(trainTrainMsg) surface.DrawTexturedRectRotated(1156,528,512,256,0) end elseif annState == 24 then -- Настройка громкости local volumes = Train:GetNW2Int("BMCIK:VolumesPage") local volumeList = self.AnnVolumeList for i=1,#volumeList do self:DrawListLine(volumeList[i][1],i,listSelected==i) drawText(getBitValue(volumes,(i-1)*4,4)*10,1230,118+(i-1)*24,TEXT_ALIGN_CENTER) end elseif annState == 25 then -- Информация local info = self.InfoList local infoNW2 = Train:GetNW2Int("BMCIK:AddInfo",0) for i=1,#info do local v = info[i][2] and Train:GetNW2Int(info[i][2]) or 0 self:DrawListLine(info[i][1]..v,i,listSelected==i) end elseif annState == 26 then -- Диагностика for i=1,#self.DiagList do self:DrawListLine(self.DiagList[i],i,listSelected==i) end elseif annState == 27 then -- Язык -- TODO: Add translations support local mode = 1 for i=1,#self.LangList do self:DrawListLine((mode==i and "☑ " or "☐ ")..self.LangList[i],i,listSelected==i) end elseif annState == 28 then -- Отображение времени на БИТ local mode = Train:GetNW2Bool("BMCIK:BITTime") and 2 or 1 for i=1,#self.BITClockList do self:DrawListLine((mode==i and "☑ " or "☐ ")..self.BITClockList[i],i,listSelected==i) end end end render.SetScissorRect(0,0,0,0,false) surface.SetTextColor(255,255,255) surface.SetFont("Metrostroi_Dejavu22") drawText("Состав:",924,647) surface.SetFont(font28) local wagNum = self.WagNum for i=0,wagNum-1 do drawButton(1091+(i-wagNum/2)*41,673,40,48,i+1) end local cikState = getBitValue(annNW2,6,4) drawText(self.CIKStatesNames[cikState],913,756) end local function stringUpperCyrillic(str) if #str == 0 then return "" end local strtbl = {utf8.codepoint(str,1,-1)} local strUp = "" for i=1,#strtbl do local chartbl = strtbl[i] if chartbl > 0x042F and chartbl < 0x0450 then chartbl = chartbl - 0x20 -- [а,я] --> [A,Я] elseif chartbl == 0x0456 then chartbl = 0x0406 -- і -> І elseif chartbl == 0x0451 then chartbl = 0x0401 -- ё -> Ё elseif chartbl == 0x0457 then chartbl = 0x0407 -- ї -> Ї elseif chartbl == 0x0454 then chartbl = 0x0404 -- є -> Є elseif chartbl == 0x045E then chartbl = 0x040E -- ў -> Ў elseif chartbl == 0x0491 then chartbl = 0x0490 -- ґ -> Ґ end strUp = strUp..(utf8.char(chartbl)) end return string.upper(strUp) end function TRAIN_SYSTEM:BMTS07(Train) local state = self.BMTS.State if state == 0 then return end if state == 1 then surface.SetFont("Metrostroi_BMTS4") surface.SetTextColor(255,120,0) local lastStation = stringUpperCyrillic(self.BMTS.Text) local lsW,lsY = surface.GetTextSize(lastStation),-5 if lsW >= 230 then surface.SetFont("Metrostroi_BMTS1") lsW = surface.GetTextSize(lastStation) lsY = 3 elseif lsW >= 168 then surface.SetFont("Metrostroi_BMTS2") lsW = surface.GetTextSize(lastStation) lsY = 2 elseif lsW >= 126 then surface.SetFont("Metrostroi_BMTS3") lsW = surface.GetTextSize(lastStation) lsY = -1 end local mat = Matrix() mat:Scale(Vector(4,4)) cam.PushModelMatrix(mat) surface.SetTextPos(64-lsW/2, lsY) surface.DrawText(lastStation) cam.PopModelMatrix() elseif state == -1 then surface.SetDrawColor(255,120,0) surface.DrawRect(0,0,512,80) end end