-------------------------------------------------------------------------------- -- ASOTP "IGLA" white indicator unit for 81-720 -------------------------------------------------------------------------------- -- Copyright (C) 2013-2018 Metrostroi Team & FoxWorks Aerospace s.r.o. -- Contains proprietary code. See license.txt for additional information. -------------------------------------------------------------------------------- Metrostroi.DefineSystem("IGLA_CBKI1") TRAIN_SYSTEM.DontAccelerateSimulation = true function TRAIN_SYSTEM:Initialize() self.Log = {} self.States = {} self.Messages = {} self.MessagesCount = 0 if not self.Train.IGLA1 then self.Train:LoadSystem("IGLA1","Relay","Switch",{bass = true}) self.Train:LoadSystem("IGLA2","Relay","Switch",{bass = true}) self.Train:LoadSystem("IGLA3","Relay","Switch",{bass = true}) self.Train:LoadSystem("IGLA4","Relay","Switch",{bass = true}) end self.TriggerNames = { "IGLA1", "IGLA2", "IGLA3", "IGLA4", } self.Triggers = {} self.State = 0 self.Timer = 0 if not TURBOSTROI then self.BVolt = 3.0+math.random()*0.4 self.Train:SetNW2Int("IGLA:BVolt",self.BVolt*10) end end if TURBOSTROI then return end function TRAIN_SYSTEM:Inputs() return { "" } end if CLIENT then local Chars = { full = utf8.char(0x2588), lhalf = utf8.char(0x258C), rhalf = utf8.char(0x2590), shade = utf8.char(0x2592), [1] = utf8.char(0x2776), [2] = utf8.char(0x2777), [3] = utf8.char(0x2778), [4] = utf8.char(0x2779), [5] = utf8.char(0x277A), [6] = utf8.char(0x277B), [7] = utf8.char(0x277C), [8] = utf8.char(0x277D), [9] = utf8.char(0x277E), [0] = utf8.char(0x24FF), } local Converter = { ["\1"] = Chars[1], ["\2"] = Chars[2], ["\3"] = Chars[3], ["\4"] = Chars[4], ["\5"] = Chars[5], ["\6"] = Chars[6], ["\7"] = Chars[7], ["\8"] = Chars[8], ["\9"] = Chars[9], ["\0"] = Chars[0], } local function FormatEnd1(num) if num == 1 then return " " elseif 1 < num and num < 5 then return "а" end return "ов" end local function FormatEnd2(num) if num == 1 then return "ка" elseif 1 < num and num < 5 then return "ки" end return "ок" end function TRAIN_SYSTEM:PrintText(x,y,text,col) local str = {utf8.codepoint(text,1,-1)} for i=1,#str do local char = utf8.char(str[i]) local alpha = col.a if alpha > 1 then draw.SimpleText(char,"MetrostroiSubway_IGLAb",-8+(x+i)*25,30+y*43+1,ColorAlpha(col,alpha*0.08),TEXT_ALIGN_CENTER,TEXT_ALIGN_CENTER) end draw.SimpleText(char,"MetrostroiSubway_IGLA",-8+(x+i)*25,30+y*43,col,TEXT_ALIGN_CENTER,TEXT_ALIGN_CENTER) end end function TRAIN_SYSTEM:ClientThink() if not self.Train:ShouldDrawPanel("IGLA") then return end if not self.DrawTimer then render.PushRenderTarget(self.Train.IGLA,0,0,512, 128) render.Clear(0, 0, 0, 0) render.PopRenderTarget() end self.DrawTimer = self.DrawTimer or CurTime() if CurTime()-self.DrawTimer < 0.1 then return end self.DrawTimer = CurTime() render.PushRenderTarget(self.Train.IGLA,0,0,512, 128) render.Clear(0, 0, 0, 0) cam.Start2D() self:IGLA(self.Train) cam.End2D() render.PopRenderTarget() end local messages = { START = "питание цбки включ", CONN = "подключен", DISCONN = "потеря связи", SCHEME = "несбор сх ваг", RP = "сработка рп", DOORS = "открытые двери", BPSN = "выкл бпсн", PARKING = "вкл стоян торм", MANUAL = "вкл ручн торм", BRAKES = "вкл пневм торм", UAVA = "сраб срыв клап", UAVAK = "контакты уава", EPK = "сработка эпв", ARS = "прев арс 9км\\ч", RU = "резерв котнрол", } local colorb = Color(60,160,140,1) local colorf = Color(60,160,140,255) local colorh = Color(60,160,140,75) function TRAIN_SYSTEM:IGLA() local Train = self.Train surface.SetDrawColor(60*0.075,160*0.075,140*0.075) surface.DrawRect(0,0,512,107) self:PrintText(0,0,string.rep(Chars.full,20),colorb) self:PrintText(0,1,string.rep(Chars.full,20),colorb) local State = self.Train:GetNW2Int("IGLA:State",0) if State == -3 then self:PrintText(0,0,"обратитесь в службу",colorf) self:PrintText(0,1,"ремонта чайников",colorf) elseif State == 0 then if RealTime()%0.6 > 0.3 then self:PrintText(0,0,Chars.full,colorf) end elseif State == 1 then self.VoltRandom = self.VoltRandom or RealTime() if not self.Volt1 or CurTime()-self.VoltRandom > 0 then self.VoltRandom = CurTime()+0.2+math.random()*0.6 self.Volt1 = 4.9+math.random()*0.2 self.Volt2 = 3.0+math.random()*0.2 end self:PrintText(0,0,"к 15в 5в 3.3в бт пчм",colorf) if not Train:GetNW2Bool("IGLA:E") or RealTime()%0.5 > 0.25 then self:PrintText(0,1,Format("%X",Train:GetNW2Int("IGLA:B")),colorf) end self:PrintText(2,1,"15",colorf) self:PrintText(5,1,Format("%.1f",self.Volt1 or 5),colorf) self:PrintText(9,1,Format("%.1f",self.Volt2 or 3.2),colorf) self:PrintText(13,1,Format("%.1f",Train:GetNW2Int("IGLA:BVolt",0)/10),colorf) if Train:GetNW2Bool("IGLA:P") then self:PrintText(17,1,".",colorf) end if Train:GetNW2Bool("IGLA:C") then self:PrintText(18,1,".",colorf) end self:PrintText(19,1,".",colorf) elseif State == 2 then local State2 = Train:GetNW2Int("IGLA:State2",0) --[[ for i=1,6 do self:PrintText((i-1)*3,0,Format("%02d",i),colorf) self:PrintText((i-1)*3,1,Format("%02d",Train:GetNW2Int("PUAV:RK" .. i,0)),colorf) end--]] if State2 == 0 then local Standby = Train:GetNW2Bool("IGLA:Standby") local ShowTime = Train:GetNW2Bool("IGLA:ShowTime") if not Standby then local count = Train:GetNW2Int("IGLA:Count") self:PrintText(0,0,"асотп",colorf) self:PrintText(6,0,Format("%2d",count),colorf) self:PrintText(9,0,"комплект",colorf) self:PrintText(17,0,FormatEnd1(count),colorf) local d = Metrostroi.GetSyncTime() self:PrintText(0,1,os.date("!%d-%m-%y",d),colorf) self:PrintText(12,1,os.date("!%H:%M:%S",d),colorf) elseif ShowTime then local d = Metrostroi.GetSyncTime() self:PrintText(0,1,os.date("!%d-%m-%y",d),colorh) self:PrintText(12,1,os.date("!%H:%M:%S",d),colorh) end elseif State2 == 1 then local w = Train:GetNW2Int("IGLA:WagNumber") local m = Train:GetNW2String("IGLA:ErrorID") if messages[m] then m = messages[m] end if m == "PTROverheat" then if CurTime()%2 > 1 then self:PrintText(1,0,"!! PIZDA POEZDU !!",colorf) else self:PrintText(0,0,Format("%05d",w),colorf) self:PrintText(6,0,"ПТР",colorf) self:PrintText(10,0,Format ("% 3dC",Train:GetNW2Int("IGLA:Temp",0)),colorf) self:PrintText(15,0,"пожар",colorf) end elseif m == "PTROverheating" then self:PrintText(0,0,Format("%05d",w),colorf) self:PrintText(6,0,"ПТР",colorf) self:PrintText(9,0,Format ("% 3dC",Train:GetNW2Int("IGLA:Temp",0)),colorf) self:PrintText(15,0,"перег",colorf) else self:PrintText(0,0,Format("%05d",w),colorf) self:PrintText(6,0,m,colorf) end self:PrintText(0,1,"^",colorf) if Train:GetNW2Bool("IGLA:ButtonL2") then self:PrintText(6,1,"<-",colorf) end if Train:GetNW2Bool("IGLA:ButtonL3") then self:PrintText(11,1,"->",colorf) end self:PrintText(15,1,Format("[%03d]",Train:GetNW2Int("IGLA:MessagesCount")),colorf) elseif State2 == 2 then self:PrintText(0,0,"введите код:",colorf) elseif State2 == 3 then local w = Train:GetNW2Int("IGLA:WagNumber") local m = Train:GetNW2String("IGLA:LogID") if messages[m] then m = messages[m] end if w > 0 then self:PrintText(0,0,Format("%05d",w),colorf) if m == "PTROverheat" then if CurTime()%2 > 1 then self:PrintText(6,0,"PIZDA POEZDU",colorf) else self:PrintText(6,0,"ПТР",colorf) self:PrintText(10,0,"пожар",colorf) end elseif m == "PTROverheating" then self:PrintText(6,0,"ПТР",colorf) self:PrintText(10,0,"перегрев",colorf) else self:PrintText(6,0,m,colorf) end else self:PrintText(0,0,m,colorf) end self:PrintText(0,1,"^",colorf) local d = Train:GetNW2Int("IGLA:LogDate") self:PrintText(3,1,os.date("!%d-%m-%y",d),colorf) self:PrintText(12,1,os.date("!%H:%M:%S",d),colorf) end end end else function TRAIN_SYSTEM:CANReceive(source,sourceid,target,targetid,textdata,numdata) if self.State < 2 then return end if not self.States[sourceid] then self.States[sourceid] = {} table.insert(self.Log,{"CONN",sourceid,Metrostroi.GetSyncTime()}) end self.States[sourceid][textdata] = numdata end function TRAIN_SYSTEM:CANWrite(name,value) self.Train:CANWrite("IGLA_CBKI",self.Train:GetWagonNumber(),"IGLA_PCBK",nil,name,value) end function TRAIN_SYSTEM:Trigger(name,value) if self.State == -3 then local ID = tonumber(name[5]) if ID and bit.band(self.StartError,2^(ID-1)) == 0 then self.Reset = true end elseif self.State == 2 then local ID = tonumber(name[5]) if self.State2 == 0 then if ID == 1 and self.MessagesCount > 0 and value then self.State2 = 1 self.StandbyTimer = CurTime() self.Selected = #self.Messages elseif ID == 4 and CurTime()-self.StandbyTimer > 10 and value then self.ShowTimeTimer = CurTime() elseif ID==4 and not value and self.ShowTimeTimer then if self.ShowTimeTimer ~= true then self.StandbyTimer = CurTime() end self.ShowTimeTimer = nil end elseif self.State2 == 1 then self.StandbyTimer = CurTime() if ID==1 and value then self.State2 = 0 elseif ID==2 and value and self.Selected > 1 then self.Selected = self.Selected - 1 end if ID==3 and value and self.Selected < #self.Messages then self.Selected = self.Selected + 1 end elseif self.State2 == 2 and ID and value then self.Password = self.Password..ID if #self.Password > 3 then if self.Password == "3241" then self.State2 = 3 self.StandbyTimer = CurTime() self.Selected = #self.Log else self.State2 = 0 end self.Password = nil end elseif self.State2 == 3 then self.StandbyTimer = CurTime() if ID==1 and value then self.State2 = 0 elseif ID==2 and value and self.Selected > 1 then self.Selected = self.Selected - 1 end if ID==3 and value and self.Selected < #self.Log then self.Selected = self.Selected + 1 end end end end local Logging = { PTROverheat = true, PTROverheating = true, SCHEME = false, RP = true, DOORS = true, BPSN = true, PARKING = true, MANUAL = true, BRAKES = true, UAVA = true, UAVAK = true, EPK = true, ARS = true, RU = true, } function TRAIN_SYSTEM:CError(WagID,ErrID,status) local ID = WagID..ErrID if not self.Messages[ID] and status then self.Messages[ID] = table.insert(self.Messages,{ErrID,WagID,Metrostroi.GetSyncTime(),ID,status}) if Logging[ErrID] then table.insert(self.Log,self.Messages[self.Messages[ID]]) end --print(Format("Message with ErrID '%s' have ID:%d",ID,self.Messages[ID])) elseif self.Messages[ID] and not status then --print(Format("Removed message with ErrID '%s' have ID:%d",ID,self.Messages[ID])) table.remove(self.Messages,self.Messages[ID]) self.Messages[ID] = nil for k,v in ipairs(self.Messages) do self.Messages[v[4]] = k end end end function TRAIN_SYSTEM:Think(dT) local Train = self.Train local Power = Train.Panel.CBKIPower > 0 if Power and --[[ Train.A63.Value > 0.5 and--]] self.State ~= -2 then for k,v in pairs(self.TriggerNames) do if Train[v] and (Train[v].Value > 0.5) ~= self.Triggers[v] then self:Trigger(v,Train[v].Value > 0.5) self.Triggers[v] = Train[v].Value > 0.5 end end end if not Power or --[[ Train.A63.Value < 0.5 or--]] self.Reset then self.Reset = false if self.State ~= -2 then self.State = -2 self.Timer = nil self.Timer1 = nil self.Timer2 = nil self.ButtonL1 = false self.ButtonL2 = false self.ButtonL3 = false self.ButtonL4 = false self.Fire = 0 self.Error = 0 self.States = {} self.Messages = {} end end if self.State == -2 and Power --[[ and Train.A63.Value > 0.5--]] then self.State = -1 self.Timer = CurTime()+math.random()*0.3 self.StartError = false end if self.State == -1 and CurTime()-self.Timer > 0.3 then self.State = 0 Train:PlayOnce("igla_start2","cabin",nil,2) self.Timer = CurTime()+math.random()*0.4 end if self.State == 0 and CurTime()-self.Timer > 0.6 then table.insert(self.Log,{"START",sourceid,Metrostroi.GetSyncTime()}) self.State = 1 Train:PlayOnce("igla_start1","cabin") self.Timer = CurTime()+math.random()*0.4 self.Timer1 = 0.9+CurTime()+math.random()*0.2 self.Timer2 = 1.0+CurTime()+math.random()*1.2 self.StartError = Train.IGLA1.Value+Train.IGLA2.Value*2+Train.IGLA3.Value*4+Train.IGLA4.Value*8 Train:SetNW2Bool("IGLA:E",self.StartError > 0) end if self.State == 1 then Train:SetNW2Bool("IGLA:P",CurTime()-self.Timer1 > 0) Train:SetNW2Bool("IGLA:C",CurTime()-self.Timer2 > 0) Train:SetNW2Int("IGLA:B",Train.IGLA1.Value+Train.IGLA2.Value*2+Train.IGLA3.Value*4+Train.IGLA4.Value*8) self.ButtonL1 = self.StartError > 0 or CurTime()-self.Timer < 3 self.ButtonL2 = self.ButtonL1 self.ButtonL3 = self.ButtonL1 self.ButtonL4 = self.ButtonL1 self.Fire = true self.Error = true --Train:SetNW2Bool("IGLA:M",CurTime()-self.Timer3 > 0) if CurTime()-self.Timer > 5 then self.State = self.StartError > 0 and -3 or 2 self.State2 = 0 self.StandbyTimer = CurTime() self.ShowTimeTimer = nil self.ShowTime = false self.FireAlarm = false self.OverhAlarm = false self.FireState = false self.OverhState = false Train:PlayOnce("igla_start2","cabin",nil,1) self.PCBKTimer = nil end elseif self.State == -3 then self.ButtonL1 = bit.band(self.StartError,1) == 0 self.ButtonL2 = bit.band(self.StartError,2) == 0 self.ButtonL3 = bit.band(self.StartError,4) == 0 self.ButtonL4 = bit.band(self.StartError,8) == 0 self.Fire = false self.Error = CurTime()%0.5 > 0.25 elseif self.State == 2 then if #self.Log > 100 then table.remove(self.Log,1) end local Standby = CurTime()-self.StandbyTimer > 60 if self.State2 > 0 and Standby then self.State2 = 0 end if self.ShowTimeTimer and self.ShowTimeTimer ~= true and CurTime()-self.ShowTimeTimer > 1.5 then self.ShowTime = not self.ShowTime self.ShowTimeTimer = true end if not self.PCBKTimer or CurTime()-self.PCBKTimer > 1.4 then self:CANWrite("Update",1) self.PCBKTimer = CurTime()+math.random()*0.4 end local count = 0 for k,v in pairs(self.States) do local timer = v.Timer and CurTime()-v.Timer or 10 if timer <= 5 then for id in pairs(Logging) do self:CError(k,id,v[id]) end count = count + 1 else for k1,v1 in ipairs(self.Messages) do if v1[2] == k then --print(Format("Removed message with ErrID '%s' have ID:%d, PCBK discon",v1[4],self.Messages[v1[4]])) self.Messages[v1[4]] = nil table.remove(self.Messages,k1) end end table.insert(self.Log,{"DISCONN",k,Metrostroi.GetSyncTime()}) self.States[k] = nil end end self.PCBKCount = count if self.MessagesCount ~= #self.Messages then local mess = #self.Messages if self.MessagesCount < mess then --Train:PlayOnce("igla_alarm3","cabin",nil,1) self.StandbyTimer = CurTime() if self.State2 ~= 1 then self.State2 = 1 self.Selected = mess end if self.Selected >= self.MessagesCount then self.Selected = mess end end if self.State2 == 1 and self.Selected > mess then self.Selected = mess end if self.State2 == 1 and mess == 0 then self.State2 = 0 end self.MessagesCount = mess end if self.State2 == 0 then if self.Triggers.IGLA2 and self.Triggers.IGLA3 then self.Password = "" self.State2 = 2 self.StandbyTimer = CurTime() end self.ButtonL1 = self.MessagesCount > 0 self.ButtonL2 = false self.ButtonL3 = false self.ButtonL4 = Standby elseif self.State2 == 1 then local err = self.Messages[self.Selected] Train:SetNW2String("IGLA:ErrorID",err[1]) Train:SetNW2Int("IGLA:WagNumber",err[2]) if err[1] == "PTROverheating" or err[1] == "PTROverheat" then Train:SetNW2Int("IGLA:Temp",math.floor(self.States[err[2]][err[1]])) end self.ButtonL1 = true self.ButtonL2 = self.Selected > 1 self.ButtonL3 = self.Selected < #self.Messages Train:SetNW2Int("IGLA:MessagesCount",self.MessagesCount) self.ButtonL4 = false elseif self.State2 == 2 then self.ButtonL1 = true self.ButtonL2 = true self.ButtonL3 = true self.ButtonL4 = true elseif self.State2 == 3 then if self.Selected >= #self.Log then self.Selected = #self.Log end local log = self.Log[self.Selected] Train:SetNW2String("IGLA:LogID",log[1]) Train:SetNW2Int("IGLA:WagNumber",log[2]) Train:SetNW2Int("IGLA:LogDate",log[3]) for i=4,#log do Train:SetNW2Int("IGLA:Log"..i,log[i]) end self.ButtonL1 = true self.ButtonL2 = self.Selected > 1 self.ButtonL3 = self.Selected < #self.Log self.ButtonL4 = false end Train:SetNW2Int("IGLA:Count",self.PCBKCount) Train:SetNW2Int("IGLA:State2",self.State2) Train:SetNW2Bool("IGLA:Standby",Standby) Train:SetNW2Bool("IGLA:ShowTime",self.ShowTime) self.Fire = false local overh = false for i,v in ipairs(self.Messages) do if v[1] == "PTROverheat" then if not self.FireAlarm then self.FireAlarm = CurTime() end self.Fire = CurTime()%0.5>0.25 self.OverhAlarm = true elseif v[1] == "PTROverheating" and self.OverhAlarm ~= true then overh = true end end if overh and not self.OverhAlarm then self.OverhAlarm = CurTime() elseif not overh and self.OverhAlarm then self.OverhAlarm = false self.OverhState = false end if self.OverhAlarm and self.OverhAlarm ~= true and self.OverhState ~= math.floor((CurTime()-self.OverhAlarm)*2) and (not self.OverhState or self.OverhState < 5) then Train:PlayOnce("igla_alarm2","cabin",nil,1) self.OverhState = math.floor((CurTime()-self.OverhAlarm)*2) end if self.FireAlarm and self.FireState ~= math.floor((CurTime()-self.FireAlarm)*1.5) and (not self.FireState or self.FireState < 10) then Train:PlayOnce("igla_alarm3","cabin",nil,1) self.FireState = math.floor((CurTime()-self.FireAlarm)*1.5) end self.Error = false end Train:SetNW2Bool("IGLA:Messages",self.MessagesCount) Train:SetNW2Bool("IGLA:ButtonL1",self.ButtonL1) Train:SetNW2Bool("IGLA:ButtonL2",self.ButtonL2) Train:SetNW2Bool("IGLA:ButtonL3",self.ButtonL3) Train:SetNW2Bool("IGLA:ButtonL4",self.ButtonL4) Train:SetNW2Bool("IGLA:Fire",self.Fire) Train:SetNW2Bool("IGLA:Error",self.Error) Train:SetNW2Int("IGLA:State",self.State) end end