1
0
mirror of https://github.com/metrostroi-repo/MetrostroiAddon.git synced 2026-05-02 00:42:29 +00:00
Files
MetrostroiAddon/lua/entities/gmod_subway_base/shared.lua
2022-01-13 22:26:57 +03:00

624 lines
21 KiB
Lua

ENT.Type = "anim"
ENT.Author = ""
ENT.Contact = ""
ENT.Purpose = ""
ENT.Instructions = ""
ENT.Category = "Metrostroi (utility)"
ENT.Spawnable = true
ENT.AdminSpawnable = false
ENT.CustomThinks = ENT.CustomThinks or {}
ENT.CustomSpawnerUpdates = ENT.CustomSpawnerUpdates or {}
local function destroySound(snd,nogc)
if IsValid(snd) then snd:Stop() end
if not nogc and snd and snd.__gc then snd:__gc() end
end
function ENT:DestroySound(snd,nogc)
destroySound(snd,nogc)
end
--------------------------------------------------------------------------------
-- Default initializer only loads up DURA
--------------------------------------------------------------------------------
function ENT:InitializeSystems()
--self:LoadSystem("DURA")
self:LoadSystem("ALSCoil")
self.ALSCoil:TriggerInput("Enabled",1)
end
function ENT:PostInitializeSystems() end
function ENT:PassengerCapacity()
return 0
end
function ENT:GetStandingArea()
return Vector(-64,-64,0),Vector(64,64,0)
end
function ENT:BoardPassengers(delta)
self:SetNW2Float("PassengerCount", math.max(0,math.min(self:PassengerCapacity(),self:GetNW2Float("PassengerCount") + delta)))
end
ENT.LeftDoorPositions = { Vector(0,0,0) }
ENT.RightDoorPositions = { Vector(0,0,0) }
ENT.MirrorCams = {
Vector(450,71,24),Angle(1,180,0),15,
Vector(450,-71,24),Angle(1,180,0),15,
}
--------------------------------------------------------------------------------
-- Load/define basic sounds
--------------------------------------------------------------------------------
function ENT:InitializeSounds()
self.SoundPositions = {} -- Positions (used clientside)
self.SoundNames = {}
self.SoundNames["uava_on"] = {
"subway_trains/common/uava/uava_on1.mp3",
"subway_trains/common/uava/uava_on2.mp3",
"subway_trains/common/uava/uava_on3.mp3",
}
self.SoundNames["uava_off"] = {
"subway_trains/common/uava/uava_off1.mp3",
"subway_trains/common/uava/uava_off2.mp3",
"subway_trains/common/uava/uava_off3.mp3",
}
self.SoundNames["uava_reset"] = {
"subway_trains/common/uava/uava_reset1.mp3",
"subway_trains/common/uava/uava_reset2.mp3",
"subway_trains/common/uava/uava_reset4.mp3",
}
self.SoundNames["junk_small"] = {
"subway_trains/common/junk/junk_small1.mp3",
"subway_trains/common/junk/junk_small2.mp3",
"subway_trains/common/junk/junk_small3.mp3",
"subway_trains/common/junk/junk_small4.mp3",
"subway_trains/common/junk/junk_small5.mp3",
"subway_trains/common/junk/junk_small6.mp3",
}
self.SoundNames["junk_medium"] = {
"subway_trains/common/junk/junk_medium1.mp3",
"subway_trains/common/junk/junk_medium2.mp3",
"subway_trains/common/junk/junk_medium3.mp3",
"subway_trains/common/junk/junk_medium4.mp3",
"subway_trains/common/junk/junk_medium5.mp3",
"subway_trains/common/junk/junk_medium6.mp3",
}
self.SoundNames["junk_enginestart_speed"] = {
"subway_trains/common/junk/junk_enginestart_speed1.mp3",
"subway_trains/common/junk/junk_enginestart_speed2.mp3",
"subway_trains/common/junk/junk_enginestart_speed3.mp3",
"subway_trains/common/junk/junk_enginestart_speed4.mp3",
"subway_trains/common/junk/junk_enginestart_speed5.mp3",
}
self.SoundNames["pb_on"] = "subway_trains/common/switches/pb_on.mp3"
self.SoundNames["pb_off"] = "subway_trains/common/switches/pb_off.mp3"
self.SoundNames["vu224_on"] = {
"subway_trains/common/switches/vu224/vu224_on1.mp3",
"subway_trains/common/switches/vu224/vu224_on2.mp3",
"subway_trains/common/switches/vu224/vu224_on3.mp3",
}
self.SoundNames["vu224_off"] = {
"subway_trains/common/switches/vu224/vu224_off1.mp3",
"subway_trains/common/switches/vu224/vu224_off2.mp3",
"subway_trains/common/switches/vu224/vu224_off3.mp3",
}
self.SoundNames["av_on"] = {
"subway_trains/common/switches/va21/va21_on1.mp3",
"subway_trains/common/switches/va21/va21_on2.mp3",
"subway_trains/common/switches/va21/va21_on3.mp3",
"subway_trains/common/switches/va21/va21_on4.mp3",
"subway_trains/common/switches/va21/va21_on5.mp3",
"subway_trains/common/switches/va21/va21_on6.mp3",
}
self.SoundNames["av_off"] = {
"subway_trains/common/switches/va21/va21_off1.mp3",
"subway_trains/common/switches/va21/va21_off2.mp3",
"subway_trains/common/switches/va21/va21_off3.mp3",
"subway_trains/common/switches/va21/va21_off4.mp3",
"subway_trains/common/switches/va21/va21_off5.mp3",
"subway_trains/common/switches/va21/va21_off6.mp3",
}
self.SoundNames["av_knock"] = {
"subway_trains/common/switches/va21/va21_knock1.mp3",
"subway_trains/common/switches/va21/va21_knock2.mp3",
"subway_trains/common/switches/va21/va21_knock3.mp3",
}
self.SoundNames["br_334_1-2"] = "subway_trains/common/334/334_02.mp3"
self.SoundNames["br_334_2-1"] = "subway_trains/common/334/334_01.mp3"
self.SoundNames["br_334_2-3"] = "subway_trains/common/334/334_02.mp3"
self.SoundNames["br_334_3-2"] = "subway_trains/common/334/334_03.mp3"
self.SoundNames["br_334_4-3"] = "subway_trains/common/334/334_03.mp3"
self.SoundNames["br_334_4-5"] = "subway_trains/common/334/334_05.mp3"
self.SoundNames["br_013"] = {
"subway_trains/common/switches/013_1.mp3",
"subway_trains/common/switches/013_2.mp3",
"subway_trains/common/switches/013_3.mp3",
"subway_trains/common/switches/013_4.mp3",
}
for i = 1,10 do
local id1 = Format("b1tunnel_%d",i)
local id2 = Format("b2tunnel_%d",i)
self.SoundNames[id1.."a"] = "subway_trains/bogey/st"..i.."a.wav"
self.SoundNames[id1.."b"] = "subway_trains/bogey/st"..i.."b.wav"
self.SoundPositions[id1.."a"] = {700,1e9,Vector( 317-5,0,-84),1}
self.SoundPositions[id1.."b"] = self.SoundPositions[id1.."a"]
self.SoundNames[id2.."a"] = "subway_trains/bogey/st"..i.."a.wav"
self.SoundNames[id2.."b"] = "subway_trains/bogey/st"..i.."b.wav"
self.SoundPositions[id2.."a"] = {700,1e9,Vector(-317+0,0,-84),1}
self.SoundPositions[id2.."b"] = self.SoundPositions[id2.."a"]
end
for i = 1,14 do
local id1 = Format("b1street_%d",i)
local id2 = Format("b2street_%d",i)
self.SoundNames[id1.."a"] = "subway_trains/bogey/wheels/street_"..i.."a.mp3"
self.SoundNames[id1.."b"] = "subway_trains/bogey/wheels/street_"..i.."b.mp3"
self.SoundPositions[id1.."a"] = {700,1e9,Vector( 317-5,0,-84),1.5}
self.SoundPositions[id1.."b"] = self.SoundPositions[id1.."a"]
self.SoundNames[id2.."a"] = "subway_trains/bogey/wheels/street_"..i.."a.mp3"
self.SoundNames[id2.."b"] = "subway_trains/bogey/wheels/street_"..i.."b.mp3"
self.SoundPositions[id2.."a"] = {700,1e9,Vector(-317+0,0,-84),1.5}
self.SoundPositions[id2.."b"] = self.SoundPositions[id2.."a"]
end
end
--------------------------------------------------------------------------------
-- Sound functions
--------------------------------------------------------------------------------
--[[
function ENT:SetSoundState(sound,volume,pitch,timeout,range)
--if not self.Sounds[sound] then return end
--if sound == "ring" then sound = "zombie_loop" end
if not self.Sounds[sound] then
if self.SoundNames and self.SoundNames[sound] then
local name = self.SoundNames[sound]
if self.SoundPositions[sound] then
local ent_nwID
if self.SoundPositions[sound] == "cabin" then ent_nwID = "seat_driver" end
local ent = self:GetNW2Entity(ent_nwID)
if IsValid(ent) then
self.Sounds[sound] = CreateSound(ent, Sound(name))
else
return
end
else
self.Sounds[sound] = CreateSound(self, Sound(name))
end
else
return
end
end
local default_range = 0.80
if (volume <= 0) or (pitch <= 0) then
self.Sounds[sound]:SetSoundLevel(100*(range or default_range))
self.Sounds[sound]:Stop()
return
end
if soundid == "switch" then default_range = 0.50 end
local pch = math.floor(math.max(0,math.min(255,100*pitch)) + math.random())
self.Sounds[sound]:SetSoundLevel(100*(range or default_range))
local vol = math.max(0,math.min(255,2.55*volume)) + (0.001/2.55) + (0.001/2.55)*math.random()
self.Sounds[sound]:PlayEx(vol,pch+1)
self.Sounds[sound]:ChangeVolume(vol,timeout or 0)
self.Sounds[sound]:ChangePitch(pch+1,timeout or 0)
self.Sounds[sound]:SetSoundLevel(100*(range or default_range))
end
]]
local function PauseBASS(snd)
snd:Pause()
snd:SetTime(0)
end
function ENT:CreateBASSSound(name,callback,noblock,onerr)
if self.StopSounds or not self.ClientPropsInitialized or self.CreatingCSEnts then return end
--if self.SoundSpawned and name:find(".wav") then return end
--self.SoundSpawned = true
sound.PlayFile(Sound("sound/"..name), "3d noplay mono"..(noblock and " noblock" or ""), function( snd,err,errName )
if not IsValid(self) then destroySound(snd) return end
if err then
self:DestroySound(snd)
if err == 4 or err == 37 then self.StopSounds = true end
if err ~= 41 then
MsgC(Color(255,0,0),Format("Sound:%s\n\tErrCode:%s, ErrName:%s\n",name,err,errName))
if onerr then callback(false) end
elseif GetConVar("metrostroi_drawdebug"):GetInt() ~= 0 then
MsgC(Color(255,255,0),Format("Sound:%s\n\tBASS_ERROR_UNKNOWN (it's normal),ErrCode:%s, ErrName:%s\n",name,err,errName))
self:CreateBASSSound(name,callback)
end
return
elseif not self.Sounds then
self:DestroySound(snd)
if onerr then callback(false) end
else
callback(snd)
end
end )
end
function ENT:SetPitchVolume(snd,pitch,volume,tbl)
if not IsValid(snd) then return end
if tbl then
if tbl[4] then
snd:SetVolume(tbl[4]*volume)
else
snd:SetVolume(volume)
end
else
snd:SetVolume(volume)
end
snd:SetPlaybackRate(pitch)
end
function ENT:SetBASSPos(snd,tbl)
if tbl then
snd:SetPos(self:LocalToWorld(tbl[3]),self:GetAngles():Forward())
else
snd:SetPos(self:GetPos())
end
end
function ENT:SetBassParameters(snd,pitch,volume,tbl,looping,spec)
if snd:GetState() ~= GMOD_CHANNEL_STOPPED and snd:GetState() ~= GMOD_CHANNEL_PAUSED then
return
end
self:SetBASSPos(snd,tbl)
if tbl then
snd:Set3DFadeDistance(tbl[1],tbl[2])
if tbl[4] then
snd:SetVolume(tbl[4]*volume)
else
snd:SetVolume(volume)
end
else
snd:Set3DFadeDistance(200,1e9)
snd:SetVolume(volume)
end
snd:EnableLooping(looping or false)
snd:SetPlaybackRate(pitch)
local siz1,siz2 = snd:Get3DFadeDistance()--[[]
debugoverlay.Sphere(snd:GetPos(),4,2,Color(0,255,0),true)
debugoverlay.Sphere(snd:GetPos(),siz1,2,Color(255,0,0,100),false)]]
--debugoverlay.Sphere(snd:GetPos(),siz2,2,Color(0,0,255,100),false)
end
function ENT:SetSoundState(soundid,volume,pitch,time)
--volume = (input.IsKeyDown( KEY_LALT ) and soundid == "horn") and 0 or 1+math.sin(CurTime()*3)*0.2
--pitch = (input.IsKeyDown( KEY_LALT ) and soundid == "horn") and 1 or 1+math.sin(CurTime()*3)*0.2
if self.StopSounds or not self.ClientPropsInitialized or self.CreatingCSEnts then return end
local name = self.SoundNames and self.SoundNames[soundid]
local tbl = self.SoundPositions[soundid]
local looptbl = type(name) == "table" and name
if looptbl and #name > 1 then --triple-looped sound
if not self.Sounds.loop[soundid] then self.Sounds.loop[soundid] = {state=false,newstate=false,pitch=0} end
local sndtbl = self.Sounds.loop[soundid]
if volume > 0 then sndtbl.volume = volume end
if pitch > 0 then sndtbl.pitch = pitch end
for i,v in ipairs(name) do
if not sndtbl[i] then sndtbl[i] = {} end
if not IsValid(sndtbl[i].sound) and sndtbl[i].sound ~= false then
self:CreateBASSSound(v,function(snd)
if not snd then
destroySound(sndtbl[i].sound)
sndtbl[i].sound = nil
return
end
snd:SetPos(self:LocalToWorld(tbl[3]),self:GetAngles():Forward())
sndtbl[i].sound = snd
sndtbl[i].volume = volume > 0 and sndtbl.volume or volume or 0
self:SetBassParameters(snd,pitch,sndtbl[i].volume,tbl,i==2)
end,true,true)
sndtbl[i].sound = false
end
end
local state = volume > 0
if sndtbl.state ~= state then
sndtbl[1].state = state
if not state then sndtbl[2].state = false end
sndtbl[3].state = not state
sndtbl.control = state and 1 or 3
sndtbl.state = state
end
else
if looptbl then name = name[1] end
local snd = self.Sounds[soundid]
if not IsValid(snd) and name and snd ~= false then
self:CreateBASSSound(name,function(snd)
if not snd then
destroySound(self.Sounds[soundid])
self.Sounds[soundid] = nil
return
end
self.Sounds[soundid] = snd
self.Sounds.isloop[soundid] = true
self:SetBassParameters(snd,pitch,volume,tbl,looptbl and looptbl.loop)
end,true,true)
self.Sounds[soundid] = false
return
end
if not IsValid(snd) then return end
local default_range = 0.80
if ((volume <= 0) or (pitch <= 0)) then
if snd:GetTime() > 0 then
PauseBASS(snd)
end
return
end
if snd:GetState() ~= GMOD_CHANNEL_PLAYING then
if timeout then
snd:SetTime(time)
end
snd:Play()
end
snd:SetPlaybackRate(pitch)
if tbl and tbl[4] then
snd:SetVolume(tbl[4]*volume)
else
snd:SetVolume(volume)
end
end
if soundid == "switch" then default_range = 0.50 end
local pch = math.floor(math.max(0,math.min(255,100*pitch)) + math.random())
--self.Sounds[soundid]:SetSoundLevel(100*(range or default_range))
--local vol = math.max(0,math.min(255,2.55*volume)) + (0.001/2.55) + (0.001/2.55)*math.random()
--self.Sounds[soundid]:PlayEx(vol,pch+1)
--self.Sounds[soundid]:ChangeVolume(vol,timeout or 0)
--self.Sounds[soundid]:ChangePitch(pch+1,timeout or 0)
--self.Sounds[soundid]:SetSoundLevel(100*(range or default_range))
end
--[[function ENT:CheckActionTimeout(action,timeout)
self.LastActionTime = self.LastActionTime or {}
self.LastActionTime[action] = self.LastActionTime[action] or (CurTime()-1000)
if CurTime() - self.LastActionTime[action] < timeout then return true end
self.LastActionTime[action] = CurTime()
return false
end
]]--
if SERVER then
util.AddNetworkString("metrostroi_client_sound")
else
net.Receive("metrostroi_client_sound", function(size)
local train = net.ReadEntity()
if not IsValid(train) or not train.PlayOnce or not train:ShouldRenderClientEnts() then return end
local snd = net.ReadString()
local pos = net.ReadString()
local range = net.ReadFloat()
local pitch = net.ReadUInt(9)/100
if pitch == 0 then pitch = 1 end
if pos == "styk" and train.OnStyk then
local opsnd,oppos,oprange,oppitch = train:OnStyk(snd,pos,range,pitch)
if opsnd then
train:PlayOnce(opsnd or snd,oppos or pos,oprange or range,oppitch or pitch)
end
elseif train.OnPlay then
local opsnd,oppos,oprange,oppitch = train:OnPlay(snd,pos,range,pitch)
if opsnd then
train:PlayOnce(opsnd or snd,oppos or pos,oprange or range,oppitch or pitch)
end
elseif snd then
train:PlayOnce(snd,pos,range,pitch)
end
end)
end
if SERVER then
function ENT:PlayOnce(soundid,location,range,pitch,randoff)
if self.OnPlay then
soundid,location,range,pitch = self:OnPlay(soundid,location,range,pitch)
end
net.Start("metrostroi_client_sound",true)
net.WriteEntity(self)
net.WriteString(soundid)
net.WriteString(location or "")
net.WriteFloat(range or 0.8)
net.WriteUInt((pitch or 1)*100,9)
net.SendPAS(self:GetPos())
end
else
function ENT:PlayOnceFromPos(id,sndname,volume,pitch,min,max,location)
if self.StopSounds or not self.ClientPropsInitialized or self.CreatingCSEnts then return end
self:DestroySound(self.Sounds[id],true)
self.Sounds[id] = nil
if sndname == "_STOP" then return end
self.SoundPositions[id] = {min,max,location}
self:CreateBASSSound(sndname,function(snd)
self.Sounds[id] = snd
self:SetBassParameters(self.Sounds[id],pitch,volume,self.SoundPositions[id],false)
snd:Play()
end)
end
function ENT:PlayOnce(soundid,location,range,pitch,randoff)
if self.StopSounds or not self.ClientPropsInitialized or self.CreatingCSEnts then return end
if not soundid then
ErrorNoHalt(debug.Trace())
end
-- Emit sound from right location
if self.ClientSounds and self.ClientSounds[soundid] then
local entsound = self.ClientSounds[soundid]
for i,esnd in ipairs(entsound) do
soundid = esnd[2](self,range,location)
local soundname = self.SoundNames[soundid]
if not soundname then print("NO SOUND",soundname,soundid) continue end
if type(soundname) == "table" then soundname = table.Random(soundname) end
if IsValid(self.ClientEnts[esnd[1]]) and not self.ClientEnts[esnd[1]].snd then
local ent = self.ClientEnts[esnd[1]]
sound.PlayFile( "sound/"..soundname, "3d noplay mono", function( snd,err,errName )
if not IsValid(self) then destroySound(snd) return end
if err then
self:DestroySound(snd)
if err == 4 or err == 37 then self.StopSounds = true end
if err ~= 41 then
MsgC(Color(255,0,0),Format("Sound:%s\n\tErrCode:%s, ErrName:%s\n",name,err,errName))
elseif GetConVar("metrostroi_drawdebug"):GetInt() ~= 0 then
MsgC(Color(255,255,0),Format("Sound:%s\n\tBASS_ERROR_UNKNOWN (it's normal),ErrCode:%s, ErrName:%s\n",name,err,errName))
--self:PlayOnce(soundid,location,range,pitch,randoff)
end
return
elseif not IsValid(ent) then
self:DestroySound(snd)
else
snd:SetPos(ent:GetPos(),ent:LocalToWorldAngles(esnd[7]):Forward())
snd:SetPlaybackRate(esnd[4])
snd:SetVolume(esnd[3])
if esnd[5] then
snd:Set3DFadeDistance(esnd[5],esnd[6])
end
table.insert(ent.BASSSounds,snd)
snd:Play()
--local siz1,siz2 = snd:Get3DFadeDistance()
--debugoverlay.Sphere(snd:GetPos(),4,2,Color(0,255,0),true)
--debugoverlay.Sphere(snd:GetPos(),siz1,2,Color(255,0,0,100),false)
--debugoverlay.Sphere(snd:GetPos(),siz2,2,Color(0,0,255,100),false)
end
end)
end
end
return
end
local tbl = self.SoundPositions[soundid]
local soundname = self.SoundNames[soundid]
if type(soundname) == "table" then soundname = table.Random(soundname) end
if not soundname or not tbl then
--print("NO SOUND",soundname,soundid)
return
end
if IsValid(self.Sounds[soundid]) then
self:DestroySound(self.Sounds[soundid])
self.Sounds[soundid] = nil
end
self:CreateBASSSound(soundname,function(snd)
self.Sounds[soundid] = snd
self:SetBassParameters(self.Sounds[soundid],pitch,range,tbl,false)
snd:Play()
end)
end
end
--------------------------------------------------------------------------------
-- Load a single system with given name
--------------------------------------------------------------------------------
function ENT:LoadSystem(a,b,...)
local name
local sys_name
if b then
name = b
sys_name = a
else
name = a
sys_name = a
end
if not Metrostroi.Systems[name] then ErrorNoHalt("No system defined: "..name) return end
if self.Systems[sys_name] then ErrorNoHalt("System already defined: "..sys_name) return end
local no_acceleration = Metrostroi.BaseSystems[name].DontAccelerateSimulation
local run_everywhere = Metrostroi.BaseSystems[name].RunEverywhere
if SERVER and Turbostroi and not self.DontAccelerateSimulation then
-- Load system into turbostroi
if (not GLOBAL_SKIP_TRAIN_SYSTEMS) then
Turbostroi.LoadSystem(sys_name,name,...)
end
-- Load system locally (this may load any systems nested in the initializer)
GLOBAL_SKIP_TRAIN_SYSTEMS = GLOBAL_SKIP_TRAIN_SYSTEMS or 0
if GLOBAL_SKIP_TRAIN_SYSTEMS then GLOBAL_SKIP_TRAIN_SYSTEMS = GLOBAL_SKIP_TRAIN_SYSTEMS + 1 end
self[sys_name] = Metrostroi.Systems[name](self,...)
GLOBAL_SKIP_TRAIN_SYSTEMS = GLOBAL_SKIP_TRAIN_SYSTEMS - 1
if GLOBAL_SKIP_TRAIN_SYSTEMS == 0 then GLOBAL_SKIP_TRAIN_SYSTEMS = nil end
-- Setup nice name as normal
--if (name ~= sys_name) or (b) then self[sys_name].Name = sys_name end
self[sys_name].Name = sys_name
self.Systems[sys_name] = self[sys_name]
-- Create fake placeholder
if not no_acceleration then
if run_everywhere then
local old_func = self[sys_name].TriggerInput
self[sys_name].TriggerInput = function(system,name,value)
old_func(self,sys_name,name,value)
Turbostroi.TriggerInput(self,sys_name,name,value)
end
else
self[sys_name].TriggerInput = function(system,name,value)
Turbostroi.TriggerInput(self,sys_name,name,value)
end
end
self[sys_name].Think = function() end
end
else
-- Load system like normal
self[sys_name] = Metrostroi.Systems[name](self,...)
--if (name ~= sys_name) or (b) then self[sys_name].Name = sys_name end
self[sys_name].Name = sys_name
self.Systems[sys_name] = self[sys_name]
--if SERVER then
--[[self[sys_name].TriggerOutput = function(sys,name,value)
local varname = (sys.Name or "")..name
--self:TriggerOutput(varname, tonumber(value) or 0)
self.DebugVars[varname] = value
end]]--
--end
end
end
function ENT:SetupDataTables()
self._NetData = {{},{}}
end
---------------------------------------------------------------------------------------
-- Sends and get float via NWVars
---------------------------------------------------------------------------------------
function ENT:SetPackedRatio(idx,value)
--local idx = type(idx) == "number" and 999-idx or idx
if self._NetData[2][idx] ~= nil and self._NetData[2][idx] == math.floor(value*1000+0.5) then return end
self:SetNW2Int(idx,math.floor(value*1000+0.5))
end
function ENT:GetPackedRatio(idx)
return self:GetNW2Int(idx)*0.001
end
--------------------------------------------------------------------------------
-- Sends and get bool via NWVars
--------------------------------------------------------------------------------
function ENT:SetPackedBool(idx,value)
if self._NetData[1][idx] ~= nil and self._NetData[1][idx] == value then return end
self:SetNW2Bool(idx,value)
end
function ENT:GetPackedBool(idx)
return self:GetNW2Bool(idx)
end
ENT.SubwayTrain = {
Type = "Base",
Name = "Base",
WagType = 2,
ALS = {
HaveAutostop = false,
TwoToSix = true,
RSAs325Hz = true,
Aproove0As325Hz = false,
},
}