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

538 lines
19 KiB
Lua

AddCSLuaFile("cl_init.lua")
AddCSLuaFile("shared.lua")
include("shared.lua")
--------------------------------------------------------------------------------
function ENT:Initialize()
-- Defined train information
self.SubwayTrain = {
Type = "AI",
Name = "",
}
if not self.TrainType then self.TrainType = "81-717" end
-- Set model and initialize
self.NoPhysics = true
if self.TrainType == "81-717" then self:SetModel("models/metrostroi/81/81-7036.mdl") end
if self.TrainType == "81-714" then self:SetModel("models/metrostroi/81/81-7037.mdl") end
self.BaseClass.Initialize(self)
-- Create bogeys
self.FrontBogey = self:CreateBogey(Vector( 325-20,0,-75),Angle(0,180,0),true)
self.RearBogey = self:CreateBogey(Vector(-325-10,0,-75),Angle(0,0,0),false)
-- Seats
if self.TrainType == "81-717" then
self.DriverSeat = self:CreateSeat("driver",Vector(410,-2,-23))
--self.InstructorsSeat = self:CreateSeat("instructor",Vector(410,35,-28))
--self.ExtraSeat = self:CreateSeat("instructor",Vector(410,-35,-28))
end
--[[
for i=1,1 do --17
local pos = Vector(280-(i-1)*30-math.floor((i-1)/5)*80,-47,-32)
local p1 = self:CreateSeat("passenger",pos,Angle(0,90,0))
pos.y = -pos.y
local p2 = self:CreateSeat("passenger",pos,Angle(0,270,0))
end]]
-- Setup door positions
self.LeftDoorPositions = {}
self.RightDoorPositions = {}
for i=0,3 do
table.insert(self.LeftDoorPositions,Vector(353.0 - 35*0.5 - 231*i,65,-1.8))
table.insert(self.RightDoorPositions,Vector(353.0 - 35*0.5 - 231*i,-65,-1.8))
end
-- Find SOME sort of route
local route
for k,v in pairs(Metrostroi.AIConfiguration) do
if not route then route = k end
end
-- Initial setup
if not self.Route then self.Route = route end
if (not self.PathID) and (route) and Metrostroi.AIConfiguration[route] then
self.PathID = Metrostroi.AIConfiguration[route].Path
end
self.Position = self.Position or 100
self.Velocity = 0
self.RheostatPosition = 0
-- Lights
if self.TrainType == "81-717" then
self.Lights = {
-- Head
[1] = { "headlight", Vector(465,0,-20), Angle(0,0,0), Color(176,161,132), fov = 100 },
[2] = { "glow", Vector(460, 51,-23), Angle(0,0,0), Color(255,255,255), brightness = 2 },
[3] = { "glow", Vector(460,-51,-23), Angle(0,0,0), Color(255,255,255), brightness = 2 },
[4] = { "glow", Vector(460,-8, 55), Angle(0,0,0), Color(255,255,255), brightness = 0.3 },
[5] = { "glow", Vector(460,-8, 55), Angle(0,0,0), Color(255,255,255), brightness = 0.3 },
[6] = { "glow", Vector(460, 2, 55), Angle(0,0,0), Color(255,255,255), brightness = 0.3 },
[7] = { "glow", Vector(460, 2, 55), Angle(0,0,0), Color(255,255,255), brightness = 0.3 },
-- Reverse
[8] = { "light", Vector(458,-45, 55), Angle(0,0,0), Color(255,0,0), brightness = 10, scale = 1.0 },
[9] = { "light", Vector(458, 45, 55), Angle(0,0,0), Color(255,0,0), brightness = 10, scale = 1.0 },
-- Cabin
[10] = { "dynamiclight", Vector( 420, 0, 35), Angle(0,0,0), Color(255,255,255), brightness = 0.1, distance = 550 },
-- Interior
[12] = { "dynamiclight", Vector( 0, 0, 5), Angle(0,0,0), Color(255,255,255), brightness = 3, distance = 400 },
-- Side lights
[14] = { "light", Vector(-50, 68, 54), Angle(0,0,0), Color(255,0,0), brightness = 0.5, scale = 0.10, texture = "models/metrostroi_signals/signal_sprite_002.vmt" },
[15] = { "light", Vector(4, 68, 54), Angle(0,0,0), Color(150,255,255), brightness = 0.6, scale = 0.10, texture = "models/metrostroi_signals/signal_sprite_002.vmt" },
[16] = { "light", Vector(1, 68, 54), Angle(0,0,0), Color(0,255,0), brightness = 0.5, scale = 0.10, texture = "models/metrostroi_signals/signal_sprite_002.vmt" },
[17] = { "light", Vector(-2, 68, 54), Angle(0,0,0), Color(255,255,0), brightness = 0.5, scale = 0.10, texture = "models/metrostroi_signals/signal_sprite_002.vmt" },
[18] = { "light", Vector(-50, -69, 54), Angle(0,0,0), Color(255,0,0), brightness = 0.5, scale = 0.10, texture = "models/metrostroi_signals/signal_sprite_002.vmt" },
[19] = { "light", Vector(5, -69, 54), Angle(0,0,0), Color(150,255,255), brightness = 0.6, scale = 0.10, texture = "models/metrostroi_signals/signal_sprite_002.vmt" },
[20] = { "light", Vector(2, -69, 54), Angle(0,0,0), Color(0,255,0), brightness = 0.5, scale = 0.10, texture = "models/metrostroi_signals/signal_sprite_002.vmt" },
[21] = { "light", Vector(-1, -69, 54), Angle(0,0,0), Color(255,255,0), brightness = 0.5, scale = 0.10, texture = "models/metrostroi_signals/signal_sprite_002.vmt" },
}
end
if self.TrainType == "81-714" then
self.Lights = {
-- Interior
[12] = { "dynamiclight", Vector( 0, 0, 5), Angle(0,0,0), Color(255,255,255), brightness = 3, distance = 400 },
-- Side lights
[14] = { "light", Vector(-50, 68, 54), Angle(0,0,0), Color(255,0,0), brightness = 0.5, scale = 0.10, texture = "models/metrostroi_signals/signal_sprite_002.vmt" },
[15] = { "light", Vector(4, 68, 54), Angle(0,0,0), Color(150,255,255), brightness = 0.6, scale = 0.10, texture = "models/metrostroi_signals/signal_sprite_002.vmt" },
[16] = { "light", Vector(1, 68, 54), Angle(0,0,0), Color(0,255,0), brightness = 0.5, scale = 0.10, texture = "models/metrostroi_signals/signal_sprite_002.vmt" },
[17] = { "light", Vector(-2, 68, 54), Angle(0,0,0), Color(255,255,0), brightness = 0.5, scale = 0.10, texture = "models/metrostroi_signals/signal_sprite_002.vmt" },
[18] = { "light", Vector(-50, -69, 54), Angle(0,0,0), Color(255,0,0), brightness = 0.5, scale = 0.10, texture = "models/metrostroi_signals/signal_sprite_002.vmt" },
[19] = { "light", Vector(5, -69, 54), Angle(0,0,0), Color(150,255,255), brightness = 0.6, scale = 0.10, texture = "models/metrostroi_signals/signal_sprite_002.vmt" },
[20] = { "light", Vector(2, -69, 54), Angle(0,0,0), Color(0,255,0), brightness = 0.5, scale = 0.10, texture = "models/metrostroi_signals/signal_sprite_002.vmt" },
[21] = { "light", Vector(-1, -69, 54), Angle(0,0,0), Color(255,255,0), brightness = 0.5, scale = 0.10, texture = "models/metrostroi_signals/signal_sprite_002.vmt" },
}
end
-- Prop-protection related
if CPPI and IsValid(self.Owner) then
self:CPPISetOwner(self.Owner)
end
-- Spawn a dummy consist
if (self.TrainType == "81-717") and (not self.TrainHead) then
for i=2,5 do
local ent = ents.Create("gmod_subway_ai")
if i == 5
then ent.TrainType = "81-717"
else ent.TrainType = "81-714"
end
ent.TrainIndex = i
ent.TrainHead = self
ent.Owner = self.Owner
ent:Spawn()
table.insert(self.TrainEntities,ent)
end
end
--self:Remove()
-- Type
self:SetNW2String("TrainType",self.TrainType)
end
--[[concommand.Add("metrostroi_ai_spawn", function(ply, _, args)
if (ply:IsValid()) and (not ply:IsAdmin()) then return end
local pathid = tonumber(args[2]) or 1
local trainCounter = tonumber(args[1]) or 1
local prevEnt
timer.Create("metrostroi-ai-spawntimer-"..pathid,1.0,0,function()
if prevEnt then
if (pathid == 1) and (prevEnt.Position < 260) then
return
end
if (pathid == 2) and (prevEnt.Position < 960) then
return
end
end
if trainCounter < 1 then return end
local ent = ents.Create("gmod_subway_ai")
ent.Position = 150
ent.PathID = pathid
ent:Spawn()
prevEnt = ent
trainCounter = trainCounter - 1
print("Spawning AI trains (path "..pathid.."), left: "..trainCounter)
end)
end)
concommand.Add("metrostroi_ai_clear", function(ply, _, args)
if (ply:IsValid()) and (not ply:IsAdmin()) then return end
for k,v in pairs(ents.FindByClass("gmod_subway_ai")) do
SafeRemoveEntity(v)
if args[1] then print("Removed one") return end
end
--timer.Create("metrostroi-ai-spawntimer",1.0,0,function()end)
end)]]--
concommand.Add("metrostroi_ai_info", function(ply, _, args)
if (ply:IsValid()) and (not ply:IsAdmin()) then return end
for k,v in pairs(ents.FindByClass("gmod_subway_ai")) do
if not v.TrainHead then
print(Format("Train to [%03d][%02d] (%.0f m %.02f km/h, left %0.3f m)",
v.TargetStation or 0,v.TargetPlatform or 0,v.Position,v.Speed,
(v.PlatformEdgeX or 0) - v.Position))
end
end
end)
--------------------------------------------------------------------------------
-- Train driving AI
--------------------------------------------------------------------------------
function ENT:DoAI(dT)
-- Get a schedule
if self.Schedule and (#self.Schedule == 0) then
self.Schedule = nil
end
if (not self.Schedule) and (not self.NoStation) then
self.Schedule = Metrostroi.GenerateSchedule(self.Route)
self.StopTimer = 10
end
-- See if must move to next station
if self.Schedule then
if ((Metrostroi.ServerTime()+10000 > (self.Schedule[1][3]*60)) and (self.StopTimer < 0)) or
(self.StopTimer < -200) then
table.remove(self.Schedule,1)
self.StopTimer = 10
end
end
-- Get current target station info
local platformEdgeX
if self.Schedule and self.Schedule[1] then
local targetStation = self.Schedule[1][1]
local targetPlatform = self.Schedule[1][2]
local stationData = Metrostroi.Stations[targetStation]
local platformData
if stationData then platformData = stationData[targetPlatform] end
if platformData then
platformEdgeX = math.max(platformData.x_end,platformData.x_start)
end
if platformData and platformData.node_end then
if platformData.node_end.path.id ~= self.PathID then
--print("WRONG PATH")
platformEdgeX = nil
end
end
self.TargetStation = targetStation
self.TargetPlatform = targetPlatform
else
self.NoStation = true
end
self.PlatformEdgeX = platformEdgeX
if platformEdgeX then
if self.Position > platformEdgeX then
--print("Overrun!",self.Position,platformEdgeX)
table.remove(self.Schedule,1)
self.StopTimer = 10
end
end
-- Get current information on driving
local speedLimit = self.ALS_ARS.SpeedLimit
local nextLimit = self.ALS_ARS.NextLimit
local targetSpeed = nextLimit
--print()
if nextLimit == 0 then targetSpeed = speedLimit end
-- Move at slow speed to next red light or blocked section
if targetSpeed == 0 then targetSpeed = 20 end
-- If there is a red light ahead, stop once in its range
if self.RedLightDistance and (self.RedLightDistance < 20) then
targetSpeed = 0
end
-- Stop at station gradually
if platformEdgeX and (platformEdgeX > self.Position) then
local dX = platformEdgeX - self.Position
if dX < 100 then
targetSpeed = math.min(targetSpeed,55) * (math.max(0.0,math.min(1.0,(dX-12)/90))^0.5)
if dX > 18 then targetSpeed = math.max(targetSpeed,20) end
if self.Speed < 1 then
self.StopTimer = self.StopTimer - dT
end
end
end
-- Wait for schedule start
if (self.PathID == 1) and (self.Position < 250) and
(self.Schedule) and (self.Schedule[1]) then
local dT = self.Schedule[1][3]*60 - Metrostroi.ServerTime()
--if dT > 90 then targetSpeed = 0 end
end
--targetSpeed = 0
-- Reached target speed, stop accelerating
if self.Speed > (targetSpeed-2) then
self.Accelerating = false
end
-- Speed is below required, try to accelerate
if self.Speed < (targetSpeed-10) then
self.Accelerating = true
end
-- Exceeding speed limit, apply brakes
if self.Speed > targetSpeed then
self.Braking = true
end
-- Braked enough, stop braking
if (self.Speed < (targetSpeed-5)) and (self.Braking) then
self.Braking = false
end
-- ARS system logic
if false and self.ALS_ARS.LVD then
self.Braking = true
self.Accelerating = false
end
--print(self.ALS_ARS.LVD)
if self.ALS_ARS.LVD
then self.ALS_ARS.AttentionPedal = true
else self.ALS_ARS.AttentionPedal = false
end
if speedLimit == 0 then self.ALS_ARS.AttentionPedal = true end
-- Apply pneumatic brakes if overspeeding much or stopped
self.Pneumo = false
if (self.Speed < 7) and (not self.Accelerating) then
self.Pneumo = true
end
if (self.Speed > (targetSpeed+5)) then
--self.Pneumo = true
end
-- Save for statistics
self.TargetSpeed = targetSpeed
--if self.RedLightDistance and (self.RedLightDistance < 30) then self.Pneumo = true end
end
--------------------------------------------------------------------------------
-- Train physics
--------------------------------------------------------------------------------
function ENT:DoPhysics(dT)
-- Slopes code
local slopeAngle = self:GetAngles().p
if slopeAngle > 180 then slopeAngle = slopeAngle-360 end
local slopeFactor = math.min(8.0,math.max(-8.0,slopeAngle))/8.0
-- Motor code
local motorPower = 0
if self.Accelerating then motorPower = 1.0 end
if self.Braking then motorPower = -1.0 end
local motorForce = 0
if motorPower > 0 then motorForce = 1.25*motorPower end
if motorPower < 0 then motorForce = -1.3*math.abs(motorPower) * math.max(-1.0,math.min(1.0,0.25*self.Velocity)) end
-- Brake code
local brakeForce = 0
if self.Pneumo then
brakeForce = -1.4*math.max(-1.0,math.min(1.0,3.0*self.Velocity))
slopeFactor = slopeFactor*math.max(-1.0,math.min(1.0,3.0*self.Velocity))
end
self.PneumoForce = brakeForce
-- Integrate position and velocity
self.Acceleration = 0
+motorForce
+brakeForce
-self.Velocity*0.0045
+slopeFactor*1.52
self.Velocity = self.Velocity + dT*self.Acceleration
self.Position = self.Position + dT*self.Velocity
--print(Format("%.2f/%.2f km/h %.0f m A-%s B-%s P-%s",
--self.Speed,self.TargetSpeed,self.Position,
--tostring(self.Accelerating),tostring(self.Braking),tostring(self.Pneumo)))
-- Info
self.MotorPower = motorPower
end
function ENT:Think()
-- Basic think loop
self.PrevTime = self.PrevTime or CurTime()
self.DeltaTime = (CurTime() - self.PrevTime)
self.PrevTime = CurTime()
--self:RecvPackedData()
self:NextThink(CurTime()+0.10)
-- Simulate equipment specific to trains
local dT = self.DeltaTime
if (self.TrainType == "81-717") and (not self.TrainHead) then
self.ALS_ARS:Think(dT,1)
end
-- Select path
if (not self.PathID) or (not self.Route) then return true end
local path = Metrostroi.Paths[self.PathID]
local config = Metrostroi.AIConfiguration[self.Route]
if self.Position > config.EndPosition then
self.Route = config.NextRoute
config = Metrostroi.AIConfiguration[self.Route]
self.PathID = config.Path
self.Position = config.SpawnPosition
self.Velocity = 0
self.Schedule = nil
self.NoStation = false
end
--self.Velocity = 0
----------------------------------------------------------------------------
-- If needed, update train physics and AI
if not self.TrainHead then
self:DoAI(dT)
self:DoPhysics(dT)
else
if not IsValid(self.TrainHead) then
SafeRemoveEntity(self)
return
end
self.Route = self.TrainHead.Route
self.PathID = self.TrainHead.PathID
self.Position = self.TrainHead.Position - 18.6*(self.TrainIndex-1)
self.Velocity = self.TrainHead.Velocity
self.MotorPower = self.TrainHead.MotorPower
self.PneumoForce = self.TrainHead.PneumoForce
end
----------------------------------------------------------------------------
-- Lighting
if self.TrainType == "81-717" then
self:SetLightPower(1, self.TrainHead == nil)
self:SetLightPower(2, self.TrainHead == nil)
self:SetLightPower(3, self.TrainHead == nil)
self:SetLightPower(4, self.TrainHead == nil)
self:SetLightPower(5, self.TrainHead == nil)
self:SetLightPower(6, self.TrainHead == nil)
self:SetLightPower(7, self.TrainHead == nil)
self:SetLightPower(8, self.TrainHead ~= nil)
self:SetLightPower(9, self.TrainHead ~= nil)
self:SetLightPower(10, (CurTime() % 60) > 0.1)
self:SetLightPower(12, (CurTime() % 60) > 0.1)
end
if self.TrainType == "81-714" then
self:SetLightPower(12, (CurTime() % 60) > 0.1)
end
-- Pneumatic brakes
self.PneumaticPressure = self.PneumaticPressure or 0
self.PneumaticPressure_dPdT = self.PneumaticPressure_dPdT or 0
if self.Pneumo
then self.PneumaticPressure_dPdT = 0.65*(1.5 - self.PneumaticPressure)
else self.PneumaticPressure_dPdT = 0.65*(0.0 - self.PneumaticPressure)
end
self.PneumaticPressure = self.PneumaticPressure + self.PneumaticPressure_dPdT*dT
-- Minor state
if self.TrainHead then
self.LeftDoorsOpen = self.TrainHead.LeftDoorsOpen
self.RightDoorsOpen = self.TrainHead.RightDoorsOpen
else
self.LeftDoorsOpen = self.StopTimer and (self.StopTimer < 9)
self.RightDoorsOpen = self.StopTimer and (self.StopTimer < 9)
end
if self.LeftDoorsOpen ~= self.PrevLeftDoorsOpen then
self.PrevLeftDoorsOpen = self.LeftDoorsOpen
if self.LeftDoorsOpen then
self:PlayOnce("door_open1")
else
self:PlayOnce("door_close1")
end
end
if self.RightDoorsOpen ~= self.PrevRightDoorsOpen then
self.PrevRightDoorsOpen = self.RightDoorsOpen
if self.RightDoorsOpen then
self:PlayOnce("door_open1")
else
self:PlayOnce("door_close1")
end
end
self:SetPackedBool(21,self.LeftDoorsOpen)
self:SetPackedBool(22,self.LeftDoorsOpen)
self:SetPackedBool(23,self.LeftDoorsOpen)
self:SetPackedBool(24,self.LeftDoorsOpen)
self:SetPackedBool(25,self.RightDoorsOpen)
self:SetPackedBool(26,self.RightDoorsOpen)
self:SetPackedBool(27,self.RightDoorsOpen)
self:SetPackedBool(28,self.RightDoorsOpen)
self:SetPackedBool(52,1)
self:SetPackedBool(39,self.ALS_ARS.LVD and (not self.TrainHead))
-- Update state of all objects and sounds
self.Speed = math.abs(self.Velocity/0.277778)
self.FrontBogey.Speed = self.Speed
self.RearBogey.Speed = self.Speed
self.FrontBogey.MotorPower = self.MotorPower
self.RearBogey.MotorPower = self.MotorPower
self.FrontBogey.BrakeCylinderPressure_dPdT = -self.PneumaticPressure_dPdT
self.RearBogey.BrakeCylinderPressure_dPdT = -self.PneumaticPressure_dPdT
self.FrontBogey.BrakeSqueal = math.min(1,(3*math.abs(self.PneumoForce or 0))^1)
self.RearBogey.BrakeSqueal = math.min(1,(3*math.abs(self.PneumoForce or 0))^1)
----------------------------------------------------------------------------
-- Update train position
local vec,dir,node = Metrostroi.GetTrackPosition(path,self.Position)
if vec then
--local vec1,dir1 = Metrostroi.GetTrackPosition(path,self.Position+0)
local vec2,dir2 = Metrostroi.GetTrackPosition(path,self.Position-5)
if dir2 then
dir = dir2
end
if self.TrainHead then dir = -dir end
--[[local trace = {
start = vec,
endpos = vec + Vector(0,0,-384),
mask = MASK_NPCWORLDSTATIC
}
local result = util.TraceLine(trace)]]--
local rollAngle = Angle(0,0,0)--Angle(0,0,(180.0/math.pi)*math.acos(result.HitNormal.z))
self:SetPos(vec)
self:SetAngles(dir:Angle() + rollAngle)
end
-- Update information about restrictions in driving
self.RestrictionTimeout = self.RestrictionTimeout or 0
if (CurTime() - self.RestrictionTimeout) > 0.50 then
self.RestrictionTimeout = CurTime()
if node and (not self.TrainHead) then
self.RedLightDistance = nil
-- Check ARS signal/traffic light being red
local nextARS = Metrostroi.GetARSJoint(node,self.Position,true)
if nextARS and nextARS.AutoEnabled then
local arsOffset = (nextARS.ARSOffset or self.Position)
local dX = math.abs(arsOffset - self.Position)
if (not self.PlatformEdgeX) or (arsOffset < self.PlatformEdgeX) then
self.RedLightDistance = dX
end
end
-- Find other trains on the same line
if not self.RedLightDistance then
for k,v in pairs(ents.FindByClass("gmod_subway_ai")) do
if (v.PathID == self.PathID) and (v ~= self) and (v.Position > self.Position) then
self.RedLightDistance = math.abs(v.Position - self.Position)
end
end
end
end
end
-- self:SendPackedData()
return true
end