1
0
mirror of https://github.com/metrostroi-repo/MetrostroiAddon.git synced 2026-05-02 00:42:29 +00:00
Files
MetrostroiAddon/lua/metrostroi/cl_util.lua
Ivan Gordeev 2b5cc47ae8 #289 (#301)
* 81-717.
Убраны засветы подсветки, если у клиента не включены тени

* Global change.
Фикс названия переменной в конфиге лампочки

* 81-718.
Убраны засветы от лампочек кнопок, если у клиента не включены тени
2021-07-30 11:47:10 +03:00

1010 lines
43 KiB
Lua

--------------------------------------------------------------------------------
-- Clientside utility functions
--------------------------------------------------------------------------------
local bitmap_font_1 = {
[10] = {
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0},
["."] = {
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,1,0},
[1] = {
0,0,0,1,
0,0,0,1,
0,0,0,1,
0,0,0,1,
0,0,0,1,
0,0,0,1,
0,0,0,1},
[2] = {
1,1,1,1,
0,0,0,1,
0,0,0,1,
1,1,1,1,
1,0,0,0,
1,0,0,0,
1,1,1,1},
[3] = {
1,1,1,1,
0,0,0,1,
0,0,0,1,
1,1,1,1,
0,0,0,1,
0,0,0,1,
1,1,1,1},
[4] = {
1,0,0,1,
1,0,0,1,
1,0,0,1,
1,1,1,1,
0,0,0,1,
0,0,0,1,
0,0,0,1},
[5] = {
1,1,1,1,
1,0,0,0,
1,0,0,0,
1,1,1,1,
0,0,0,1,
0,0,0,1,
1,1,1,1},
[6] = {
1,1,1,1,
1,0,0,0,
1,0,0,0,
1,1,1,1,
1,0,0,1,
1,0,0,1,
1,1,1,1},
[7] = {
1,1,1,1,
0,0,0,1,
0,0,0,1,
0,0,0,1,
0,0,0,1,
0,0,0,1,
0,0,0,1},
[8] = {
1,1,1,1,
1,0,0,1,
1,0,0,1,
1,1,1,1,
1,0,0,1,
1,0,0,1,
1,1,1,1},
[9] = {
1,1,1,1,
1,0,0,1,
1,0,0,1,
1,1,1,1,
0,0,0,1,
0,0,0,1,
0,0,0,1},
[0] = {
1,1,1,1,
1,0,0,1,
1,0,0,1,
1,0,0,1,
1,0,0,1,
1,0,0,1,
1,1,1,1},
}
--------------------------------------------------------------------------------
-- Draw bitmap digit
function Metrostroi.DrawClockDigit(cx,cy,scale,digit)
local bitmap = bitmap_font_1[digit]
if not bitmap then return end
local w=12*scale
local p=8*scale
for i=1,4*7 do
local x = (i-1)%4
local y = math.floor((i-1)/4)
if bitmap[i] == 1 then
for z=1,6,1 do
surface.SetDrawColor(Color(255,60,0,math.max(0,30-1*z*z)))
surface.DrawRect(cx+x*w-z*scale, cy+y*w-z*scale, p+2*z*scale, p+2*z*scale)
end
surface.SetDrawColor(Color(255,240,0,255))
surface.DrawRect(cx+x*w, cy+y*w, p, p)
end
end
end
function Metrostroi.PositionFromPanel(panel,button_id_or_vec,z,x,y,train)
local self = train or ENT
local panel = self.ButtonMap[panel]
if not panel then return Vector(0,0,0) end
if not panel.buttons then return Vector(0,0,0) end
-- Find button or read position
local vec
if type(button_id_or_vec) == "string" then
local button
for k,v in pairs(panel.buttons) do
if v.ID == button_id_or_vec then
button = v
break
end
end
vec = Vector(button.x + (button.radius and 0 or (button.w or 0)/2)+(x or 0),button.y + (button.radius and 0 or (button.h or 0)/2)+(y or 0),z or 0)
else
vec = button_id_or_vec
end
-- Convert to global coords
vec.y = -vec.y
vec:Rotate(panel.ang)
return panel.pos + vec * panel.scale
end
function Metrostroi.AngleFromPanel(panel,ang,train)
local self = train or ENT
local panel = self.ButtonMap[panel]
if not panel then return Vector(0,0,0) end
local true_ang = panel.ang + Angle(0,0,0)
if type(ang) == "Angle" then
true_ang:RotateAroundAxis(panel.ang:Forward(),ang.pitch)
true_ang:RotateAroundAxis(panel.ang:Right(),ang.yaw)
true_ang:RotateAroundAxis(panel.ang:Up(),ang.roll)
else
true_ang:RotateAroundAxis(panel.ang:Up(),ang or -90)
end
return true_ang
end
Metrostroi.PrecacheModels = Metrostroi.PrecacheModels or {}
function Metrostroi.GenerateClientProps()
local self = ENT
if not self.AutoAnimNames then self.AutoAnimNames = {} end
local ret = "self.table = {\n"
--local reti = 0
for id, panel in pairs(self.ButtonMap) do
if not panel.buttons then continue end
if not panel.props then panel.props = {} end
for name, buttons in pairs(panel.buttons) do
--if reti > 8 then reti=0; ret=ret.."\n" end
if buttons.tooltipFunc then
local func = buttons.tooltipFunc
buttons.tooltipState = function(ent)
local str = func(ent)
if not str then return "" end
return "\n["..str:gsub("\n","]\n[").."]"
end
elseif buttons.varTooltip then
local states = buttons.states or {"Train.Buttons.Off","Train.Buttons.On"}
local count = (#states-1)
buttons.tooltipState = function(ent)
return Format("\n[%s]",Metrostroi.GetPhrase(states[math.floor(buttons.varTooltip(ent)*count+0.5)+1]):gsub("\n","]\n["))
end
elseif buttons.var then
local var = buttons.var
local st1,st2 = "Train.Buttons.Off","Train.Buttons.On"
if buttons.states then
st1 = buttons.states[1]
st2 = buttons.states[2]
end
buttons.tooltipState = function(ent)
return Format("\n[%s]",Metrostroi.GetPhrase(ent:GetPackedBool(var) and st2 or st1):gsub("\n","]\n["))
end
end
if buttons.model then
local config = buttons.model
local name = config.name or buttons.ID
if config.tooltipFunc then
local func = config.tooltipFunc
buttons.tooltipState = function(ent)
local str = func(ent)
if not str then return "" end
return "\n["..str:gsub("\n","]\n[").."]"
end
elseif config.varTooltip then
local states = config.states or {"Train.Buttons.Off","Train.Buttons.On"}
local count = (#states-1)
local func = config.getfunc
if config.varTooltip == true and func then
buttons.tooltipState = function(ent)
return Format("\n[%s]",Metrostroi.GetPhrase(states[math.floor(config.func(ent)*count+0.5)+1]):gsub("\n","]\n["))
end
elseif config.varTooltip ~= true then
buttons.tooltipState = function(ent)
return Format("\n[%s]",Metrostroi.GetPhrase(states[math.floor(config.varTooltip(ent)*count+0.5)+1]):gsub("\n","]\n["))
end
end
elseif (config.var and (not config.noTooltip and not buttons.ID:find("Set") or config.noTooltip==false)) then
local var = config.var
local st1,st2 = "Train.Buttons.Off","Train.Buttons.On"
if config.states then
st1 = config.states[1]
st2 = config.states[2]
end
buttons.tooltipState = function(ent)
return Format("\n[%s]",Metrostroi.GetPhrase(ent:GetPackedBool(var) and st2 or st1))
end
end
if config.model then
table.insert(panel.props,name)
self.ClientProps[name] = {
model = config.model or "models/metrostroi/81-717/button07.mdl",
pos = Metrostroi.PositionFromPanel(id,config.pos or buttons.ID,(config.z or 0.2),(config.x or 0),(config.y or 0)),
ang = Metrostroi.AngleFromPanel(id,config.ang),
color = config.color,
colora = config.colora,
skin = config.skin or 0,
config = config,
cabin = config.cabin,
hide = panel.hide or config.hide,
hideseat = panel.hideseat or config.hideseat,
bscale = config.bscale,
scale = config.scale,
}
--[[if config.varTooltip then
local states = config.states or {"Train.Buttons.On","Train.Buttons.Off"}
local count = (#states-1)
buttons.tooltipState = function(ent)
local text = "\n["
for i,t in ipairs(states) do
if i == #states then
text = text..Metrostroi.GetPhrase(t)
else
text = text..Metrostroi.GetPhrase(t).."|"
end
end
text = text.."]"
return text,states[math.floor(config.varTooltip(ent)+0.5)*count+1]
end
elseif (config.var and not config.noTooltip) then
local var = config.var
local st1,st2 = "Train.Buttons.On","Train.Buttons.Off"
if config.states then
st1 = config.states[1]
st2 = config.states[2]
end
buttons.tooltipState = function(ent)
return Format("\n[%s|%s]",Metrostroi.GetPhrase(st1),Metrostroi.GetPhrase(st2)),ent:GetPackedBool(var) and st1 or st2
end
end]]
if config.var then
local var = config.var
local vmin, vmax = config.vmin or 0,config.vmax or 1
local min,max = config.min or 0,config.max or 1
local speed,damping,stickyness = config.speed or 16,config.damping or false,config.stickyness or nil
local func = config.getfunc
local i
if func then
if config.disable then
i = table.insert(self.AutoAnims, function(ent)
ent:Animate(name,func(ent,vmin,vmax,var),min,max,speed,damping,stickyness)
ent:HideButton(config.disable,ent:GetPackedBool(var))
end)
elseif config.disableinv then
i = table.insert(self.AutoAnims, function(ent)
ent:Animate(name,func(ent,vmin,vmax,var),min,max,speed,damping,stickyness)
ent:HideButton(config.disableinv,not ent:GetPackedBool(var))
end)
elseif config.disableoff and config.disableon then
i = table.insert(self.AutoAnims, function(ent)
ent:Animate(name,func(ent,vmin,vmax,var),min,max,speed,damping,stickyness)
ent:HideButton(config.disableoff,ent:GetPackedBool(var))
ent:HideButton(config.disableon,not ent:GetPackedBool(var))
end)
elseif config.disablevar then
i = table.insert(self.AutoAnims, function(ent)
ent:HideButton(name,ent:GetPackedBool(config.disablevar))
ent:Animate(name,func(ent,vmin,vmax,var),min,max,speed,damping,stickyness)
end)
else
i = table.insert(self.AutoAnims, function(ent) ent:Animate(name,func(ent,vmin,vmax),min,max,speed,damping,stickyness) end)
end
else
if config.disable then
i = table.insert(self.AutoAnims, function(ent)
ent:Animate(name,ent:GetPackedBool(var) and vmax or vmin,min,max,speed,damping,stickyness)
ent:HideButton(config.disable,ent:GetPackedBool(var))
end)
elseif config.disableinv then
i = table.insert(self.AutoAnims, function(ent)
ent:Animate(name,ent:GetPackedBool(var) and vmax or vmin,min,max,speed,damping,stickyness)
ent:HideButton(config.disableinv,not ent:GetPackedBool(var))
end)
elseif config.disableoff and config.disableon then
i = table.insert(self.AutoAnims, function(ent)
ent:Animate(name,ent:GetPackedBool(var) and vmax or vmin,min,max,speed,damping,stickyness)
ent:HideButton(config.disableoff,ent:GetPackedBool(var))
ent:HideButton(config.disableon,not ent:GetPackedBool(var))
end)
elseif config.disablevar then
i = table.insert(self.AutoAnims, function(ent)
ent:HideButton(name,ent:GetPackedBool(config.disablevar))
ent:Animate(name,ent:GetPackedBool(var) and vmax or vmin,min,max,speed,damping,stickyness)
end)
else
i = table.insert(self.AutoAnims, function(ent) ent:Animate(name,ent:GetPackedBool(var) and vmax or vmin,min,max,speed,damping,stickyness) end)
end
end
self.AutoAnimNames[i] = name
end
end
if config.sound or config.sndvol and config.var then
local id = config.sound or config.var
local sndid = config.sndid or buttons.ID
local vol,pitch,min,max = config.sndvol, config.sndpitch,config.sndmin,config.sndmax
local func,snd = config.getfunc, config.snd
local vmin, vmax = config.vmin or 0,config.vmax or 1
local var = config.var
local ang = config.sndang
--if func then
--self.ClientSounds[id] = {sndid,function(ent,var) return snd(func(ent,vmin,vmax),var) end,vol or 1,pitch or 1,min or 100,max or 1000,ang or Angle(0,0,0)}
--else
if not self.ClientSounds[id] then self.ClientSounds[id] = {} end
table.insert(self.ClientSounds[id],{sndid,function(ent,var) return snd(var > 0,var) end,vol or 1,pitch or 1,min or 100,max or 1000,ang or Angle(0,0,0)})
--end
end
if config.plomb then
local pconfig = config.plomb
local pname = name.."_pl"
if pconfig.model then
table.insert(panel.props,pname)
self.ClientProps[pname] = {
model = pconfig.model,
pos = Metrostroi.PositionFromPanel(id,config.pos or buttons.ID,(config.z or 0.2)+(pconfig.z or 0.2),(config.x or 0)+(pconfig.x or 0),(config.y or 0)+(pconfig.y or 0)),
ang = Metrostroi.AngleFromPanel(id,pconfig.ang or config.ang),
color = pconfig.color or pconfig.color,
skin = pconfig.skin or config.skin or 0,
config = pconfig,
cabin = pconfig.cabin,
hide = panel.hide or config.hide,
hideseat = panel.hideseat or config.hideseat,
bscale = pconfig.bscale or config.bscale,
scale = pconfig.scale or config.scale,
}
end
if pconfig.var then
local var = pconfig.var
if pconfig.model then
local i = table.insert(self.AutoAnims, function(ent)
ent:SetCSBodygroup(pname,1,ent:GetPackedBool(var) and 0 or 1)
end)
self.AutoAnimNames[i] = pname
end
local id,tooltip = buttons.ID,buttons.tooltip
local pid,ptooltip = pconfig.ID,pconfig.tooltip
buttons.plombed = function(ent)
if ent:GetPackedBool(var) then
return Format("%s\n%s",buttons.tooltip,Metrostroi.GetPhrase("Train.Buttons.Sealed") or "Plombed"),pid,Color(255,150,150),true
else
return buttons.tooltip,id,false
end
end
end
end
if config.lamp then
local lconfig = config.lamp
local lname = name.."_lamp"
table.insert(panel.props,lname)
self.ClientProps[lname] = {
model = lconfig.model or "models/metrostroi/81-717/button07.mdl",
pos = Metrostroi.PositionFromPanel(id,config.pos or buttons.ID,(config.z or 0.2)+(lconfig.z or 0.2),(config.x or 0)+(lconfig.x or 0),(config.y or 0)+(lconfig.y or 0)),
ang = Metrostroi.AngleFromPanel(id,lconfig.ang or config.ang),
color = lconfig.color or config.color,
skin = lconfig.skin or config.skin or 0,
config = lconfig,
cabin = lconfig.cabin,
igrorepanel = true,
hide = panel.hide or config.hide,
hideseat = panel.hideseat or config.hideseat,
bscale = lconfig.bscale or config.bscale,
scale = lconfig.scale or config.scale,
}
if lconfig.anim then
local i = table.insert(self.AutoAnims, function(ent)
ent:AnimateFrom(lname,name)
end)
self.AutoAnimNames[i] = lname
end
if lconfig.lcolor then
self.Lights[lname] = { "headlight",
Metrostroi.PositionFromPanel(id,config.pos or buttons.ID,(config.z or 0.2)+(lconfig.z or 0.2)+(lconfig.lz or 0.2),(config.x or 0)+(lconfig.x or 0)+(lconfig.lx or 0),(config.y or 0)+(lconfig.y or 0)+(lconfig.ly or 0)),
Metrostroi.AngleFromPanel(id,lconfig.lang or lconfig.ang or config.ang)+Angle(90,0,0),
lconfig.lcolor,farz = lconfig.lfar or 8,nearz = lconfig.lnear or 1,shadows = lconfig.lshadows or 1,brightness = lconfig.lbright or 1,fov = lconfig.lfov,texture=lconfig.ltex or "effects/flashlight/soft",panellight=true,
hidden = lname,
}
--[[self.ClientProps[lname.."TEST"] = {
model = "models/metrostroi_train/81-703/cabin_cran_334.mdl",
pos = Metrostroi.PositionFromPanel(id,config.pos or buttons.ID,(config.z or 0.2)+(lconfig.z or 0.2)+(lconfig.lz or 0.2),(config.x or 0)+(lconfig.x or 0)+(lconfig.lx or 0),(config.y or 0)+(lconfig.y or 0)+(lconfig.ly or 0)),
ang = Metrostroi.AngleFromPanel(id,lconfig.lang or lconfig.ang or config.ang)+Angle(-180,180,0),
scale=0.1,
}]]
--[[table.insert(self.AutoAnims, function(ent)
ent:AnimateFrom(lname,name)
end)]]
end
if lconfig.var then
--ret=ret.."\""..lconfig.var.."\","
--reti = reti + 1
local var,animvar = lconfig.var,lname.."_anim"
local min,max = lconfig.min or 0,lconfig.max or 1
local speed = lconfig.speed or 10
local func = lconfig.getfunc
local light = lconfig.lcolor
if func then
table.insert(self.AutoAnims, function(ent)
local val = ent:Animate(animvar,func(ent,min,max,var),0,1,speed,false)
ent:ShowHideSmooth(lname,val)
if light then ent:SetLightPower(lname,val>0,val) end
end)
else
local i = table.insert(self.AutoAnims, function(ent)
--print(lname,ent.SmoothHide[lname])
local val = ent:Animate(animvar,ent:GetPackedBool(var) and max or min,0,1,speed,false)
ent:ShowHideSmooth(lname,val)
if light then ent:SetLightPower(lname,val>0,val) end
end)
end
end
end
if config.lamps then
for k,lconfig in ipairs(config.lamps) do
local lname = name.."_lamp"..k
table.insert(panel.props,lname)
self.ClientProps[lname] = {
model = lconfig.model or "models/metrostroi/81-717/button07.mdl",
pos = Metrostroi.PositionFromPanel(id,config.pos or buttons.ID,(config.z or 0.2)+(lconfig.z or 0.2),(config.x or 0)+(lconfig.x or 0),(config.y or 0)+(lconfig.y or 0)),
ang = Metrostroi.AngleFromPanel(id,lconfig.ang or config.ang),
color = lconfig.color or config.color,
skin = lconfig.skin or config.skin or 0,
config = lconfig,
cabin = lconfig.cabin,
igrorepanel = true,
hide = panel.hide or config.hide,
hideseat = panel.hideseat or config.hideseat,
bscale = lconfig.bscale or config.bscale,
scale = lconfig.scale or config.scale,
}
if lconfig.var then
--ret=ret.."\""..lconfig.var.."\","
--reti = reti + 1
local var,animvar = lconfig.var,lname.."_anim"
local min,max = lconfig.min or 0,lconfig.max or 1
local speed = lconfig.speed or 10
local func = lconfig.getfunc
if func then
table.insert(self.AutoAnims, function(ent)
local val = ent:Animate(animvar,func(ent,min,max,var),0,1,speed,false)
ent:ShowHideSmooth(lname,val)
end)
else
table.insert(self.AutoAnims, function(ent)
--print(lname,ent.SmoothHide[lname])
local val = ent:Animate(animvar,ent:GetPackedBool(var) and max or min,0,1,speed,false)
ent:ShowHideSmooth(lname,val)
end)
end
end
end
end
if config.sprite then
local sconfig = config.sprite
local hideName = sconfig.hidden or config.lamp and name.."_lamp" or name
self.Lights[sconfig.lamp or name] = { sconfig.glow and "glow" or "light",
Metrostroi.PositionFromPanel(id,config.pos or buttons.ID,(config.z or 0.5)+(sconfig.z or 0.2),(config.x or 0)+(sconfig.x or 0),(config.y or 0)+(sconfig.y or 0)),
Metrostroi.AngleFromPanel(id, sconfig.ang or config.ang)+Angle(90,0,0),
sconfig.color or sconfig.color,
brightness = sconfig.bright,texture=sconfig.texture or "sprites/light_glow02",scale=sconfig.scale or 0.02,vscale=sconfig.vscale,
size = sconfig.size,
hidden = hideName,
aa = sconfig.aa,panel = sconfig.panel ~= false,
}
local i
if sconfig.getfunc then
local func = sconfig.getfunc
i = table.insert(self.AutoAnims, function(ent)
local val = func(ent)
ent:SetLightPower(name,not ent.Hidden[hideName] and val>0,val)
end)
elseif sconfig.var then
--ret=ret.."\""..lconfig.var.."\","
--reti = reti + 1
local var,animvar = sconfig.var,name.."_sanim"
local speed = sconfig.speed or 10
i = table.insert(self.AutoAnims, function(ent)
local val = ent:Animate(animvar,ent:GetPackedBool(var) and 1 or 0,0,1,speed,false)
ent:SetLightPower(name,val>0,val)
end)
elseif sconfig.lamp then
local lightName = sconfig.lamp
i = table.insert(self.AutoAnims, function(ent)
local val = ent.Anims[lightName] and ent.Anims[lightName].value or 0
ent:SetLightPower(lightName,val>0,val)
end)
elseif config.lamp and config.lamp.var then
local lname = name.."_lamp"
local lightName = lname.."_anim"
i = table.insert(self.AutoAnims, function(ent)
local val = ent.Anims[lightName] and ent.Anims[lightName].value or 0
ent:SetLightPower(name,val>0,val)
end)
end
if not i then
ErrorNoHalt("Bad sprite "..name.."/"..hideName..", no controlable function...\n")
else
self.AutoAnimNames[i] = hideName
end
end
if config.labels then
for k,aconfig in ipairs(config.labels) do
local aname = name.."_label"..k
table.insert(panel.props,aname)
self.ClientProps[aname] = {
model = aconfig.model or "models/metrostroi/81-717/button07.mdl",
pos = Metrostroi.PositionFromPanel(id,config.pos or buttons.ID,(config.z or 0.2)+(aconfig.z or 0.2),(config.x or 0)+(aconfig.x or 0),(config.y or 0)+(aconfig.y or 0)),
ang = Metrostroi.AngleFromPanel(id,aconfig.ang or config.ang),
color = aconfig.color or config.color,
colora = aconfig.colora or config.colora,
skin = aconfig.skin or config.skin or 0,
config = aconfig,
cabin = aconfig.cabin,
igrorepanel = true,
hide = panel.hide or config.hide,
hideseat = panel.hideseat or config.hideseat,
bscale = aconfig.bscale or config.bscale,
scale = aconfig.scale or config.scale,
}
end
end
buttons.model = nil
end
end
end
for k,v in pairs(self.ClientProps) do
if not v.model then continue end
Metrostroi.PrecacheModels[v.model] = true
end
for k,v in pairs(self.Lights or {}) do
if not v.hidden then continue end
local cP = self.ClientProps[v.hidden]
if not cP then ErrorNoHalt("No clientProp "..v.hidden.." in entity "..self.Folder.."\n") continue end
if not cP.lamps then cP.lamps = {} end
table.insert(cP.lamps,k)
end
--ret = ret.."\n}"
--SetClipboardText(ret)
end
--[[
timer.Simple(1,function()
for k,ent in pairs(Metrostroi.PrecacheModels) do
if ent==true or not IsValid(ent) then
local model = ClientsideModel(k)
model:SetPos(LocalPlayer():GetPos())
Metrostroi.PrecacheModels[k] = model
end
end
timer.Simple(2,function()
for k,ent in pairs(Metrostroi.PrecacheModels) do
if IsValid(ent) then
SafeRemoveEntity(ent)
end
end
end)
end)]]
function Metrostroi.InsertHide(panel,prop_name)
local self = ENT
if self.ButtonMap[panel] then
if not self.ButtonMap[panel].props then self.ButtonMap[panel].props = {} end
table.insert(self.ButtonMap[panel].props,prop_name)
end
end
--------------------------------------------------------------------------------
-- Training markers
--------------------------------------------------------------------------------
local prevV = 0
local A = 0
local D1true = 0
local D2true = 0
local prevTime
hook.Add("PostDrawOpaqueRenderables", "metrostroi-draw-stopmarker",function()
prevTime = prevTime or RealTime()
local dT = math.max(0.001,RealTime() - prevTime)
prevTime = RealTime()
-- Skip if disabled
if GetConVar("metrostroi_stop_helper"):GetInt() ~= 1 then return end
-- Get train
local train = LocalPlayer().InMetrostroiTrain
if not IsValid(train) then return end
-- Calculate acceleration
local V = train:GetNW2Float("V",train:GetVelocity():Length()*0.01905)*0.277778
local newA = (V - prevV)/dT
prevV = V
-- Calculate marker position
A = train:GetNW2Float("A",A + (newA - A)*1.0*dT)
local T1 = math.abs(V/(A+1e-8))
local T2 = math.abs(V/(1.2+1e-8))
local D1 = T1*V + (T1^2)*A/2
local D2 = T2*V + (T2^2)*A/2
-- Smooth out D
D1 = math.min(200,math.max(0,D1))*0.65
D2 = math.min(200,math.max(0,D2))*0.70
D1true = D1true + (D1 - D1true)*12.0*dT
D2true = D2true + (D2 - D2true)*12.0*dT
local offset1 = D1true/0.01905
local offset2 = D2true/0.01905
-- Draw marker
if A > -0.1 then return end
-- if D1 > 195 then return end
if D2 > 195 then return end
local base_pos1 = train:LocalToWorld(Vector(500+offset1,80,10))
cam.Start3D2D(base_pos1,train:LocalToWorldAngles(Angle(0,-90,90)),1.0)
surface.SetDrawColor(255,255,255)
surface.DrawRect(-1,-1,8*20+2,4+2)
for i=0,19 do
surface.SetDrawColor(240,200,40)
surface.DrawRect(8*i+0,0,4,4)
surface.SetDrawColor(0,0,0)
surface.DrawRect(8*i+4,0,4,4)
end
surface.SetDrawColor(255,255,255)
surface.DrawRect(-1,-96,2,192)
surface.DrawRect(8*20,-96,2,192)
-- surface.SetTextColor(255,255,255)
-- surface.SetFont("Trebuchet24")
-- surface.SetTextPos(64-128,-30)
-- surface.DrawText(Format("%.1f m %.1f m/s %.1f m/s2",D,V,A))
-- surface.SetTextPos(64,-30)
-- surface.DrawText(Format("%.1f m %.0f sec",D,T))
cam.End3D2D()
local base_pos2 = train:LocalToWorld(Vector(500+offset2,80,10))
cam.Start3D2D(base_pos2,train:LocalToWorldAngles(Angle(0,-90,90)),1.0)
surface.SetDrawColor(240,40,40)
surface.DrawRect(-1,-1,8*20+2,4+2)
for i=0,19 do
surface.SetDrawColor(0,0,0)
surface.DrawRect(8*i+0,0,4,4)
surface.SetDrawColor(240,40,40)
surface.DrawRect(8*i+4,0,4,4)
end
surface.SetDrawColor(240,40,40)
surface.DrawRect(-1,-1+110,8*20+2,16+2)
for i=0,19 do
surface.SetDrawColor(0,0,0)
surface.DrawRect(8*i+0,110,4,16)
surface.SetDrawColor(240,40,40)
surface.DrawRect(8*i+4,110,4,16)
end
surface.SetDrawColor(240,40,40)
surface.DrawRect(-6,-96,6,192)
surface.DrawRect(8*20,-96,4,192)
cam.End3D2D()
end)
--------------------------------------------------------------------------------
-- Fix for gm_metrostroi 3D sky
--------------------------------------------------------------------------------
local player_state = {}
if string.sub(game.GetMap(),1,13) == "gm_metrostroi" then
timer.Create("Metrostroi_3DSkyFix",1.0,0,function()
local player = LocalPlayer()
if not IsValid(player) then return end
RunConsoleCommand("r_3dsky", (player:GetPos().z < -1024) and "0" or "1")
end)
end
timer.Simple(0,function()
net.Start("metrostroi_cam_update") net.SendToServer()
end)
net.Receive("metrostroi_cam_update",function()
local ent = Entity(net.ReadUInt(16))
Metrostroi.RTCamera = ent
end)
local CamRT = surface.GetTextureID( "pp/rt" )
local CamWork = GetConVar("metrostroi_drawcams")
Metrostroi.CamTimers = Metrostroi.CamTimers or {}
Metrostroi.CamQueue = Metrostroi.CamQueue or {}
function Metrostroi.RenderCamOnRT(train,cpos,name,time,RT,post,pos,ang,x,y,scale,xmin,ymin)
if not CamWork then CamWork = GetConVar("metrostroi_drawcams") return end
if not CamWork:GetBool() then return end
name = train:EntIndex()..name
--print(name,Metrostroi.CamQueue[name])
if (not Metrostroi.CamTimers[name] or RealTime()-Metrostroi.CamTimers[name] > time) and not Metrostroi.CamQueue[name] then
Metrostroi.CamQueue[name] = table.insert(Metrostroi.CamQueue,{train,cpos,name,time,RT,post,pos,ang,x,y,scale,xmin,ymin})
end
end
function Metrostroi.SetCamPosAng(pos,ang)
if IsValid(Metrostroi.RTCamera) then
Metrostroi.RTCamera:SetPos(pos)
Metrostroi.RTCamera:SetAngles(ang)
end
end
hook.Add("Think","metrostroi_camera_move",function()
if IsValid(Metrostroi.RTCamera) then
Metrostroi.RTCamera:SetPos(Vector(0,0,-2^16))
Metrostroi.RTCamera:SetAngles(Angle(90,0,0))
end
if Metrostroi.RenderCam and Metrostroi.RenderedCam ~= RealTime() then
local camera = Metrostroi.RenderCam
Metrostroi.RenderCam = nil
if IsValid(camera[1]) then
local distance = camera[1]:LocalToWorld(camera[2]):Distance(LocalPlayer():GetPos())
if distance > 256 then return end
local x,y = camera[9],camera[10]
local scale = camera[11] or 1
local xmin,ymin = camera[12] or 0,camera[13] or 0
render.PushRenderTarget(camera[5],0,0,x, y)
render.Clear(0, 0, 0, 0)
cam.Start2D()
surface.SetTexture( CamRT )
surface.SetDrawColor( 255, 255, 255, 255 )
surface.DrawTexturedRectRotated((x/2-xmin)*scale,(y/2-ymin)*scale,x*scale,y*scale,0)
cam.End2D()
render.PopRenderTarget()
else
end
end
if #Metrostroi.CamQueue > 0 and not Metrostroi.RenderCam then
local cam = table.remove(Metrostroi.CamQueue,1)
Metrostroi.CamQueue[cam[3]] = nil
local name,time,post,pos,ang = cam[3],cam[4],cam[6],cam[7],cam[8]
if IsValid(post) then
debugoverlay.Sphere(post:LocalToWorld(pos),1,time,Color( 150, 105, 200 ),true)
debugoverlay.Text(post:LocalToWorld(pos),name,time,Color( 150, 105, 200 ),true)
debugoverlay.Line(post:LocalToWorld(pos),post:LocalToWorld(pos)+post:LocalToWorldAngles(ang):Forward()*25,time,Color( 150, 105, 200 ),true)
Metrostroi.RenderCam = cam
Metrostroi.SetCamPosAng(post:LocalToWorld(cam[7]),post:LocalToWorldAngles(cam[8]))
Metrostroi.CamTimers[cam[3]] = RealTime()
end
end
end)
local function rect_ol(x,y,w,h,c)
Metrostroi.DrawLine(x-1,y,x+w,y,c)
Metrostroi.DrawLine(x+w,y,x+w,y+h,c)
Metrostroi.DrawLine(x,y+h,x+w,y+h,c)
Metrostroi.DrawLine(x,y,x,y+h,c)
end
function Metrostroi.DrawLine(x1,y1,x2,y2,col,sz)
surface.SetDrawColor(col)
if x1 == x2 then
-- vertical line
local wid = (sz or 1) / 2
surface.DrawRect(x1-wid, y1, wid*2, y2-y1)
elseif y1 == y2 then
-- horizontal line
local wid = (sz or 1) / 2
surface.DrawRect(x1, y1-wid, x2-x1, wid*2)
else
-- other lines
local x3 = (x1 + x2) / 2
local y3 = (y1 + y2) / 2
local wx = math.sqrt((x2-x1) ^ 2 + (y2-y1) ^ 2)
local angle = math.deg(math.atan2(y1-y2, x2-x1))
draw.NoTexture()
surface.DrawTexturedRectRotated(x3, y3, wx, (sz or 1), angle)
end
end
function Metrostroi.DrawRectOutline(x,y,w,h,col,sz)
local wid = sz or 1
if wid < 0 then
for i=0, wid+1, -1 do
rect_ol(x+i, y+i, w-2*i, h-2*i, col)
end
elseif wid > 0 then
for i=0, wid-1 do
rect_ol(x+i, y+i, w-2*i, h-2*i, col)
end
end
end
function Metrostroi.DrawRectOL(x,y,w,h,col,sz,col1)
local wid = sz or 1
if wid < 0 then
for i=0, wid+1, -1 do
rect_ol(x+i, y+i, w-2*i, h-2*i, col)
end
elseif wid > 0 then
for i=0, wid-1 do
rect_ol(x+i, y+i, w-2*i, h-2*i, col)
end
end
surface.SetDrawColor(col1)
surface.DrawRect(x+math.max(0,sz-1),y+math.max(0,sz-1),w-math.max(0,(sz-0.5)*2),h-math.max(0,(sz-0.5)*1.5))
end
function Metrostroi.DrawTextRect(x,y,w,h,col,mat)
surface.SetDrawColor(col)
surface.SetMaterial(mat)
surface.DrawTexturedRect(x,y,w,h)
end
function Metrostroi.DrawTextRectOL(x,y,w,h,col,mat,sz,col1)
local wid = sz or 1
if wid < 0 then
for i=0, wid+1, -1 do
rect_ol(x+i, y+i, w-2*i, h-2*i, col1)
end
elseif wid > 0 then
for i=0, wid-1 do
rect_ol(x+i, y+i, w-2*i, h-2*i, col1)
end
end
surface.SetDrawColor(col)
surface.DrawRect(x+math.max(0,sz-1),y+math.max(0,sz-1),w-math.max(0,(sz-0.5)*2),h-math.max(0,(sz-0.5)*1.5))
surface.SetDrawColor(Color(col.r - 40,col.g - 40,col.b - 40))
surface.SetMaterial(mat)
surface.DrawTexturedRect(x+math.max(0,sz-1),y+math.max(0,sz-1),w-math.max(0,(sz-0.5)*2),h-math.max(0,(sz-0.5)*2))
end
local function recurePrecache(sound)
if type(sound) == "table" then
for k,snd in pairs(sound) do recurePrecache(snd) end
elseif type(sound) == "string" then
util.PrecacheSound(sound)
end
end
local function util_PrecacheSound(dir)
local files,dirs = file.Find(dir.."/*","GAME")
for _, fdir in pairs(dirs) do
util_PrecacheSound(dir.."/"..fdir)
end
for _,v in pairs(files) do
util.PrecacheSound(dir.."/"..v)
end
end
--util_PrecacheSound("sound/subway_trains")
matproxy.Add{
name = "TrainBodyColor",
init = function( self, mat, values )
-- Store the name of the variable we want to set
if values then self._MATresultVarC = values.resultvar end
end,
bind = function( self, mat, ent )
if ( self._MATresultVarC and ent.GetBodyColor ) then
mat:SetVector( self._MATresultVarC, ent:GetBodyColor() )
end
end
}
matproxy.Add{
name = "TrainBodyDecal",
init = function( self, mat, values )
-- Store the name of the variable we want to set
if values then self._MATresultVarD = values.resultvar end
end,
bind = function( self, mat, ent )
if ( self._MATresultVarD and ent.GetDirtLevel ) then
mat:SetFloat( self._MATresultVarD, ent:GetDirtLevel() )
end
end
}
Metrostroi.RenderTargetNames = {
"ASNP","IGLA","PUAV","PAM","Vityaz","Tickers","Sarmat","Cam1","Cam2","Cam3","Cam4",
}
function Metrostroi.AddCaptureRTName(name)
if not table.HasValue(Metrostroi.RenderTargetNames,name) then
table.insert(Metrostroi.RenderTargetNames,name)
end
end
concommand.Add("metrostroi_capture_rt",function(_,_,args)
local RTs = #args > 0 and args or Metrostroi.RenderTargetNames
local train = LocalPlayer().InMetrostroiTrain
if not IsValid(train) then return end
local oldRt = render.GetRenderTarget() -- we'll save the old screen and draw on a new one!
file.CreateDir("rt_captures")
for i,v in ipairs(RTs) do
local RT = train[v]
if RT and type(RT) == "ITexture" then
render.SetRenderTarget( train[v] )
local data = render.Capture( { format = "png", quality = 100, x = 0, y = 0, h = RT:Height(), w = RT:Width() } )
local pictureFile = file.Open("rt_captures/"..train:EntIndex().." "..v.." "..os.date("!%d%m%y_%H%M%S",os.time())..".png", "wb", "DATA" )
pictureFile:Write( data )
pictureFile:Close()
end
end
render.SetRenderTarget( oldRt )
end)
--------------------------------------------------------------------------------
-- Player meta table magic
-- Author: HunterNL
--------------------------------------------------------------------------------
local Player = FindMetaTable("Player")
function Player:GetTrain()
local seat = self:GetVehicle()
if IsValid(seat) then
return seat:GetNW2Entity("TrainEntity"),seat
end
end
hook.Add("Think","MetrostroiGetTrain",function()
local ply = LocalPlayer()
local train = ply:GetTrain()
if IsValid(train) then
ply.InMetrostroiTrain = train
else
ply.InMetrostroiTrain = false
end
end)
RunConsoleCommand("r_rootlod",0) -- Train models only visible with High model quality
local matSprite = {
["$basetexture"] = "",
["$spriteorientation"] = "vp_parallel",
["$spriteorigin"] = "[ 0.50 0.50 ]",
["$illumfactor"] = 7,
["$spriterendermode"] = 3,
}
local matUnlit = {
["$basetexture"] = "",
["$translucent"]= 1,
["$additive"] = 1,
["$vertexcolor"] = 1,
--["$vertexalpha"] = 1,
}
Metrostroi.SpriteCache1 = Metrostroi.SpriteCache1 or {}
Metrostroi.SpriteCache2 = Metrostroi.SpriteCache2 or {}
function Metrostroi.MakeSpriteTexture(path,isSprite)
if isSprite then
if Metrostroi.SpriteCache1[path] then return Metrostroi.SpriteCache1[path] end
matSprite["$basetexture"] = path
Metrostroi.SpriteCache1[path] = CreateMaterial(path..":sprite","Sprite",matSprite)
return Metrostroi.SpriteCache1[path]
else
if Metrostroi.SpriteCache1[path] then return Metrostroi.SpriteCache1[path] end
matUnlit["$basetexture"] = path
Metrostroi.SpriteCache2[path] = CreateMaterial(path..":spriteug","UnlitGeneric",matUnlit)
return Metrostroi.SpriteCache2[path]
end
end