From 44f0e81756a292c6b7b3a0460f9da77c1be50b27 Mon Sep 17 00:00:00 2001 From: Zenkaku Hiragana Date: Sat, 11 Jan 2025 21:01:24 +0900 Subject: [PATCH] =?UTF-8?q?=F0=9F=8E=A8=20style:=20Eliminating=20TAB=20cha?= =?UTF-8?q?racters?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + addon.json | 17 +- lua/autorun/client/cl_decentvehicle.lua | 476 ++--- lua/autorun/client/cl_decentvehicle.taxi.lua | 126 +- lua/autorun/decentvehicle.lua | 290 +-- lua/autorun/server/sv_decentvehicle.lua | 1076 +++++----- lua/autorun/server/sv_decentvehicle_taxi.lua | 332 +-- lua/decentvehicle/base/en.lua | 194 +- lua/decentvehicle/base/ja.lua | 194 +- lua/decentvehicle/base/ru.lua | 30 +- lua/decentvehicle/npc_decentvehicle/en.lua | 2 +- lua/decentvehicle/npc_dvtaxi/en.lua | 32 +- lua/decentvehicle/npc_dvtaxi/ja.lua | 32 +- lua/decentvehicle/npc_dvtaxi/ru.lua | 32 +- lua/entities/ent_dv_traffic_light/cl_init.lua | 92 +- lua/entities/ent_dv_traffic_light/init.lua | 66 +- lua/entities/ent_dv_traffic_light/shared.lua | 20 +- lua/entities/ent_dvtaxi_station.lua | 65 +- lua/entities/env_dv_save.lua | 6 +- lua/entities/gmod_wire_dvmanager.lua | 160 +- lua/entities/npc_decentvehicle/api.lua | 942 ++++----- lua/entities/npc_decentvehicle/cl_init.lua | 20 +- lua/entities/npc_decentvehicle/init.lua | 1856 ++++++++--------- lua/entities/npc_decentvehicle/playermeta.lua | 234 +-- lua/entities/npc_decentvehicle/shared.lua | 76 +- lua/entities/npc_dvpolice.lua | 576 ++--- lua/entities/npc_dvtaxi.lua | 112 +- lua/entities/npc_learningvehicle.lua | 22 +- lua/weapons/gmod_tool/stools/dv_route.lua | 594 +++--- lua/wire/stools/dv_wiremanager.lua | 8 +- .../ent_dvtaxi_station/screen.vmt | 40 +- .../decentvehicle/ent_dvtaxi_station/skin.vmt | 40 +- materials/decentvehicle/trafficlight/body.vmt | 40 +- materials/decentvehicle/trafficlight/lg.vmt | 40 +- .../decentvehicle/trafficlight/lightg.vmt | 50 +- .../decentvehicle/trafficlight/lightr.vmt | 52 +- .../decentvehicle/trafficlight/lighty.vmt | 50 +- materials/decentvehicle/trafficlight/lr.vmt | 40 +- materials/decentvehicle/trafficlight/ly.vmt | 40 +- .../vgui/entities/ent_dv_traffic_light.vmt | 8 +- .../vgui/entities/ent_dvtaxi_station.vmt | 8 +- materials/vgui/entities/npc_decentvehicle.vmt | 8 +- materials/vgui/entities/npc_dvpolice.vmt | 8 +- materials/vgui/entities/npc_dvtaxi.vmt | 8 +- .../vgui/entities/npc_learningvehicle.vmt | 8 +- 45 files changed, 4062 insertions(+), 4061 deletions(-) diff --git a/README.md b/README.md index 82bb627..d7b8b6c 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,3 @@ # DecentVehicle + An automatically driving system for Garry's Mod. diff --git a/addon.json b/addon.json index a9470fc..c28203a 100644 --- a/addon.json +++ b/addon.json @@ -1,11 +1,10 @@ { - "title" : "[DV] Decent Vehicle - Basic AI", - "type" : "npc", - "tags" : ["roleplay"], - "ignore" : - [ - "*.psd", - "*.vcproj", - "*.svn*" - ] + "title": "[DV] Decent Vehicle - Basic AI", + "type": "npc", + "tags": ["roleplay"], + "ignore": [ + "*.psd", + "*.vcproj", + "*.svn*" + ] } diff --git a/lua/autorun/client/cl_decentvehicle.lua b/lua/autorun/client/cl_decentvehicle.lua index 5b5c2da..950ab70 100644 --- a/lua/autorun/client/cl_decentvehicle.lua +++ b/lua/autorun/client/cl_decentvehicle.lua @@ -12,201 +12,201 @@ include "autorun/decentvehicle.lua" -- Returns if v1 < v2 local VersionConst = Vector(1e8, 1e4, 1) local function CompareVersion(v1, v2) - v1 = Vector(tonumber(v1[1]) or 0, tonumber(v1[2]) or 0, tonumber(v1[3]) or 0) - v2 = Vector(tonumber(v2[1]) or 0, tonumber(v2[2]) or 0, tonumber(v2[3]) or 0) - return v1:Dot(VersionConst) < v2:Dot(VersionConst) + v1 = Vector(tonumber(v1[1]) or 0, tonumber(v1[2]) or 0, tonumber(v1[3]) or 0) + v2 = Vector(tonumber(v2[1]) or 0, tonumber(v2[2]) or 0, tonumber(v2[3]) or 0) + return v1:Dot(VersionConst) < v2:Dot(VersionConst) end local dvd = DecentVehicleDestination local function NotifyUpdate(d) - if not d then return end - -- local header = d.description:match(dvd.Texts.VersionPrefix .. "[^%c]+") or "" - local header = d.description:match "Version[^%c]+" or "" - dvd.Texts.Version = "Decent Vehicle: " .. header - - local showupdates = GetConVar "dv_route_showupdates" - if not (showupdates and showupdates:GetBool()) then return end - - if not file.Exists("decentvehicle", "DATA") then file.CreateDir "decentvehicle" end - local versionfile = "decentvehicle/version.txt" - local checkedversion = string.Explode(".", file.Read(versionfile) or "0.0.0") - local version = string.Explode(".", header:sub(8):Trim()) - if tonumber(checkedversion[1]) > 1e8 then checkedversion = {} end -- Backward compatibility - if CompareVersion(dvd.Version, version) then - notification.AddLegacy(dvd.Texts.OldVersionNotify, NOTIFY_ERROR, 15) - elseif CompareVersion(checkedversion, dvd.Version) then - local i = 0 - local sub = d.description:find "quote=Decent Vehicle" - if not sub then return end - local description = d.description:sub(1, sub - 2) - notification.AddLegacy("Decent Vehicle " .. header, NOTIFY_GENERIC, 18) - for update in description:gmatch "%[%*%][^%c]+" do - timer.Simple(3 * i, function() - if not showupdates:GetBool() then return end - notification.AddLegacy(update:sub(4), NOTIFY_UNDO, 6) - end) - - i = i + 1 - end - - file.Write(versionfile, string.format("%d.%d.%d", - dvd.Version[1], dvd.Version[2], dvd.Version[3])) - end + if not d then return end + -- local header = d.description:match(dvd.Texts.VersionPrefix .. "[^%c]+") or "" + local header = d.description:match "Version[^%c]+" or "" + dvd.Texts.Version = "Decent Vehicle: " .. header + + local showupdates = GetConVar "dv_route_showupdates" + if not (showupdates and showupdates:GetBool()) then return end + + if not file.Exists("decentvehicle", "DATA") then file.CreateDir "decentvehicle" end + local versionfile = "decentvehicle/version.txt" + local checkedversion = string.Explode(".", file.Read(versionfile) or "0.0.0") + local version = string.Explode(".", header:sub(8):Trim()) + if tonumber(checkedversion[1]) > 1e8 then checkedversion = {} end -- Backward compatibility + if CompareVersion(dvd.Version, version) then + notification.AddLegacy(dvd.Texts.OldVersionNotify, NOTIFY_ERROR, 15) + elseif CompareVersion(checkedversion, dvd.Version) then + local i = 0 + local sub = d.description:find "quote=Decent Vehicle" + if not sub then return end + local description = d.description:sub(1, sub - 2) + notification.AddLegacy("Decent Vehicle " .. header, NOTIFY_GENERIC, 18) + for update in description:gmatch "%[%*%][^%c]+" do + timer.Simple(3 * i, function() + if not showupdates:GetBool() then return end + notification.AddLegacy(update:sub(4), NOTIFY_UNDO, 6) + end) + + i = i + 1 + end + + file.Write(versionfile, string.format("%d.%d.%d", + dvd.Version[1], dvd.Version[2], dvd.Version[3])) + end end net.Receive("Decent Vehicle: Add a waypoint", function() - local pos = net.ReadVector() - local waypoint = {Target = pos, Neighbors = {}} - table.insert(dvd.Waypoints, waypoint) + local pos = net.ReadVector() + local waypoint = {Target = pos, Neighbors = {}} + table.insert(dvd.Waypoints, waypoint) end) net.Receive("Decent Vehicle: Remove a waypoint", function() - local id = net.ReadUInt(24) - for _, w in ipairs(dvd.Waypoints) do - local Neighbors = {} - for _, n in ipairs(w.Neighbors) do - if n > id then - table.insert(Neighbors, n - 1) - elseif n < id then - table.insert(Neighbors, n) - end - end - - w.Neighbors = Neighbors - end - - table.remove(dvd.Waypoints, id) + local id = net.ReadUInt(24) + for _, w in ipairs(dvd.Waypoints) do + local Neighbors = {} + for _, n in ipairs(w.Neighbors) do + if n > id then + table.insert(Neighbors, n - 1) + elseif n < id then + table.insert(Neighbors, n) + end + end + + w.Neighbors = Neighbors + end + + table.remove(dvd.Waypoints, id) end) net.Receive("Decent Vehicle: Add a neighbor", function() - local from = net.ReadUInt(24) - local to = net.ReadUInt(24) - if not dvd.Waypoints[from] then return end - table.insert(dvd.Waypoints[from].Neighbors, to) + local from = net.ReadUInt(24) + local to = net.ReadUInt(24) + if not dvd.Waypoints[from] then return end + table.insert(dvd.Waypoints[from].Neighbors, to) end) net.Receive("Decent Vehicle: Remove a neighbor", function() - local from = net.ReadUInt(24) - local to = net.ReadUInt(24) - if not dvd.Waypoints[from] then return end - table.RemoveByValue(dvd.Waypoints[from].Neighbors, to) + local from = net.ReadUInt(24) + local to = net.ReadUInt(24) + if not dvd.Waypoints[from] then return end + table.RemoveByValue(dvd.Waypoints[from].Neighbors, to) end) net.Receive("Decent Vehicle: Traffic light", function() - local id = net.ReadUInt(24) - local traffic = net.ReadEntity() - if not dvd.Waypoints[id] then return end - dvd.Waypoints[id].TrafficLight = Either(IsValid(traffic), traffic, nil) + local id = net.ReadUInt(24) + local traffic = net.ReadEntity() + if not dvd.Waypoints[id] then return end + dvd.Waypoints[id].TrafficLight = Either(IsValid(traffic), traffic, nil) end) local PopupTexts = { - dvd.Texts.OnSave, - dvd.Texts.OnLoad, - dvd.Texts.OnDelete, - dvd.Texts.OnGenerate, + dvd.Texts.OnSave, + dvd.Texts.OnLoad, + dvd.Texts.OnDelete, + dvd.Texts.OnGenerate, } local Notifications = { - dvd.Texts.SavedWaypoints, - dvd.Texts.LoadedWaypoints, - dvd.Texts.DeletedWaypoints, - dvd.Texts.GeneratedWaypoints, + dvd.Texts.SavedWaypoints, + dvd.Texts.LoadedWaypoints, + dvd.Texts.DeletedWaypoints, + dvd.Texts.GeneratedWaypoints, } net.Receive("Decent Vehicle: Save and restore", function() - local save = net.ReadUInt(dvd.POPUPWINDOW.BITS) - local Confirm = vgui.Create "DFrame" - local Text = Label(PopupTexts[save + 1], Confirm) - local Cancel = vgui.Create "DButton" - local OK = vgui.Create "DButton" - Confirm:Add(Cancel) - Confirm:Add(OK) - Confirm:SetSize(ScrW() / 5, ScrH() / 5) - Confirm:SetTitle "Decent Vehicle" - Confirm:SetBackgroundBlur(true) - Confirm:ShowCloseButton(false) - Confirm:Center() - Cancel:SetText(dvd.Texts.SaveLoad_Cancel) - Cancel:SetSize(Confirm:GetWide() * 5 / 16, 22) - Cancel:SetPos(Confirm:GetWide() * 7 / 8 - Cancel:GetWide(), Confirm:GetTall() - 22 - Cancel:GetTall()) - OK:SetText(dvd.Texts.SaveLoad_OK) - OK:SetSize(Confirm:GetWide() * 5 / 16, 22) - OK:SetPos(Confirm:GetWide() / 8, Confirm:GetTall() - 22 - OK:GetTall()) - Text:SizeToContents() - Text:Center() - Confirm:MakePopup() - - function Cancel:DoClick() Confirm:Close() end - function OK:DoClick() - net.Start "Decent Vehicle: Save and restore" - net.WriteUInt(save, dvd.POPUPWINDOW.BITS) - net.SendToServer() - notification.AddLegacy(Notifications[save + 1], NOTIFY_GENERIC, 5) - - Confirm:Close() - end + local save = net.ReadUInt(dvd.POPUPWINDOW.BITS) + local Confirm = vgui.Create "DFrame" + local Text = Label(PopupTexts[save + 1], Confirm) + local Cancel = vgui.Create "DButton" + local OK = vgui.Create "DButton" + Confirm:Add(Cancel) + Confirm:Add(OK) + Confirm:SetSize(ScrW() / 5, ScrH() / 5) + Confirm:SetTitle "Decent Vehicle" + Confirm:SetBackgroundBlur(true) + Confirm:ShowCloseButton(false) + Confirm:Center() + Cancel:SetText(dvd.Texts.SaveLoad_Cancel) + Cancel:SetSize(Confirm:GetWide() * 5 / 16, 22) + Cancel:SetPos(Confirm:GetWide() * 7 / 8 - Cancel:GetWide(), Confirm:GetTall() - 22 - Cancel:GetTall()) + OK:SetText(dvd.Texts.SaveLoad_OK) + OK:SetSize(Confirm:GetWide() * 5 / 16, 22) + OK:SetPos(Confirm:GetWide() / 8, Confirm:GetTall() - 22 - OK:GetTall()) + Text:SizeToContents() + Text:Center() + Confirm:MakePopup() + + function Cancel:DoClick() Confirm:Close() end + function OK:DoClick() + net.Start "Decent Vehicle: Save and restore" + net.WriteUInt(save, dvd.POPUPWINDOW.BITS) + net.SendToServer() + notification.AddLegacy(Notifications[save + 1], NOTIFY_GENERIC, 5) + + Confirm:Close() + end end) hook.Add("PostCleanupMap", "Decent Vehicle: Clean up waypoints", function() - table.Empty(dvd.Waypoints) + table.Empty(dvd.Waypoints) end) hook.Add("InitPostEntity", "Decent Vehicle: Load waypoints", function() - net.Start "Decent Vehicle: Retrive waypoints" - net.WriteUInt(1, 24) - net.SendToServer() + net.Start "Decent Vehicle: Retrive waypoints" + net.WriteUInt(1, 24) + net.SendToServer() - steamworks.FileInfo("1587455087", NotifyUpdate) + steamworks.FileInfo("1587455087", NotifyUpdate) end) net.Receive("Decent Vehicle: Retrive waypoints", function() - local id = net.ReadUInt(24) - if id < 1 then return end - local pos = net.ReadVector() - local traffic = net.ReadEntity() - if not IsValid(traffic) then traffic = nil end - local fuelstation = net.ReadBool() - local useturnlights = net.ReadBool() - local waituntilnext = net.ReadFloat() - local speedlimit = net.ReadFloat() - local group = net.ReadInt(8) - local num = net.ReadUInt(14) - local neighbors = {} - for i = 1, num do - table.insert(neighbors, net.ReadUInt(24)) - end - - dvd.Waypoints[id] = { - Target = pos, - TrafficLight = traffic, - FuelStation = fuelstation, - UseTurnLights = useturnlights, - WaitUntilNext = waituntilnext, - SpeedLimit = speedlimit, - Group = group, - Neighbors = neighbors, - } - - net.Start "Decent Vehicle: Retrive waypoints" - net.WriteUInt(id + 1, 24) - net.SendToServer() + local id = net.ReadUInt(24) + if id < 1 then return end + local pos = net.ReadVector() + local traffic = net.ReadEntity() + if not IsValid(traffic) then traffic = nil end + local fuelstation = net.ReadBool() + local useturnlights = net.ReadBool() + local waituntilnext = net.ReadFloat() + local speedlimit = net.ReadFloat() + local group = net.ReadInt(8) + local num = net.ReadUInt(14) + local neighbors = {} + for i = 1, num do + table.insert(neighbors, net.ReadUInt(24)) + end + + dvd.Waypoints[id] = { + Target = pos, + TrafficLight = traffic, + FuelStation = fuelstation, + UseTurnLights = useturnlights, + WaitUntilNext = waituntilnext, + SpeedLimit = speedlimit, + Group = group, + Neighbors = neighbors, + } + + net.Start "Decent Vehicle: Retrive waypoints" + net.WriteUInt(id + 1, 24) + net.SendToServer() end) net.Receive("Decent Vehicle: Send waypoint info", function() - local id = net.ReadUInt(24) - local waypoint = dvd.Waypoints[id] - if not waypoint then return end - waypoint.Group = net.ReadUInt(16) - waypoint.SpeedLimit = net.ReadFloat() - waypoint.WaitUntilNext = net.ReadFloat() - waypoint.UseTurnLights = net.ReadBool() - waypoint.FuelStation = net.ReadBool() + local id = net.ReadUInt(24) + local waypoint = dvd.Waypoints[id] + if not waypoint then return end + waypoint.Group = net.ReadUInt(16) + waypoint.SpeedLimit = net.ReadFloat() + waypoint.WaitUntilNext = net.ReadFloat() + waypoint.UseTurnLights = net.ReadBool() + waypoint.FuelStation = net.ReadBool() end) net.Receive("Decent Vehicle: Clear waypoints", function() - table.Empty(dvd.Waypoints) + table.Empty(dvd.Waypoints) end) net.Receive("Decent Vehicle: Sync CVar", function() - hook.Run "Decent Vehicle: Sync CVar" + hook.Run "Decent Vehicle: Sync CVar" end) local FuelColor = Color(192, 128, 0) @@ -221,94 +221,94 @@ local NumPolys = 192 local AngleStep = 360 / NumPolys hook.Add("PostDrawTranslucentRenderables", "Decent Vehicle: Draw waypoints", function(bDrawingDepth, bDrawingSkybox) - local weapon = LocalPlayer():GetActiveWeapon() - if not IsValid(weapon) then return end - if not isfunction(LocalPlayer().GetTool) then return end - - local always = GetConVar "dv_route_showalways" - local showpoints = GetConVar "dv_route_showpoints" - local drawdistance = GetConVar "dv_route_drawdistance" - local distsqr = drawdistance and drawdistance:GetFloat()^2 or 1000^2 - local size = dvd.WaypointSize - local TOOL = LocalPlayer():GetTool() - local ToolEquipped = weapon:GetClass() == "gmod_tool" and TOOL and TOOL.IsDecentVehicleTool - local MultiEdit = ToolEquipped and LocalPlayer():KeyDown(IN_USE) - local Trace = LocalPlayer():GetEyeTrace() - local UpdateRadius = GetConVar "dv_route_updateradius" - local Radius = UpdateRadius and UpdateRadius:GetInt() or 0 - local RadiusSqr = Radius^2 - if not (always:GetBool() or ToolEquipped) then return end - - if bDrawingSkybox or not (showpoints and showpoints:GetBool()) then return end - if MultiEdit then - render.SetMaterial(SelectRadiusMaterial) - render.StartBeam(NumPolys + 1) - local filter = player.GetAll() - local BaseNormal = Trace.HitNormal:Dot(vector_up) > .7 and Trace.HitNormal or vector_up - local TraceVector = BaseNormal * 32768 - local BaseAngle = BaseNormal:Angle() - for i = 0, NumPolys do - local pos = Vector(0, Radius, 0) - pos:Rotate(Angle(0, 0, AngleStep * i)) - - local start = LocalToWorld(pos, angle_zero, Trace.HitPos, BaseAngle) - local tr = util.TraceLine {start = start, endpos = start + TraceVector, mask = MASK_SOLID_BRUSHONLY} - tr = util.TraceLine {start = tr.HitPos, endpos = tr.HitPos - TraceVector, mask = MASK_SOLID, filter = filter} - - render.AddBeam(tr.HitPos + BaseNormal, 10, i, SelectedColor) - end - - render.EndBeam() - end - - for _, w in ipairs(dvd.Waypoints) do - if w.Target:DistToSqr(EyePos()) > distsqr then continue end - local visible = EyeAngles():Forward():Dot(w.Target - EyePos()) > 0 - if visible then - local color = w.FuelStation and FuelColor or color_white - if MultiEdit and Trace.HitPos:DistToSqr(w.Target) < RadiusSqr then - color = SelectedColor - end - - render.SetMaterial(WaypointMaterial) - render.DrawSprite(w.Target + Height, size, size, color) - if w.UseTurnLights then - render.SetMaterial(UseTurnLightsMaterial) - render.DrawSprite(w.Target + Height, size, size, color_white) - end - end - - render.SetMaterial(LinkMaterial) - for _, link in ipairs(w.Neighbors) do - local n = dvd.Waypoints[link] - if n and (visible or EyeAngles():Forward():Dot(n.Target - EyePos()) > 0) then - local pos = n.Target - local tex = w.Target:Distance(pos) / 100 - local texbase = 1 - CurTime() % 1 - render.DrawBeam(w.Target + Height, pos + Height, 20, texbase, texbase + tex, color_white) - end - end - - if IsValid(w.TrafficLight) then - local pos = w.TrafficLight:GetPos() - if visible or EyeAngles():Forward():Dot(pos - EyePos()) > 0 then - local tex = w.Target:Distance(pos) / 100 - render.SetMaterial(TrafficMaterial) - render.DrawBeam(w.Target + Height, pos, 20, 0, tex, color_white) - end - end - end - - render.SetMaterial(TrafficMaterial) - for m in pairs(dvd.WireManagers) do - local i = m:GetNWInt "WaypointID" - if i < 0 then continue end - local w = dvd.Waypoints[i] - if not w then continue end - local pos = w.Target + Height - local tex = m:GetPos():Distance(pos) / 100 - render.DrawBeam(m:GetPos(), pos, 20, 0, tex, color_white) - end + local weapon = LocalPlayer():GetActiveWeapon() + if not IsValid(weapon) then return end + if not isfunction(LocalPlayer().GetTool) then return end + + local always = GetConVar "dv_route_showalways" + local showpoints = GetConVar "dv_route_showpoints" + local drawdistance = GetConVar "dv_route_drawdistance" + local distsqr = drawdistance and drawdistance:GetFloat()^2 or 1000^2 + local size = dvd.WaypointSize + local TOOL = LocalPlayer():GetTool() + local ToolEquipped = weapon:GetClass() == "gmod_tool" and TOOL and TOOL.IsDecentVehicleTool + local MultiEdit = ToolEquipped and LocalPlayer():KeyDown(IN_USE) + local Trace = LocalPlayer():GetEyeTrace() + local UpdateRadius = GetConVar "dv_route_updateradius" + local Radius = UpdateRadius and UpdateRadius:GetInt() or 0 + local RadiusSqr = Radius^2 + if not (always:GetBool() or ToolEquipped) then return end + + if bDrawingSkybox or not (showpoints and showpoints:GetBool()) then return end + if MultiEdit then + render.SetMaterial(SelectRadiusMaterial) + render.StartBeam(NumPolys + 1) + local filter = player.GetAll() + local BaseNormal = Trace.HitNormal:Dot(vector_up) > .7 and Trace.HitNormal or vector_up + local TraceVector = BaseNormal * 32768 + local BaseAngle = BaseNormal:Angle() + for i = 0, NumPolys do + local pos = Vector(0, Radius, 0) + pos:Rotate(Angle(0, 0, AngleStep * i)) + + local start = LocalToWorld(pos, angle_zero, Trace.HitPos, BaseAngle) + local tr = util.TraceLine {start = start, endpos = start + TraceVector, mask = MASK_SOLID_BRUSHONLY} + tr = util.TraceLine {start = tr.HitPos, endpos = tr.HitPos - TraceVector, mask = MASK_SOLID, filter = filter} + + render.AddBeam(tr.HitPos + BaseNormal, 10, i, SelectedColor) + end + + render.EndBeam() + end + + for _, w in ipairs(dvd.Waypoints) do + if w.Target:DistToSqr(EyePos()) > distsqr then continue end + local visible = EyeAngles():Forward():Dot(w.Target - EyePos()) > 0 + if visible then + local color = w.FuelStation and FuelColor or color_white + if MultiEdit and Trace.HitPos:DistToSqr(w.Target) < RadiusSqr then + color = SelectedColor + end + + render.SetMaterial(WaypointMaterial) + render.DrawSprite(w.Target + Height, size, size, color) + if w.UseTurnLights then + render.SetMaterial(UseTurnLightsMaterial) + render.DrawSprite(w.Target + Height, size, size, color_white) + end + end + + render.SetMaterial(LinkMaterial) + for _, link in ipairs(w.Neighbors) do + local n = dvd.Waypoints[link] + if n and (visible or EyeAngles():Forward():Dot(n.Target - EyePos()) > 0) then + local pos = n.Target + local tex = w.Target:Distance(pos) / 100 + local texbase = 1 - CurTime() % 1 + render.DrawBeam(w.Target + Height, pos + Height, 20, texbase, texbase + tex, color_white) + end + end + + if IsValid(w.TrafficLight) then + local pos = w.TrafficLight:GetPos() + if visible or EyeAngles():Forward():Dot(pos - EyePos()) > 0 then + local tex = w.Target:Distance(pos) / 100 + render.SetMaterial(TrafficMaterial) + render.DrawBeam(w.Target + Height, pos, 20, 0, tex, color_white) + end + end + end + + render.SetMaterial(TrafficMaterial) + for m in pairs(dvd.WireManagers) do + local i = m:GetNWInt "WaypointID" + if i < 0 then continue end + local w = dvd.Waypoints[i] + if not w then continue end + local pos = w.Target + Height + local tex = m:GetPos():Distance(pos) / 100 + render.DrawBeam(m:GetPos(), pos, 20, 0, tex, color_white) + end end) hook.Run "Decent Vehicle: PostInitialize" diff --git a/lua/autorun/client/cl_decentvehicle.taxi.lua b/lua/autorun/client/cl_decentvehicle.taxi.lua index 5e286f8..7498049 100644 --- a/lua/autorun/client/cl_decentvehicle.taxi.lua +++ b/lua/autorun/client/cl_decentvehicle.taxi.lua @@ -4,76 +4,76 @@ -- and DangerKiddy(DK) (https://steamcommunity.com/profiles/76561198132964487/). local dvd = DecentVehicleDestination -if not dvd then return end +if not dvd then return end net.Receive("Decent Vehicle: Open a taxi menu", function() - local st = net.ReadEntity() - local DFrame = vgui.Create "DFrame" - local stations = {} - for k, v in ipairs(ents.GetAll()) do - if not v.IsDVTaxiStation then continue end - local name = v:GetStationName() - if st.IsDVTaxiStation and name == st:GetStationName() then continue end - stations[name] = true - end - - DFrame:SetTitle "DV Taxi" - DFrame:Center() - DFrame:SetSize(200, 100) - DFrame:SetSizable(true) - DFrame:SetVisible(true) - DFrame:SetDraggable(true) - DFrame:ShowCloseButton(true) - DFrame:MakePopup() - function DFrame:OnClose() - if DFrame.Called then return end - if st.IsDVTaxiStation then return end - net.Start "Decent Vehicle: Exit vehicle" - net.WriteEntity(st) - net.SendToServer() - end - - if st.IsDVTaxiStation then - local CurrentLocation = Label(st:GetStationName(), DFrame) - CurrentLocation:Dock(TOP) - end + local st = net.ReadEntity() + local DFrame = vgui.Create "DFrame" + local stations = {} + for k, v in ipairs(ents.GetAll()) do + if not v.IsDVTaxiStation then continue end + local name = v:GetStationName() + if st.IsDVTaxiStation and name == st:GetStationName() then continue end + stations[name] = true + end - local DComboBox = vgui.Create("DComboBox", DFrame) - DComboBox:Dock(TOP) - for name in pairs(stations) do - DComboBox:AddChoice(name) - end + DFrame:SetTitle "DV Taxi" + DFrame:Center() + DFrame:SetSize(200, 100) + DFrame:SetSizable(true) + DFrame:SetVisible(true) + DFrame:SetDraggable(true) + DFrame:ShowCloseButton(true) + DFrame:MakePopup() + function DFrame:OnClose() + if DFrame.Called then return end + if st.IsDVTaxiStation then return end + net.Start "Decent Vehicle: Exit vehicle" + net.WriteEntity(st) + net.SendToServer() + end - local DButton = vgui.Create("DButton", DFrame) - DButton:SetText(dvd.Texts.Taxi.Button) - DButton:Dock(TOP) - function DButton:DoClick() - if DComboBox:GetValue() == "" then return DFrame:Close() end - net.Start "Decent Vehicle: Call a taxi" - net.WriteString(DComboBox:GetValue()) - net.WriteEntity(st) - net.SendToServer() - DFrame.Called = true - DFrame:Close() - end + if st.IsDVTaxiStation then + local CurrentLocation = Label(st:GetStationName(), DFrame) + CurrentLocation:Dock(TOP) + end + + local DComboBox = vgui.Create("DComboBox", DFrame) + DComboBox:Dock(TOP) + for name in pairs(stations) do + DComboBox:AddChoice(name) + end + + local DButton = vgui.Create("DButton", DFrame) + DButton:SetText(dvd.Texts.Taxi.Button) + DButton:Dock(TOP) + function DButton:DoClick() + if DComboBox:GetValue() == "" then return DFrame:Close() end + net.Start "Decent Vehicle: Call a taxi" + net.WriteString(DComboBox:GetValue()) + net.WriteEntity(st) + net.SendToServer() + DFrame.Called = true + DFrame:Close() + end end) local quotes = { - [0] = "Coming", - [1] = "Getin", - [2] = "Arrived", - [3] = "StartGoing", - [4] = "ArrivedDestination", - [5] = "Getoff", - [6] = "Busy", - [7] = "NotEnoughMoney", - [8] = "NoDriverFound", + [0] = "Coming", + [1] = "Getin", + [2] = "Arrived", + [3] = "StartGoing", + [4] = "ArrivedDestination", + [5] = "Getoff", + [6] = "Busy", + [7] = "NotEnoughMoney", + [8] = "NoDriverFound", } net.Receive("Decent Vehicle: The taxi driver says something localized", function() - local t = net.ReadUInt(4) - LocalPlayer():ChatPrint(dvd.Texts.Taxi[quotes[t]]) - if t ~= 0 then return end - local dv = net.ReadEntity() - if not IsValid(dv) then return end - LocalPlayer():ChatPrint(dvd.Texts.Taxi.ShowCarName:format(dv:GetNWString "CarName")) + local t = net.ReadUInt(4) + LocalPlayer():ChatPrint(dvd.Texts.Taxi[quotes[t]]) + if t ~= 0 then return end + local dv = net.ReadEntity() + if not IsValid(dv) then return end + LocalPlayer():ChatPrint(dvd.Texts.Taxi.ShowCarName:format(dv:GetNWString "CarName")) end) diff --git a/lua/autorun/decentvehicle.lua b/lua/autorun/decentvehicle.lua index 1aa67f3..ce4809e 100644 --- a/lua/autorun/decentvehicle.lua +++ b/lua/autorun/decentvehicle.lua @@ -5,81 +5,81 @@ AddCSLuaFile() DecentVehicleDestination = DecentVehicleDestination or { - DriverAnimation = { - ["Source_models/airboat.mdl"] = "drive_airboat", - ["Source_models/sligwolf/motorbike/motorbike.mdl"] = "drive_airboat", - ["Source_models/sligwolf/tank/sw_tank_leo.mdl"] = "sit_rollercoaster", - ["SCAR_sent_sakarias_car_yamahayfz450"] = "drive_airboat", - ["Simfphys_models/monowheel.mdl"] = "drive_airboat", - }, - DriveSide = 1, - DRIVESIDE_LEFT = 1, - DRIVESIDE_RIGHT = 0, - DefaultDriverModel = { - "models/player/group01/female_01.mdl", - "models/player/group01/female_02.mdl", - "models/player/group01/female_03.mdl", - "models/player/group01/female_04.mdl", - "models/player/group01/female_05.mdl", - "models/player/group01/female_06.mdl", - "models/player/group01/male_01.mdl", - "models/player/group01/male_02.mdl", - "models/player/group01/male_03.mdl", - "models/player/group01/male_04.mdl", - "models/player/group01/male_05.mdl", - "models/player/group01/male_06.mdl", - "models/player/group01/male_07.mdl", - "models/player/group01/male_08.mdl", - "models/player/group01/male_09.mdl", - "models/player/group02/male_02.mdl", - "models/player/group02/male_04.mdl", - "models/player/group02/male_06.mdl", - "models/player/group02/male_08.mdl", - "models/player/group03/female_01.mdl", - "models/player/group03/female_02.mdl", - "models/player/group03/female_03.mdl", - "models/player/group03/female_04.mdl", - "models/player/group03/female_05.mdl", - "models/player/group03/female_06.mdl", - "models/player/group03/male_01.mdl", - "models/player/group03/male_02.mdl", - "models/player/group03/male_03.mdl", - "models/player/group03/male_04.mdl", - "models/player/group03/male_05.mdl", - "models/player/group03/male_06.mdl", - "models/player/group03/male_07.mdl", - "models/player/group03/male_08.mdl", - "models/player/group03/male_09.mdl", - }, - FakeCUserCmd = nil, - KmphToHUps = 1000 * 3.2808399 * 16 / 3600, - KmToHU = 1000 * 3.2808399 * 16, - PID = { - Throttle = {}, - Steering = {}, - }, - POPUPWINDOW = { - BITS = 2, - SAVE = 0, - LOAD = 1, - DELETE = 2, - GENERATE = 3, - }, - SeatPos = { - ["Source_models/airboat.mdl"] = Vector(0, 0, -29), - ["Source_models/vehicle.mdl"] = Vector(-8, 0, -24), - ["Source_models/sligwolf/motorbike/motorbike.mdl"] = Vector(2, 0, -30), - ["Simfphys_"] = Vector(2, 0, -28), - }, - TLDuration = {33, 4, 40 + 3}, -- Sign duration of each light color, Green, Yellow, Red. - TrafficLights = { - {Time = CurTime() + 33, Light = 1}, -- Light pattern #1 - {Time = CurTime() + 40, Light = 3}, -- Light pattern #2 - }, - Version = {1, 1, 2}, -- Major version, Minor version, Revision - Waypoints = {}, - WaypointSize = 32, - WireManagers = {}, + DriverAnimation = { + ["Source_models/airboat.mdl"] = "drive_airboat", + ["Source_models/sligwolf/motorbike/motorbike.mdl"] = "drive_airboat", + ["Source_models/sligwolf/tank/sw_tank_leo.mdl"] = "sit_rollercoaster", + ["SCAR_sent_sakarias_car_yamahayfz450"] = "drive_airboat", + ["Simfphys_models/monowheel.mdl"] = "drive_airboat", + }, + DriveSide = 1, + DRIVESIDE_LEFT = 1, + DRIVESIDE_RIGHT = 0, + DefaultDriverModel = { + "models/player/group01/female_01.mdl", + "models/player/group01/female_02.mdl", + "models/player/group01/female_03.mdl", + "models/player/group01/female_04.mdl", + "models/player/group01/female_05.mdl", + "models/player/group01/female_06.mdl", + "models/player/group01/male_01.mdl", + "models/player/group01/male_02.mdl", + "models/player/group01/male_03.mdl", + "models/player/group01/male_04.mdl", + "models/player/group01/male_05.mdl", + "models/player/group01/male_06.mdl", + "models/player/group01/male_07.mdl", + "models/player/group01/male_08.mdl", + "models/player/group01/male_09.mdl", + "models/player/group02/male_02.mdl", + "models/player/group02/male_04.mdl", + "models/player/group02/male_06.mdl", + "models/player/group02/male_08.mdl", + "models/player/group03/female_01.mdl", + "models/player/group03/female_02.mdl", + "models/player/group03/female_03.mdl", + "models/player/group03/female_04.mdl", + "models/player/group03/female_05.mdl", + "models/player/group03/female_06.mdl", + "models/player/group03/male_01.mdl", + "models/player/group03/male_02.mdl", + "models/player/group03/male_03.mdl", + "models/player/group03/male_04.mdl", + "models/player/group03/male_05.mdl", + "models/player/group03/male_06.mdl", + "models/player/group03/male_07.mdl", + "models/player/group03/male_08.mdl", + "models/player/group03/male_09.mdl", + }, + FakeCUserCmd = nil, + KmphToHUps = 1000 * 3.2808399 * 16 / 3600, + KmToHU = 1000 * 3.2808399 * 16, + PID = { + Throttle = {}, + Steering = {}, + }, + POPUPWINDOW = { + BITS = 2, + SAVE = 0, + LOAD = 1, + DELETE = 2, + GENERATE = 3, + }, + SeatPos = { + ["Source_models/airboat.mdl"] = Vector(0, 0, -29), + ["Source_models/vehicle.mdl"] = Vector(-8, 0, -24), + ["Source_models/sligwolf/motorbike/motorbike.mdl"] = Vector(2, 0, -30), + ["Simfphys_"] = Vector(2, 0, -28), + }, + TLDuration = {33, 4, 40 + 3}, -- Sign duration of each light color, Green, Yellow, Red. + TrafficLights = { + {Time = CurTime() + 33, Light = 1}, -- Light pattern #1 + {Time = CurTime() + 40, Light = 3}, -- Light pattern #2 + }, + Version = {1, 1, 2}, -- Major version, Minor version, Revision + Waypoints = {}, + WaypointSize = 32, + WireManagers = {}, } local dvd = DecentVehicleDestination @@ -87,115 +87,115 @@ local CVarFlags = {FCVAR_ARCHIVE, FCVAR_SERVER_CAN_EXECUTE, FCVAR_REPLICATED} -- Model list for wiremod support local WireModels = { - "models/props_c17/lampShade001a.mdl", - "models/hunter/blocks/cube025x025x025.mdl", - "models/props_wasteland/controlroom_filecabinet001a.mdl", - "models/props_lab/powerbox02d.mdl", - "models/jaanus/wiretool/wiretool_siren.mdl", - "models/jaanus/wiretool/wiretool_range.mdl", + "models/props_c17/lampShade001a.mdl", + "models/hunter/blocks/cube025x025x025.mdl", + "models/props_wasteland/controlroom_filecabinet001a.mdl", + "models/props_lab/powerbox02d.mdl", + "models/jaanus/wiretool/wiretool_siren.mdl", + "models/jaanus/wiretool/wiretool_range.mdl", } for k, v in pairs(WireModels) do - if file.Exists(v, "GAME") then - list.Set("[DV] WireManager Model List", v, true) - end + if file.Exists(v, "GAME") then + list.Set("[DV] WireManager Model List", v, true) + end end -- Gets direction vector from v1 to v2. -- Arguments: --- Vector v1 | The beginning point. --- Vector v2 | The ending point. +-- Vector v1 | The beginning point. +-- Vector v2 | The ending point. -- Returns: --- Vector dir | Normalized vector of v2 - v1. +-- Vector dir | Normalized vector of v2 - v1. function dvd.GetDir(v1, v2) - return (v2 - v1):GetNormalized() + return (v2 - v1):GetNormalized() end -- Gets angle between vector A and B. -- Arguments: --- Vector A | The first vector. --- Vector B | The second vector. +-- Vector A | The first vector. +-- Vector B | The second vector. -- Returns: --- number ang | The angle of two vectors. The actual angle is math.acos(ang). +-- number ang | The angle of two vectors. The actual angle is math.acos(ang). function dvd.GetAng(A, B) - return A:GetNormalized():Dot(B:GetNormalized()) + return A:GetNormalized():Dot(B:GetNormalized()) end -- Gets angle between vector AB and BC. -- Arguments: --- Vector A | The beginning point. --- Vector B | The middle point. --- Vector C | The ending point. +-- Vector A | The beginning point. +-- Vector B | The middle point. +-- Vector C | The ending point. -- Returns: --- number ang | The same as dvd.GetAng() +-- number ang | The same as dvd.GetAng() function dvd.GetAng3(A, B, C) - return dvd.GetAng(B - A, C - B) + return dvd.GetAng(B - A, C - B) end -- Retrives the nearest waypoint to the given position. -- Arguments: --- Vector pos | The position to find. --- number filter | Optional. The maximum radius. Can also be a function. +-- Vector pos | The position to find. +-- number filter | Optional. The maximum radius. Can also be a function. -- Returns: --- table waypoint | The found waypoint. Can be nil. --- number waypointID | The ID of found waypoint. +-- table waypoint | The found waypoint. Can be nil. +-- number waypointID | The ID of found waypoint. function dvd.GetNearestWaypoint(pos, filter) - if not isvector(pos) then return end - local r = not isfunction(filter) and filter or math.huge - local mindistance, waypoint, waypointID = r^2 - for i, w in ipairs(dvd.Waypoints) do - local distance = w.Target:DistToSqr(pos) - if distance < mindistance and (not isfunction(filter) - or filter(i, waypointID, mindistance)) then - mindistance, waypoint, waypointID = distance, w, i - end - end + if not isvector(pos) then return end + local r = not isfunction(filter) and filter or math.huge + local mindistance, waypoint, waypointID = r^2 + for i, w in ipairs(dvd.Waypoints) do + local distance = w.Target:DistToSqr(pos) + if distance < mindistance and (not isfunction(filter) + or filter(i, waypointID, mindistance)) then + mindistance, waypoint, waypointID = distance, w, i + end + end - return waypoint, waypointID + return waypoint, waypointID end local lang = GetConVar "gmod_language":GetString() local function ReadTexts(convar, old, new) - dvd.Texts = {} + dvd.Texts = {} - local directories = select(2, file.Find("decentvehicle/*", "LUA")) - for _, dir in ipairs(directories) do - if SERVER then -- We need to run AddCSLuaFile() for all languages. - local path = string.format("decentvehicle/%s/", dir) - local files = file.Find(path .. "*.lua", "LUA") - for _, f in ipairs(files) do - AddCSLuaFile(path .. f) - end - end + local directories = select(2, file.Find("decentvehicle/*", "LUA")) + for _, dir in ipairs(directories) do + if SERVER then -- We need to run AddCSLuaFile() for all languages. + local path = string.format("decentvehicle/%s/", dir) + local files = file.Find(path .. "*.lua", "LUA") + for _, f in ipairs(files) do + AddCSLuaFile(path .. f) + end + end - local path = string.format("decentvehicle/%s/en.lua", dir) - if file.Exists(path, "LUA") then table.Merge(dvd.Texts, include(path)) end - path = string.format("decentvehicle/%s/%s.lua", dir, new) - if file.Exists(path, "LUA") then table.Merge(dvd.Texts, include(path)) end - end + local path = string.format("decentvehicle/%s/en.lua", dir) + if file.Exists(path, "LUA") then table.Merge(dvd.Texts, include(path)) end + path = string.format("decentvehicle/%s/%s.lua", dir, new) + if file.Exists(path, "LUA") then table.Merge(dvd.Texts, include(path)) end + end end ReadTexts("gmod_language", lang, lang) cvars.AddChangeCallback("gmod_language", ReadTexts, "Decent Vehicle: OnLanguageChanged") dvd.CVars = dvd.CVars or { - AutoLoad = CreateConVar("decentvehicle_autoload", 0, CVarFlags, dvd.Texts.CVars.AutoLoad), - DetectionRange = CreateConVar("decentvehicle_detectionrange", 30, CVarFlags, dvd.Texts.CVars.DetectionRange), - DetectionRangeELS = CreateConVar("decentvehicle_elsrange", 300, CVarFlags, dvd.Texts.CVars.DetectionRangeELS), - DriveSide = CreateConVar("decentvehicle_driveside", 0, CVarFlags, dvd.Texts.CVars.DriveSide), - ForceHeadlights = CreateConVar("decentvehicle_forceheadlights", 0, CVarFlags, dvd.Texts.CVars.ForceHeadlights), - LockVehicle = CreateConVar("decentvehicle_lock", 0, CVarFlags, dvd.Texts.CVars.LockVehicle), - Police = { - ChangeCode = CreateConVar("decentvehicle_police_changecodetimer", 60, CVarFlags, dvd.Texts.Police.CVars.ChangeCode), - }, - ShouldGoToRefuel = CreateConVar("decentvehicle_gotorefuel", 1, CVarFlags, dvd.Texts.CVars.ShouldGoToRefuel), - StopInfrontofPerson = CreateConVar("decentvehicle_stop_infrontof_person", 1, CVarFlags, dvd.Texts.CVars.StopInfrontofPerson), - Taxi = { - UnitPrice = CreateConVar("decentvehicle_taxi_unitprice", 5, CVarFlags, dvd.Texts.Taxi.UnitPrice), - }, - TimeToStopEmergency = CreateConVar("decentvehicle_timetostopemergency", 5, CVarFlags, dvd.Texts.CVars.TimeToStopEmergency), - TurnOnLights = CreateConVar("decentvehicle_turnonlights", 3, CVarFlags, dvd.Texts.CVars.TurnOnLights), + AutoLoad = CreateConVar("decentvehicle_autoload", 0, CVarFlags, dvd.Texts.CVars.AutoLoad), + DetectionRange = CreateConVar("decentvehicle_detectionrange", 30, CVarFlags, dvd.Texts.CVars.DetectionRange), + DetectionRangeELS = CreateConVar("decentvehicle_elsrange", 300, CVarFlags, dvd.Texts.CVars.DetectionRangeELS), + DriveSide = CreateConVar("decentvehicle_driveside", 0, CVarFlags, dvd.Texts.CVars.DriveSide), + ForceHeadlights = CreateConVar("decentvehicle_forceheadlights", 0, CVarFlags, dvd.Texts.CVars.ForceHeadlights), + LockVehicle = CreateConVar("decentvehicle_lock", 0, CVarFlags, dvd.Texts.CVars.LockVehicle), + Police = { + ChangeCode = CreateConVar("decentvehicle_police_changecodetimer", 60, CVarFlags, dvd.Texts.Police.CVars.ChangeCode), + }, + ShouldGoToRefuel = CreateConVar("decentvehicle_gotorefuel", 1, CVarFlags, dvd.Texts.CVars.ShouldGoToRefuel), + StopInfrontofPerson = CreateConVar("decentvehicle_stop_infrontof_person", 1, CVarFlags, dvd.Texts.CVars.StopInfrontofPerson), + Taxi = { + UnitPrice = CreateConVar("decentvehicle_taxi_unitprice", 5, CVarFlags, dvd.Texts.Taxi.UnitPrice), + }, + TimeToStopEmergency = CreateConVar("decentvehicle_timetostopemergency", 5, CVarFlags, dvd.Texts.CVars.TimeToStopEmergency), + TurnOnLights = CreateConVar("decentvehicle_turnonlights", 3, CVarFlags, dvd.Texts.CVars.TurnOnLights), } hook.Add("StartCommand", "Decent Vehicle: Get a fake CUserCmd", function(ply, cmd) - dvd.FakeCUserCmd = cmd - hook.Remove("StartCommand", "Decent Vehicle: Get a fake CUserCmd") + dvd.FakeCUserCmd = cmd + hook.Remove("StartCommand", "Decent Vehicle: Get a fake CUserCmd") end) diff --git a/lua/autorun/server/sv_decentvehicle.lua b/lua/autorun/server/sv_decentvehicle.lua index b3f8411..fe5ea5e 100644 --- a/lua/autorun/server/sv_decentvehicle.lua +++ b/lua/autorun/server/sv_decentvehicle.lua @@ -16,234 +16,234 @@ local HULLS = 10 local MAX_NODES = 1500 local NODE_VERSION_NUMBER = 37 local function ClearUndoList() - for id, undolist in pairs(undo.GetTable()) do - for i, undotable in pairs(undolist) do - if undotable.Name ~= "Decent Vehicle Waypoint" then continue end - undolist[i] = nil - end - end + for id, undolist in pairs(undo.GetTable()) do + for i, undotable in pairs(undolist) do + if undotable.Name ~= "Decent Vehicle Waypoint" then continue end + undolist[i] = nil + end + end end local function ConfirmSaveRestore(ply, save) - if not (IsValid(ply) and ply:IsPlayer()) then return end - net.Start "Decent Vehicle: Save and restore" - net.WriteUInt(save, dvd.POPUPWINDOW.BITS) - net.Send(ply) + if not (IsValid(ply) and ply:IsPlayer()) then return end + net.Start "Decent Vehicle: Save and restore" + net.WriteUInt(save, dvd.POPUPWINDOW.BITS) + net.Send(ply) end local function WriteWaypoint(id) - local waypoint = dvd.Waypoints[id] - net.WriteUInt(id, 24) - net.WriteVector(waypoint.Target) - net.WriteEntity(waypoint.TrafficLight or NULL) - net.WriteBool(waypoint.FuelStation) - net.WriteBool(waypoint.UseTurnLights) - net.WriteFloat(waypoint.WaitUntilNext) - net.WriteFloat(waypoint.SpeedLimit) - net.WriteInt(waypoint.Group, 8) - net.WriteUInt(#waypoint.Neighbors, 14) - for i, n in ipairs(waypoint.Neighbors) do - net.WriteUInt(n, 24) - end + local waypoint = dvd.Waypoints[id] + net.WriteUInt(id, 24) + net.WriteVector(waypoint.Target) + net.WriteEntity(waypoint.TrafficLight or NULL) + net.WriteBool(waypoint.FuelStation) + net.WriteBool(waypoint.UseTurnLights) + net.WriteFloat(waypoint.WaitUntilNext) + net.WriteFloat(waypoint.SpeedLimit) + net.WriteInt(waypoint.Group, 8) + net.WriteUInt(#waypoint.Neighbors, 14) + for i, n in ipairs(waypoint.Neighbors) do + net.WriteUInt(n, 24) + end end local function OverwriteWaypoints(source) - if source == dvd then return end - dvd.CVars.ForceHeadlights:SetInt(source.ForceHeadlights and 1 or 0) -- Added from version 1.0.7 - dvd.CVars.DriveSide:SetInt(source.DriveSide or 0) - dvd.DriveSide = source.DriveSide or 0 - ClearUndoList() - table.Empty(dvd.Waypoints) - - if player.GetCount() > 0 then - net.Start "Decent Vehicle: Sync CVar" - net.Broadcast() - net.Start "Decent Vehicle: Clear waypoints" - net.Broadcast() - end - - for i, t in ipairs(ents.GetAll()) do - if t.IsDVTrafficLight then t:Remove() end - end - - for i, w in ipairs(source) do - local new = dvd.AddWaypoint(w.Target) - for key, value in pairs(w) do - if Exceptions[key] then continue end - new[key] = value - end - end - - for i, t in ipairs(source.TrafficLights) do - local traffic = ents.Create(t.ClassName) - if not IsValid(traffic) then continue end - traffic:SetPos(t.Pos) - traffic:SetAngles(t.Ang) - traffic:Spawn() - traffic:SetPattern(t.Pattern) - traffic.Waypoints = t.Waypoints - for i, id in ipairs(t.Waypoints) do - if not dvd.Waypoints[id] then continue end - dvd.Waypoints[id].TrafficLight = traffic - end - - local p = traffic:GetPhysicsObject() - if IsValid(p) then p:Sleep() end - end - - hook.Run("Decent Vehicle: OnLoadWaypoints", source) - - if #dvd.Waypoints * player.GetCount() == 0 then return end - net.Start "Decent Vehicle: Retrive waypoints" - WriteWaypoint(1) - net.Broadcast() + if source == dvd then return end + dvd.CVars.ForceHeadlights:SetInt(source.ForceHeadlights and 1 or 0) -- Added from version 1.0.7 + dvd.CVars.DriveSide:SetInt(source.DriveSide or 0) + dvd.DriveSide = source.DriveSide or 0 + ClearUndoList() + table.Empty(dvd.Waypoints) + + if player.GetCount() > 0 then + net.Start "Decent Vehicle: Sync CVar" + net.Broadcast() + net.Start "Decent Vehicle: Clear waypoints" + net.Broadcast() + end + + for i, t in ipairs(ents.GetAll()) do + if t.IsDVTrafficLight then t:Remove() end + end + + for i, w in ipairs(source) do + local new = dvd.AddWaypoint(w.Target) + for key, value in pairs(w) do + if Exceptions[key] then continue end + new[key] = value + end + end + + for i, t in ipairs(source.TrafficLights) do + local traffic = ents.Create(t.ClassName) + if not IsValid(traffic) then continue end + traffic:SetPos(t.Pos) + traffic:SetAngles(t.Ang) + traffic:Spawn() + traffic:SetPattern(t.Pattern) + traffic.Waypoints = t.Waypoints + for i, id in ipairs(t.Waypoints) do + if not dvd.Waypoints[id] then continue end + dvd.Waypoints[id].TrafficLight = traffic + end + + local p = traffic:GetPhysicsObject() + if IsValid(p) then p:Sleep() end + end + + hook.Run("Decent Vehicle: OnLoadWaypoints", source) + + if #dvd.Waypoints * player.GetCount() == 0 then return end + net.Start "Decent Vehicle: Retrive waypoints" + WriteWaypoint(1) + net.Broadcast() end local function LoadWaypoints(path) - local pngpath = string.format("data/%s.png", path) - local txtpath = string.format("data/%s.txt", path) - local scriptpath = string.format("scripts/vehicles/%s.txt", path) - if file.Exists(txtpath, "GAME") then - OverwriteWaypoints(util.JSONToTable(util.Decompress(file.Read(txtpath, "GAME") or ""))) - elseif file.Exists(scriptpath, "GAME") then - OverwriteWaypoints(util.JSONToTable(util.Decompress(file.Read(scriptpath, "GAME") or ""))) - elseif file.Exists(pngpath, "GAME") then -- Backward compatibility - OverwriteWaypoints(util.JSONToTable(util.Decompress(file.Read(pngpath, "GAME") or ""))) - end + local pngpath = string.format("data/%s.png", path) + local txtpath = string.format("data/%s.txt", path) + local scriptpath = string.format("scripts/vehicles/%s.txt", path) + if file.Exists(txtpath, "GAME") then + OverwriteWaypoints(util.JSONToTable(util.Decompress(file.Read(txtpath, "GAME") or ""))) + elseif file.Exists(scriptpath, "GAME") then + OverwriteWaypoints(util.JSONToTable(util.Decompress(file.Read(scriptpath, "GAME") or ""))) + elseif file.Exists(pngpath, "GAME") then -- Backward compatibility + OverwriteWaypoints(util.JSONToTable(util.Decompress(file.Read(pngpath, "GAME") or ""))) + end end local function ParseAIN() - local path = string.format("maps/graphs/%s.ain", game.GetMap()) - local f = file.Open(path, "rb", "GAME") - if not f then return end - - local node_version = f:ReadLong() - local map_version = f:ReadLong() - local numNodes = f:ReadLong() - local nodegraph = { - node_version = node_version, - map_version = map_version, - } - - assert(node_version == NODE_VERSION_NUMBER, "Decent Vehicle: Unknown graph file.") - assert(0 <= numNodes and numNodes <= MAX_NODES, "Decent Vehicle: Graph file has an unexpected amount of nodes") - - local nodes = {} - for i = 1, numNodes do - local x = f:ReadFloat() - local y = f:ReadFloat() - local z = f:ReadFloat() - local yaw = f:ReadFloat() - local v = Vector(x, y, z) - local flOffsets = {} - for i = 1, HULLS do - flOffsets[i] = f:ReadFloat() - end - - local nodetype = f:ReadByte() - local nodeinfo = f:ReadUShort() - local zone = f:ReadShort() - local node = { - pos = v, - yaw = yaw, - offset = flOffsets, - type = nodetype, - info = nodeinfo, - zone = zone, - neighbor = {}, - numneighbors = 0, - link = {}, - numlinks = 0 - } - - table.insert(nodes, node) - end - - local numLinks = f:ReadLong() - local links = {} - for i = 1, numLinks do - local link = {} - local srcID = f:ReadShort() - local destID = f:ReadShort() - local nodesrc = assert(nodes[srcID + 1], "Decent Vehicle: Unknown source node") - local nodedest = assert(nodes[destID + 1], "Decent Vehicle: Unknown destination node") - table.insert(nodesrc. neighbor, nodedest) - nodesrc.numneighbors = nodesrc.numneighbors + 1 - - table.insert(nodesrc.link, link) - nodesrc.numlinks = nodesrc.numlinks + 1 - link.src, link.srcID = nodesrc, srcID + 1 - - table.insert(nodedest.neighbor, nodesrc) - nodedest.numneighbors = nodedest.numneighbors + 1 - - table.insert(nodedest.link, link) - nodedest.numlinks = nodedest.numlinks + 1 - link.dest, link.destID = nodedest, destID + 1 - - link.move = {} - for i = 1, HULLS do - link.move[i] = f:ReadByte() - end - - table.insert(links, link) - end - - local lookup = {} - for i = 1, numNodes do - table.insert(lookup, f:ReadLong()) - end - - f:Close() - nodegraph.nodes = nodes - nodegraph.links = links - nodegraph.lookup = lookup - return nodegraph + local path = string.format("maps/graphs/%s.ain", game.GetMap()) + local f = file.Open(path, "rb", "GAME") + if not f then return end + + local node_version = f:ReadLong() + local map_version = f:ReadLong() + local numNodes = f:ReadLong() + local nodegraph = { + node_version = node_version, + map_version = map_version, + } + + assert(node_version == NODE_VERSION_NUMBER, "Decent Vehicle: Unknown graph file.") + assert(0 <= numNodes and numNodes <= MAX_NODES, "Decent Vehicle: Graph file has an unexpected amount of nodes") + + local nodes = {} + for i = 1, numNodes do + local x = f:ReadFloat() + local y = f:ReadFloat() + local z = f:ReadFloat() + local yaw = f:ReadFloat() + local v = Vector(x, y, z) + local flOffsets = {} + for i = 1, HULLS do + flOffsets[i] = f:ReadFloat() + end + + local nodetype = f:ReadByte() + local nodeinfo = f:ReadUShort() + local zone = f:ReadShort() + local node = { + pos = v, + yaw = yaw, + offset = flOffsets, + type = nodetype, + info = nodeinfo, + zone = zone, + neighbor = {}, + numneighbors = 0, + link = {}, + numlinks = 0 + } + + table.insert(nodes, node) + end + + local numLinks = f:ReadLong() + local links = {} + for i = 1, numLinks do + local link = {} + local srcID = f:ReadShort() + local destID = f:ReadShort() + local nodesrc = assert(nodes[srcID + 1], "Decent Vehicle: Unknown source node") + local nodedest = assert(nodes[destID + 1], "Decent Vehicle: Unknown destination node") + table.insert(nodesrc. neighbor, nodedest) + nodesrc.numneighbors = nodesrc.numneighbors + 1 + + table.insert(nodesrc.link, link) + nodesrc.numlinks = nodesrc.numlinks + 1 + link.src, link.srcID = nodesrc, srcID + 1 + + table.insert(nodedest.neighbor, nodesrc) + nodedest.numneighbors = nodedest.numneighbors + 1 + + table.insert(nodedest.link, link) + nodedest.numlinks = nodedest.numlinks + 1 + link.dest, link.destID = nodedest, destID + 1 + + link.move = {} + for i = 1, HULLS do + link.move[i] = f:ReadByte() + end + + table.insert(links, link) + end + + local lookup = {} + for i = 1, numNodes do + table.insert(lookup, f:ReadLong()) + end + + f:Close() + nodegraph.nodes = nodes + nodegraph.links = links + nodegraph.lookup = lookup + return nodegraph end local function GenerateWaypoints(ply) - dvd.Nodegraph = dvd.Nodegraph or ParseAIN() - ClearUndoList() - table.Empty(dvd.Waypoints) - if player.GetCount() > 0 then - net.Start "Decent Vehicle: Clear waypoints" - net.Broadcast() - end - - local speed = ply:GetInfoNum("dv_route_speed", 45) * dvd.KmphToHUps - local time = CurTime() - local map = {} - for i, n in ipairs(dvd.Nodegraph.nodes) do - if n.type ~= 2 then continue end - table.insert(dvd.Waypoints, { - FuelStation = false, - Group = 0, - Neighbors = {}, - Owner = ply, - SpeedLimit = speed, - Target = util.QuickTrace(n.pos + vector_up * dvd.WaypointSize, -vector_up * 32768).HitPos, - Time = time, - TrafficLight = nil, - UseTurnLights = false, - WaitUntilNext = 0, - }) - - map[i] = #dvd.Waypoints - end - - for i, link in ipairs(dvd.Nodegraph.links) do - if link.move[HULL_LARGE_CENTERED + 1] ~= 1 then continue end - local d, s = map[link.destID], map[link.srcID] - if dvd.Waypoints[d] and dvd.Waypoints[s] then - table.insert(dvd.Waypoints[s].Neighbors, d) - table.insert(dvd.Waypoints[d].Neighbors, s) - end - end - - if #dvd.Waypoints * player.GetCount() == 0 then return end - net.Start "Decent Vehicle: Retrive waypoints" - WriteWaypoint(1) - net.Broadcast() + dvd.Nodegraph = dvd.Nodegraph or ParseAIN() + ClearUndoList() + table.Empty(dvd.Waypoints) + if player.GetCount() > 0 then + net.Start "Decent Vehicle: Clear waypoints" + net.Broadcast() + end + + local speed = ply:GetInfoNum("dv_route_speed", 45) * dvd.KmphToHUps + local time = CurTime() + local map = {} + for i, n in ipairs(dvd.Nodegraph.nodes) do + if n.type ~= 2 then continue end + table.insert(dvd.Waypoints, { + FuelStation = false, + Group = 0, + Neighbors = {}, + Owner = ply, + SpeedLimit = speed, + Target = util.QuickTrace(n.pos + vector_up * dvd.WaypointSize, -vector_up * 32768).HitPos, + Time = time, + TrafficLight = nil, + UseTurnLights = false, + WaitUntilNext = 0, + }) + + map[i] = #dvd.Waypoints + end + + for i, link in ipairs(dvd.Nodegraph.links) do + if link.move[HULL_LARGE_CENTERED + 1] ~= 1 then continue end + local d, s = map[link.destID], map[link.srcID] + if dvd.Waypoints[d] and dvd.Waypoints[s] then + table.insert(dvd.Waypoints[s].Neighbors, d) + table.insert(dvd.Waypoints[d].Neighbors, s) + end + end + + if #dvd.Waypoints * player.GetCount() == 0 then return end + net.Start "Decent Vehicle: Retrive waypoints" + WriteWaypoint(1) + net.Broadcast() end include "sv_decentvehicle_taxi.lua" @@ -263,436 +263,436 @@ concommand.Add("dv_route_load", function(ply) ConfirmSaveRestore(ply, dvd.POPUPW concommand.Add("dv_route_delete", function(ply) ConfirmSaveRestore(ply, dvd.POPUPWINDOW.DELETE) end) concommand.Add("dv_route_generate", function(ply) ConfirmSaveRestore(ply, dvd.POPUPWINDOW.GENERATE) end) cvars.AddChangeCallback("decentvehicle_driveside", function(cvar, old, new) - local side = tonumber(new) - if not (side == dvd.DRIVESIDE_LEFT or side == dvd.DRIVESIDE_RIGHT) then return end - dvd.DriveSide = side + local side = tonumber(new) + if not (side == dvd.DRIVESIDE_LEFT or side == dvd.DRIVESIDE_RIGHT) then return end + dvd.DriveSide = side end, "Decent Vehicle: Drive side callback") duplicator.RegisterEntityModifier("Decent Vehicle: Save waypoints", function(ply, ent, data) - OverwriteWaypoints(data) - dvd.SaveEntity = ent + OverwriteWaypoints(data) + dvd.SaveEntity = ent end) saverestore.AddSaveHook("Decent Vehicle", function(save) - saverestore.WriteTable(dvd.GetSaveTable(), save) + saverestore.WriteTable(dvd.GetSaveTable(), save) end) saverestore.AddRestoreHook("Decent Vehicle", function(restore) - OverwriteWaypoints(saverestore.ReadTable(restore)) - for id, undolist in pairs(undo.GetTable()) do - for i, undotable in pairs(undolist) do - if undotable.Name ~= "Decent Vehicle Waypoint" then continue end - undolist[i].Functions[1] = {dvd.UndoWaypoint, {}} - end - end + OverwriteWaypoints(saverestore.ReadTable(restore)) + for id, undolist in pairs(undo.GetTable()) do + for i, undotable in pairs(undolist) do + if undotable.Name ~= "Decent Vehicle Waypoint" then continue end + undolist[i].Functions[1] = {dvd.UndoWaypoint, {}} + end + end end) hook.Add("PostCleanupMap", "Decent Vehicle: Clean up waypoints", function() - dvd.Waypoints = {} - ClearUndoList() + dvd.Waypoints = {} + ClearUndoList() end) hook.Add("InitPostEntity", "Decent Vehicle: Load waypoints", function() - dvd.SaveEntity = ents.Create "env_dv_save" - dvd.SaveEntity:Spawn() - if not dvd.CVars.AutoLoad:GetBool() then return end - LoadWaypoints("decentvehicle/" .. game.GetMap()) + dvd.SaveEntity = ents.Create "env_dv_save" + dvd.SaveEntity:Spawn() + if not dvd.CVars.AutoLoad:GetBool() then return end + LoadWaypoints("decentvehicle/" .. game.GetMap()) end) hook.Add("Tick", "Decent Vehicle: Control traffic lights", function() - for PatternName, TL in pairs(dvd.TrafficLights) do - if CurTime() < TL.Time then continue end - TL.Light = TL.Light % 3 + 1 - TL.Time = CurTime() + dvd.TLDuration[TL.Light] - end + for PatternName, TL in pairs(dvd.TrafficLights) do + if CurTime() < TL.Time then continue end + TL.Light = TL.Light % 3 + 1 + TL.Time = CurTime() + dvd.TLDuration[TL.Light] + end end) net.Receive("Decent Vehicle: Retrive waypoints", function(_, ply) - local id = net.ReadUInt(24) - net.Start "Decent Vehicle: Retrive waypoints" - if id > #dvd.Waypoints then - net.WriteUInt(0, 24) - net.Send(ply) - return - end - - WriteWaypoint(id) - net.Send(ply) + local id = net.ReadUInt(24) + net.Start "Decent Vehicle: Retrive waypoints" + if id > #dvd.Waypoints then + net.WriteUInt(0, 24) + net.Send(ply) + return + end + + WriteWaypoint(id) + net.Send(ply) end) net.Receive("Decent Vehicle: Send waypoint info", function(_, ply) - local id = net.ReadUInt(24) - local waypoint = dvd.Waypoints[id] - if not waypoint then return end - net.Start "Decent Vehicle: Send waypoint info" - net.WriteUInt(id, 24) - net.WriteUInt(waypoint.Group, 16) - net.WriteFloat(waypoint.SpeedLimit) - net.WriteFloat(waypoint.WaitUntilNext) - net.WriteBool(waypoint.UseTurnLights) - net.WriteBool(waypoint.FuelStation) - net.Send(ply) + local id = net.ReadUInt(24) + local waypoint = dvd.Waypoints[id] + if not waypoint then return end + net.Start "Decent Vehicle: Send waypoint info" + net.WriteUInt(id, 24) + net.WriteUInt(waypoint.Group, 16) + net.WriteFloat(waypoint.SpeedLimit) + net.WriteFloat(waypoint.WaitUntilNext) + net.WriteBool(waypoint.UseTurnLights) + net.WriteBool(waypoint.FuelStation) + net.Send(ply) end) net.Receive("Decent Vehicle: Save and restore", function(_, ply) - if not ply:IsAdmin() then return end - local save = net.ReadUInt(dvd.POPUPWINDOW.BITS) - local dir = "decentvehicle/" - local path = dir .. game.GetMap() - if save == dvd.POPUPWINDOW.SAVE then - if not file.Exists(dir, "DATA") then file.CreateDir(dir) end - file.Write(path .. ".txt", util.Compress(util.TableToJSON(dvd.GetSaveTable()))) - elseif save == dvd.POPUPWINDOW.LOAD then - LoadWaypoints(path) - elseif save == dvd.POPUPWINDOW.DELETE then - file.Delete(path .. ".png") - file.Delete(path .. ".txt") - elseif save == dvd.POPUPWINDOW.GENERATE then - GenerateWaypoints(ply) - end + if not ply:IsAdmin() then return end + local save = net.ReadUInt(dvd.POPUPWINDOW.BITS) + local dir = "decentvehicle/" + local path = dir .. game.GetMap() + if save == dvd.POPUPWINDOW.SAVE then + if not file.Exists(dir, "DATA") then file.CreateDir(dir) end + file.Write(path .. ".txt", util.Compress(util.TableToJSON(dvd.GetSaveTable()))) + elseif save == dvd.POPUPWINDOW.LOAD then + LoadWaypoints(path) + elseif save == dvd.POPUPWINDOW.DELETE then + file.Delete(path .. ".png") + file.Delete(path .. ".txt") + elseif save == dvd.POPUPWINDOW.GENERATE then + GenerateWaypoints(ply) + end end) net.Receive("Decent Vehicle: Change serverside value", function(_, ply) - if not ply:IsAdmin() then return end - local cvar = GetConVar(net.ReadString()) - if not cvar then return end - cvar:SetString(net.ReadString()) + if not ply:IsAdmin() then return end + local cvar = GetConVar(net.ReadString()) + if not cvar then return end + cvar:SetString(net.ReadString()) end) -- Gets a table that contains all waypoints information. -- Returns: --- table save | A table for saving waypoints. +-- table save | A table for saving waypoints. function dvd.GetSaveTable() - local TrafficLights = {} - local save = {TrafficLights = {}} - for i, w in ipairs(dvd.Waypoints) do - save[i] = table.Copy(w) - save[i].TrafficLight = nil - if IsValid(w.TrafficLight) and w.TrafficLight.IsDVTrafficLight then - local index = w.TrafficLight:EntIndex() - TrafficLights[index] = table.ForceInsert(TrafficLights[index], i) - end - end - - for i, w in pairs(TrafficLights) do - local t = Entity(i) - if not IsValid(t) then continue end - if not t.IsDVTrafficLight then continue end - table.insert(save.TrafficLights, { - Waypoints = w, - Pattern = t:GetPattern(), - Pos = t:GetPos(), - Ang = t:GetAngles(), - ClassName = t:GetClass(), - }) - end - - save.DriveSide = dvd.DriveSide - save.ForceHeadlights = dvd.CVars.ForceHeadlights:GetBool() -- Added from version 1.0.7 - hook.Run("Decent Vehicle: OnSaveWaypoints", save) - return save + local TrafficLights = {} + local save = {TrafficLights = {}} + for i, w in ipairs(dvd.Waypoints) do + save[i] = table.Copy(w) + save[i].TrafficLight = nil + if IsValid(w.TrafficLight) and w.TrafficLight.IsDVTrafficLight then + local index = w.TrafficLight:EntIndex() + TrafficLights[index] = table.ForceInsert(TrafficLights[index], i) + end + end + + for i, w in pairs(TrafficLights) do + local t = Entity(i) + if not IsValid(t) then continue end + if not t.IsDVTrafficLight then continue end + table.insert(save.TrafficLights, { + Waypoints = w, + Pattern = t:GetPattern(), + Pos = t:GetPos(), + Ang = t:GetAngles(), + ClassName = t:GetClass(), + }) + end + + save.DriveSide = dvd.DriveSide + save.ForceHeadlights = dvd.CVars.ForceHeadlights:GetBool() -- Added from version 1.0.7 + hook.Run("Decent Vehicle: OnSaveWaypoints", save) + return save end -- Creates a new waypoint at given position. -- The new ID is always #dvd.Waypoints. -- Argument: --- Vector pos | The position of new waypoint. +-- Vector pos | The position of new waypoint. -- Returns: --- table waypoint | Created waypoint. +-- table waypoint | Created waypoint. function dvd.AddWaypoint(pos) - local waypoint = {Target = pos, Neighbors = {}} - table.insert(dvd.Waypoints, waypoint) - if player.GetCount() > 0 then - net.Start "Decent Vehicle: Add a waypoint" - net.WriteVector(pos) - net.Broadcast() - end - - return waypoint + local waypoint = {Target = pos, Neighbors = {}} + table.insert(dvd.Waypoints, waypoint) + if player.GetCount() > 0 then + net.Start "Decent Vehicle: Add a waypoint" + net.WriteVector(pos) + net.Broadcast() + end + + return waypoint end -- Removes a waypoint by ID. -- Argument: --- number id | An unsigned number to remove. +-- number id | An unsigned number to remove. function dvd.RemoveWaypoint(id) - if isvector(id) then id = select(2, dvd.GetNearestWaypoint(id)) end - if not id then return end - for _, w in ipairs(dvd.Waypoints) do - local Neighbors = {} - for _, n in ipairs(w.Neighbors) do - if n > id then - table.insert(Neighbors, n - 1) - elseif n < id then - table.insert(Neighbors, n) - end - end - - w.Neighbors = Neighbors - end - - table.remove(dvd.Waypoints, id) - for m in pairs(dvd.WireManagers) do - if IsValid(m) and m:GetNWInt "WaypointID" ~= id then continue end - m:UnlinkEnt() - break - end - - if player.GetCount() == 0 then return end - net.Start "Decent Vehicle: Remove a waypoint" - net.WriteUInt(id, 24) - net.Broadcast() + if isvector(id) then id = select(2, dvd.GetNearestWaypoint(id)) end + if not id then return end + for _, w in ipairs(dvd.Waypoints) do + local Neighbors = {} + for _, n in ipairs(w.Neighbors) do + if n > id then + table.insert(Neighbors, n - 1) + elseif n < id then + table.insert(Neighbors, n) + end + end + + w.Neighbors = Neighbors + end + + table.remove(dvd.Waypoints, id) + for m in pairs(dvd.WireManagers) do + if IsValid(m) and m:GetNWInt "WaypointID" ~= id then continue end + m:UnlinkEnt() + break + end + + if player.GetCount() == 0 then return end + net.Start "Decent Vehicle: Remove a waypoint" + net.WriteUInt(id, 24) + net.Broadcast() end -- Undo function that removes the most recent waypoint. function dvd.UndoWaypoint(undoinfo) - for i, w in SortedPairsByMemberValue(dvd.Waypoints, "Time", true) do - if undoinfo.Owner == w.Owner then - dvd.RemoveWaypoint(i) - return - end - end + for i, w in SortedPairsByMemberValue(dvd.Waypoints, "Time", true) do + if undoinfo.Owner == w.Owner then + dvd.RemoveWaypoint(i) + return + end + end end -- Gets all fuel station points in the map. -- Returns: --- table fuelstations | A sequential table contains all fuel stations. --- table fuelIDs | A sequential table contains all IDs of fuel station. +-- table fuelstations | A sequential table contains all fuel stations. +-- table fuelIDs | A sequential table contains all IDs of fuel station. function dvd.GetFuelStations() - local fuelstations, fuelIDs = {}, {} - for i, w in ipairs(dvd.Waypoints) do - if not w.FuelStation then continue end - table.insert(fuelstations, w) - table.insert(fuelIDs, i) - end - - return fuelstations, fuelIDs + local fuelstations, fuelIDs = {}, {} + for i, w in ipairs(dvd.Waypoints) do + if not w.FuelStation then continue end + table.insert(fuelstations, w) + table.insert(fuelIDs, i) + end + + return fuelstations, fuelIDs end -- Adds a link between two waypoints. -- The link is one-way, one to another. -- Arguments: --- number from | The waypoint ID the link starts from. --- number to | The waypoint ID connected to. +-- number from | The waypoint ID the link starts from. +-- number to | The waypoint ID connected to. function dvd.AddNeighbor(from, to) - local w = dvd.Waypoints[from] - if not w then return end - table.insert(w.Neighbors, to) - if player.GetCount() == 0 then return end - net.Start "Decent Vehicle: Add a neighbor" - net.WriteUInt(from, 24) - net.WriteUInt(to, 24) - net.Broadcast() + local w = dvd.Waypoints[from] + if not w then return end + table.insert(w.Neighbors, to) + if player.GetCount() == 0 then return end + net.Start "Decent Vehicle: Add a neighbor" + net.WriteUInt(from, 24) + net.WriteUInt(to, 24) + net.Broadcast() end -- Removes an existing link between two waypoints. -- Does nothing if the given link is not found. -- Arguments: --- number from | The waypoint ID the link starts from. --- number to | The waypoint ID connected to. +-- number from | The waypoint ID the link starts from. +-- number to | The waypoint ID connected to. function dvd.RemoveNeighbor(from, to) - local w = dvd.Waypoints[from] - if not w then return end - table.RemoveByValue(w.Neighbors, to) - if player.GetCount() == 0 then return end - net.Start "Decent Vehicle: Remove a neighbor" - net.WriteUInt(from, 24) - net.WriteUInt(to, 24) - net.Broadcast() + local w = dvd.Waypoints[from] + if not w then return end + table.RemoveByValue(w.Neighbors, to) + if player.GetCount() == 0 then return end + net.Start "Decent Vehicle: Remove a neighbor" + net.WriteUInt(from, 24) + net.WriteUInt(to, 24) + net.Broadcast() end -- Checks if the given waypoint is available for the specified group. -- Arguments: --- number id | The waypoint ID. --- number group | Waypoint group to check. +-- number id | The waypoint ID. +-- number group | Waypoint group to check. function dvd.WaypointAvailable(id, group) - local waypoint = dvd.Waypoints[id] - if not waypoint then return end - return waypoint.Group == 0 or waypoint.Group == group + local waypoint = dvd.Waypoints[id] + if not waypoint then return end + return waypoint.Group == 0 or waypoint.Group == group end -- Adds a link between a waypoint and a traffic light entity. -- Arguments: --- number id | The waypoint ID. --- Entity traffic | The traffic light entity. Giving nil to remove the link. +-- number id | The waypoint ID. +-- Entity traffic | The traffic light entity. Giving nil to remove the link. function dvd.AddTrafficLight(id, traffic) - local waypoint = dvd.Waypoints[id] - if not waypoint then return end - if not IsValid(traffic) then traffic = nil end - if traffic then - if not traffic.IsDVTrafficLight then return end - if waypoint.TrafficLight ~= traffic then - table.insert(traffic.Waypoints, id) - if IsValid(waypoint.TrafficLight) then - table.RemoveByValue(waypoint.TrafficLight.Waypoints, id) - end - else - table.RemoveByValue(traffic.Waypoints, id) - traffic = nil - end - end - - waypoint.TrafficLight = traffic - if player.GetCount() == 0 then return end - net.Start "Decent Vehicle: Traffic light" - net.WriteUInt(id, 24) - net.WriteEntity(traffic or NULL) - net.Broadcast() + local waypoint = dvd.Waypoints[id] + if not waypoint then return end + if not IsValid(traffic) then traffic = nil end + if traffic then + if not traffic.IsDVTrafficLight then return end + if waypoint.TrafficLight ~= traffic then + table.insert(traffic.Waypoints, id) + if IsValid(waypoint.TrafficLight) then + table.RemoveByValue(waypoint.TrafficLight.Waypoints, id) + end + else + table.RemoveByValue(traffic.Waypoints, id) + traffic = nil + end + end + + waypoint.TrafficLight = traffic + if player.GetCount() == 0 then return end + net.Start "Decent Vehicle: Traffic light" + net.WriteUInt(id, 24) + net.WriteEntity(traffic or NULL) + net.Broadcast() end -- Gets a waypoint connected from the given randomly. -- Argument: --- table waypoint | The given waypoint. --- function filter | If specified, removes waypoints which make it return false. +-- table waypoint | The given waypoint. +-- function filter | If specified, removes waypoints which make it return false. -- Returns: -- table waypoint | The connected waypoint. function dvd.GetRandomNeighbor(waypoint, filter) - if not waypoint.Neighbors then return end + if not waypoint.Neighbors then return end - local suggestion = {} - for i, n in ipairs(waypoint.Neighbors) do - local w = dvd.Waypoints[n] - if not w then continue end - if not (isfunction(filter) and filter(waypoint, n)) then continue end - table.insert(suggestion, w) - end + local suggestion = {} + for i, n in ipairs(waypoint.Neighbors) do + local w = dvd.Waypoints[n] + if not w then continue end + if not (isfunction(filter) and filter(waypoint, n)) then continue end + table.insert(suggestion, w) + end - return suggestion[math.random(#suggestion)] + return suggestion[math.random(#suggestion)] end -- Retrives a table of waypoints that represents the route -- from start to one of the destination in endpos. -- Using A* pathfinding algorithm. -- Arguments: --- number start | The beginning waypoint ID. --- table endpos | A table of destination waypoint IDs. {[ID] = true} --- number group | Optional, specify a waypoint group here. +-- number start | The beginning waypoint ID. +-- table endpos | A table of destination waypoint IDs. {[ID] = true} +-- number group | Optional, specify a waypoint group here. -- Returns: --- table route | List of waypoints. start is the last, endpos is the first. +-- table route | List of waypoints. start is the last, endpos is the first. function dvd.GetRoute(start, endpos, group) - if not (isnumber(start) and istable(endpos)) then return end - group = group or 0 - - local nodes, opens = {}, {} - local function CreateNode(id) - nodes[id] = { - estimate = 0, - closed = nil, - cost = 0, - id = id, - parent = nil, - score = 0, - } - - return nodes[id] - end - - local function EstimateCost(node) - local w = dvd.Waypoints[node.id] - local cost = math.huge - if not w then return cost end - - node = w.Target - for id in pairs(endpos) do - local wi = dvd.Waypoints[id] - if not wi then continue end - cost = math.min(cost, node:Distance(wi.Target)) - end - - return cost - end - - local function AddToOpenList(node, parent) - if parent then - local nodepos = dvd.Waypoints[node.id].Target - local parentpos = dvd.Waypoints[parent.id].Target - local cost = parentpos:Distance(nodepos) - local grandpa = parent.parent - if grandpa then -- Angle between waypoints is considered as cost - local gppos = dvd.Waypoints[grandpa.id].Target - cost = cost * (2 - dvd.GetAng3(gppos, parentpos, nodepos)) - end - - node.cost = parent.cost + cost - end - - node.closed = false - node.estimate = EstimateCost(node) - node.parent = parent - node.score = node.estimate + node.cost - - -- Open list is binary heap - table.insert(opens, node.id) - local i = #opens - local p = math.floor(i / 2) - while i > 0 and p > 0 and nodes[opens[i]].score < nodes[opens[p]].score do - opens[i], opens[p] = opens[p], opens[i] - i, p = p, math.floor(p / 2) - end - end - - start = CreateNode(start) - for id in pairs(endpos) do - endpos[id] = CreateNode(id) - end - - AddToOpenList(start) - while #opens > 0 do - local current = opens[1] -- Pop a node which has minimum cost. - opens[1] = opens[#opens] - opens[#opens] = nil - - local i = 1 -- Down-heap on the open list - while i <= #opens do - local c = i * 2 - if not opens[c] then break end - c = c + (opens[c + 1] and nodes[opens[c]].score > nodes[opens[c + 1]].score and 1 or 0) - if nodes[opens[c]].score >= nodes[opens[i]].score then break end - opens[i], opens[c] = opens[c], opens[i] - i = c - end - - if nodes[current].closed then continue end - if endpos[current] then - current = nodes[current] - local route = {dvd.Waypoints[current.id]} - while current.parent do - debugoverlay.Sphere(dvd.Waypoints[current.id].Target, 30, 5, Color(0, 255, 0)) - debugoverlay.SweptBox(dvd.Waypoints[current.parent.id].Target, dvd.Waypoints[current.id].Target, Vector(-10, -10, -10), Vector(10, 10, 10), angle_zero, 5, Color(0, 255, 0)) - table.insert(route, dvd.Waypoints[current.id]) - current = current.parent - end - - return route - end - - nodes[current].closed = true - for i, n in ipairs(dvd.Waypoints[nodes[current].id].Neighbors) do - if nodes[n] and nodes[n].closed ~= nil then continue end - if not dvd.WaypointAvailable(n, group) then continue end - AddToOpenList(nodes[n] or CreateNode(n), nodes[current]) - end - end + if not (isnumber(start) and istable(endpos)) then return end + group = group or 0 + + local nodes, opens = {}, {} + local function CreateNode(id) + nodes[id] = { + estimate = 0, + closed = nil, + cost = 0, + id = id, + parent = nil, + score = 0, + } + + return nodes[id] + end + + local function EstimateCost(node) + local w = dvd.Waypoints[node.id] + local cost = math.huge + if not w then return cost end + + node = w.Target + for id in pairs(endpos) do + local wi = dvd.Waypoints[id] + if not wi then continue end + cost = math.min(cost, node:Distance(wi.Target)) + end + + return cost + end + + local function AddToOpenList(node, parent) + if parent then + local nodepos = dvd.Waypoints[node.id].Target + local parentpos = dvd.Waypoints[parent.id].Target + local cost = parentpos:Distance(nodepos) + local grandpa = parent.parent + if grandpa then -- Angle between waypoints is considered as cost + local gppos = dvd.Waypoints[grandpa.id].Target + cost = cost * (2 - dvd.GetAng3(gppos, parentpos, nodepos)) + end + + node.cost = parent.cost + cost + end + + node.closed = false + node.estimate = EstimateCost(node) + node.parent = parent + node.score = node.estimate + node.cost + + -- Open list is binary heap + table.insert(opens, node.id) + local i = #opens + local p = math.floor(i / 2) + while i > 0 and p > 0 and nodes[opens[i]].score < nodes[opens[p]].score do + opens[i], opens[p] = opens[p], opens[i] + i, p = p, math.floor(p / 2) + end + end + + start = CreateNode(start) + for id in pairs(endpos) do + endpos[id] = CreateNode(id) + end + + AddToOpenList(start) + while #opens > 0 do + local current = opens[1] -- Pop a node which has minimum cost. + opens[1] = opens[#opens] + opens[#opens] = nil + + local i = 1 -- Down-heap on the open list + while i <= #opens do + local c = i * 2 + if not opens[c] then break end + c = c + (opens[c + 1] and nodes[opens[c]].score > nodes[opens[c + 1]].score and 1 or 0) + if nodes[opens[c]].score >= nodes[opens[i]].score then break end + opens[i], opens[c] = opens[c], opens[i] + i = c + end + + if nodes[current].closed then continue end + if endpos[current] then + current = nodes[current] + local route = {dvd.Waypoints[current.id]} + while current.parent do + debugoverlay.Sphere(dvd.Waypoints[current.id].Target, 30, 5, Color(0, 255, 0)) + debugoverlay.SweptBox(dvd.Waypoints[current.parent.id].Target, dvd.Waypoints[current.id].Target, Vector(-10, -10, -10), Vector(10, 10, 10), angle_zero, 5, Color(0, 255, 0)) + table.insert(route, dvd.Waypoints[current.id]) + current = current.parent + end + + return route + end + + nodes[current].closed = true + for i, n in ipairs(dvd.Waypoints[nodes[current].id].Neighbors) do + if nodes[n] and nodes[n].closed ~= nil then continue end + if not dvd.WaypointAvailable(n, group) then continue end + AddToOpenList(nodes[n] or CreateNode(n), nodes[current]) + end + end end -- Retrives a table of waypoints that represents the route -- from start to one of the destination in endpos. -- Arguments: --- Vector start | The beginning position. --- table endpos | A table of Vectors that represent destinations. Can also be a Vector. --- number group | Optional, specify a waypoint group here. +-- Vector start | The beginning position. +-- table endpos | A table of Vectors that represent destinations. Can also be a Vector. +-- number group | Optional, specify a waypoint group here. -- Returns: --- table route | The same as returning value of dvd.GetRoute() +-- table route | The same as returning value of dvd.GetRoute() function dvd.GetRouteVector(start, endpos, group) - if isvector(endpos) then endpos = {endpos} end - if not (isvector(start) and istable(endpos)) then return end - local endpostable = {} - for _, p in ipairs(endpos) do - local id = select(2, dvd.GetNearestWaypoint(p)) - if not id then continue end - endpostable[id] = true - end - - return dvd.GetRoute(select(2, dvd.GetNearestWaypoint(start)), endpostable, group) + if isvector(endpos) then endpos = {endpos} end + if not (isvector(start) and istable(endpos)) then return end + local endpostable = {} + for _, p in ipairs(endpos) do + local id = select(2, dvd.GetNearestWaypoint(p)) + if not id then continue end + endpostable[id] = true + end + + return dvd.GetRoute(select(2, dvd.GetNearestWaypoint(start)), endpostable, group) end hook.Run "Decent Vehicle: PostInitialize" diff --git a/lua/autorun/server/sv_decentvehicle_taxi.lua b/lua/autorun/server/sv_decentvehicle_taxi.lua index 457429e..c8b2421 100644 --- a/lua/autorun/server/sv_decentvehicle_taxi.lua +++ b/lua/autorun/server/sv_decentvehicle_taxi.lua @@ -10,70 +10,70 @@ local UnitPrice = dvd.CVars.Taxi.UnitPrice dvd.TaxiDrivers = dvd.TaxiDrivers or {} dvd.TaxiStations = dvd.TaxiStations or {} local function GetDriver(seat) - if seat.DecentVehicle then return seat.DecentVehicle end - if seat.IsScarSeat then - seat = seat.EntOwner - elseif IsValid(seat:GetParent()) then - seat = seat:GetParent() - else - for e in pairs(constraint.GetAllConstrainedEntities(seat)) do - if e.DecentVehicle then - seat = e - break - end - end - end - - if not (IsValid(seat) and seat:IsVehicle()) then return end - return seat.DecentVehicle + if seat.DecentVehicle then return seat.DecentVehicle end + if seat.IsScarSeat then + seat = seat.EntOwner + elseif IsValid(seat:GetParent()) then + seat = seat:GetParent() + else + for e in pairs(constraint.GetAllConstrainedEntities(seat)) do + if e.DecentVehicle then + seat = e + break + end + end + end + + if not (IsValid(seat) and seat:IsVehicle()) then return end + return seat.DecentVehicle end local function GetNearestTaxiDriver(pos) - local mindistance, taxidriver = math.huge - for driver in pairs(dvd.TaxiDrivers) do - local distance = driver:GetPos():DistToSqr(pos) - if not (IsValid(driver) and driver.IsDVTaxiDriver) then continue end - if not (driver.Coming or driver.Transporting) and distance < mindistance then - mindistance, taxidriver = distance, driver - end - end - - return taxidriver + local mindistance, taxidriver = math.huge + for driver in pairs(dvd.TaxiDrivers) do + local distance = driver:GetPos():DistToSqr(pos) + if not (IsValid(driver) and driver.IsDVTaxiDriver) then continue end + if not (driver.Coming or driver.Transporting) and distance < mindistance then + mindistance, taxidriver = distance, driver + end + end + + return taxidriver end local function StartGoing(ply, ent, dv) - local route = dvd.GetRouteVector(ent:GetPos(), dv.Destinations) - if not route or #route == 0 then return end - - local distance = 0 - for i, w in ipairs(route) do - distance = distance + w.Target:Distance(route[math.max(i - 1, 1)].Target) - end - - local unitprice = UnitPrice:GetInt() or 5 - local fare = math.max(unitprice, math.Round(distance / dvd.KmToHU * unitprice, 0)) - if engine.ActiveGamemode() == "darkrp" then - if ply.DarkRPVars.money < fare then - net.Start "Decent Vehicle: The taxi driver says something localized" - net.WriteUInt(7, 4) -- The taxi found its passenger does not have enough money - net.Send(ply) - dv.Caller = nil - dv.Coming = false - dv.Transporting = false - dv.WaitForCaller = nil - return - end - end - - dv.Coming = false - dv.Fare = fare - dv.Transporting = true - dv.WaitForCaller = nil - dv.WaypointList = route - - net.Start "Decent Vehicle: The taxi driver says something localized" - net.WriteUInt(3, 4) -- The taxi started running to its destination - net.Send(ply) + local route = dvd.GetRouteVector(ent:GetPos(), dv.Destinations) + if not route or #route == 0 then return end + + local distance = 0 + for i, w in ipairs(route) do + distance = distance + w.Target:Distance(route[math.max(i - 1, 1)].Target) + end + + local unitprice = UnitPrice:GetInt() or 5 + local fare = math.max(unitprice, math.Round(distance / dvd.KmToHU * unitprice, 0)) + if engine.ActiveGamemode() == "darkrp" then + if ply.DarkRPVars.money < fare then + net.Start "Decent Vehicle: The taxi driver says something localized" + net.WriteUInt(7, 4) -- The taxi found its passenger does not have enough money + net.Send(ply) + dv.Caller = nil + dv.Coming = false + dv.Transporting = false + dv.WaitForCaller = nil + return + end + end + + dv.Coming = false + dv.Fare = fare + dv.Transporting = true + dv.WaitForCaller = nil + dv.WaypointList = route + + net.Start "Decent Vehicle: The taxi driver says something localized" + net.WriteUInt(3, 4) -- The taxi started running to its destination + net.Send(ply) end util.AddNetworkString "Decent Vehicle: Open a taxi menu" @@ -81,130 +81,130 @@ util.AddNetworkString "Decent Vehicle: Call a taxi" util.AddNetworkString "Decent Vehicle: Exit vehicle" util.AddNetworkString "Decent Vehicle: The taxi driver says something localized" net.Receive("Decent Vehicle: Call a taxi", function(_, ply) - local destination = net.ReadString() - local ent = net.ReadEntity() - local beginning = ent.IsDVTaxiStation and ent:GetStationName() - local dv = ent.IsDVTaxiDriver and ent or GetNearestTaxiDriver(ply:GetPos()) - - if not dv then - net.Start "Decent Vehicle: The taxi driver says something localized" - net.WriteUInt(8, 4) -- No taxi driver in the map - net.Send(ply) - return - end - - if dv.Coming or dv.Transporting then return end - local cometo, goingto = {}, {} - for st in pairs(dvd.TaxiStations) do - if not (IsValid(st) and st.IsDVTaxiStation) then continue end - local name = st:GetStationName() - if name == beginning then - table.insert(cometo, st:GetPos()) - elseif name == destination then - table.insert(goingto, st:GetPos()) - end - end - - local route = dvd.GetRouteVector(dv.Waypoint and dv.Waypoint.Target or dv:GetPos(), cometo) - if beginning and (not route or #route == 0) then return end - - dv.Destinations = goingto - if beginning then - dv.WaypointList = route - dv.Waypoint, dv.NextWaypoint = nil - dv.Caller = ply - dv.Coming = true - dv.Transporting = false - net.Start "Decent Vehicle: The taxi driver says something localized" - net.WriteUInt(0, 4) -- The taxi is called by its passenger - net.WriteEntity(dv) - net.Send(ply) - elseif ent.IsDVTaxiDriver then - StartGoing(ply, ent, dv) - end + local destination = net.ReadString() + local ent = net.ReadEntity() + local beginning = ent.IsDVTaxiStation and ent:GetStationName() + local dv = ent.IsDVTaxiDriver and ent or GetNearestTaxiDriver(ply:GetPos()) + + if not dv then + net.Start "Decent Vehicle: The taxi driver says something localized" + net.WriteUInt(8, 4) -- No taxi driver in the map + net.Send(ply) + return + end + + if dv.Coming or dv.Transporting then return end + local cometo, goingto = {}, {} + for st in pairs(dvd.TaxiStations) do + if not (IsValid(st) and st.IsDVTaxiStation) then continue end + local name = st:GetStationName() + if name == beginning then + table.insert(cometo, st:GetPos()) + elseif name == destination then + table.insert(goingto, st:GetPos()) + end + end + + local route = dvd.GetRouteVector(dv.Waypoint and dv.Waypoint.Target or dv:GetPos(), cometo) + if beginning and (not route or #route == 0) then return end + + dv.Destinations = goingto + if beginning then + dv.WaypointList = route + dv.Waypoint, dv.NextWaypoint = nil + dv.Caller = ply + dv.Coming = true + dv.Transporting = false + net.Start "Decent Vehicle: The taxi driver says something localized" + net.WriteUInt(0, 4) -- The taxi is called by its passenger + net.WriteEntity(dv) + net.Send(ply) + elseif ent.IsDVTaxiDriver then + StartGoing(ply, ent, dv) + end end) net.Receive("Decent Vehicle: Exit vehicle", function(_, ply) - local dv = net.ReadEntity() - local seat = ply:GetVehicle() - if not IsValid(seat) then return end - if dv ~= GetDriver(seat) then return end - ply:ExitVehicle() + local dv = net.ReadEntity() + local seat = ply:GetVehicle() + if not IsValid(seat) then return end + if dv ~= GetDriver(seat) then return end + ply:ExitVehicle() end) hook.Add("Decent Vehicle: OnSaveWaypoints", "Save taxi stations", function(save) - save.TaxiStations = {} - for t in pairs(dvd.TaxiStations) do - if not (IsValid(t) and t.IsDVTaxiStation) then continue end - table.insert(save.TaxiStations, { - Name = t:GetStationName(), - Pos = t:GetPos(), - Ang = t:GetAngles(), - ClassName = t:GetClass(), - }) - end + save.TaxiStations = {} + for t in pairs(dvd.TaxiStations) do + if not (IsValid(t) and t.IsDVTaxiStation) then continue end + table.insert(save.TaxiStations, { + Name = t:GetStationName(), + Pos = t:GetPos(), + Ang = t:GetAngles(), + ClassName = t:GetClass(), + }) + end end) hook.Add("Decent Vehicle: OnLoadWaypoints", "Load taxi stations", function(source) - if not source.TaxiStations then return end - for i, t in ipairs(source.TaxiStations) do - local station = ents.Create(t.ClassName) - if not IsValid(station) then continue end - station:SetPos(t.Pos) - station:SetAngles(t.Ang) - station:Spawn() - station:SetStationName(t.Name) - - local p = station:GetPhysicsObject() - if IsValid(p) then p:Sleep() end - end + if not source.TaxiStations then return end + for i, t in ipairs(source.TaxiStations) do + local station = ents.Create(t.ClassName) + if not IsValid(station) then continue end + station:SetPos(t.Pos) + station:SetAngles(t.Ang) + station:Spawn() + station:SetStationName(t.Name) + + local p = station:GetPhysicsObject() + if IsValid(p) then p:Sleep() end + end end) hook.Add("Decent Vehicle: OnReachedWaypoint", "Taxi reaches", function(self) - if not self.IsDVTaxiDriver then return end - if not istable(self.WaypointList) or #self.WaypointList > 0 then return end - if not (IsValid(self.Caller) and self.Caller:IsPlayer()) then return end - if self.Coming then - self.WaitForCaller = CurTime() + math.random(30, 50) - net.Start "Decent Vehicle: The taxi driver says something localized" - net.WriteUInt(2, 4) -- The taxi arrived at where its passenger is - net.Send(self.Caller) - elseif self.Transporting then - self.WaitForCaller = true - net.Start "Decent Vehicle: The taxi driver says something localized" - net.WriteUInt(4, 4) -- The taxi arrived at its destination - net.Send(self.Caller) - end + if not self.IsDVTaxiDriver then return end + if not istable(self.WaypointList) or #self.WaypointList > 0 then return end + if not (IsValid(self.Caller) and self.Caller:IsPlayer()) then return end + if self.Coming then + self.WaitForCaller = CurTime() + math.random(30, 50) + net.Start "Decent Vehicle: The taxi driver says something localized" + net.WriteUInt(2, 4) -- The taxi arrived at where its passenger is + net.Send(self.Caller) + elseif self.Transporting then + self.WaitForCaller = true + net.Start "Decent Vehicle: The taxi driver says something localized" + net.WriteUInt(4, 4) -- The taxi arrived at its destination + net.Send(self.Caller) + end end) hook.Add("PlayerEnteredVehicle", "Decent Vehicle: Player entered a taxi", function(ply, seat, role) - local dv = GetDriver(seat) - if not (dv and dv.IsDVTaxiDriver) then return end - if not dv.Caller then - net.Start "Decent Vehicle: The taxi driver says something localized" - net.WriteUInt(1, 4) -- A new passenger got in the taxi - net.Send(ply) - net.Start "Decent Vehicle: Open a taxi menu" - net.WriteEntity(dv) - net.Send(ply) - dv.Caller = ply - dv.WaitForCaller = true - elseif ply == dv.Caller then - if not isnumber(dv.ClearMemory) then - StartGoing(ply, seat, dv) - end - - dv.ClearMemory = nil - elseif dv.WaitForCaller then - net.Start "Decent Vehicle: The taxi driver says something localized" - net.WriteUInt(6, 4) -- The taxi always has another passenger - net.Send(ply) - end + local dv = GetDriver(seat) + if not (dv and dv.IsDVTaxiDriver) then return end + if not dv.Caller then + net.Start "Decent Vehicle: The taxi driver says something localized" + net.WriteUInt(1, 4) -- A new passenger got in the taxi + net.Send(ply) + net.Start "Decent Vehicle: Open a taxi menu" + net.WriteEntity(dv) + net.Send(ply) + dv.Caller = ply + dv.WaitForCaller = true + elseif ply == dv.Caller then + if not isnumber(dv.ClearMemory) then + StartGoing(ply, seat, dv) + end + + dv.ClearMemory = nil + elseif dv.WaitForCaller then + net.Start "Decent Vehicle: The taxi driver says something localized" + net.WriteUInt(6, 4) -- The taxi always has another passenger + net.Send(ply) + end end) hook.Add("PlayerLeaveVehicle", "Decent Vehicle: Player left a taxi", function(ply, seat) - local dv = GetDriver(seat) - if not (dv and dv.IsDVTaxiDriver) then return end - if ply ~= dv.Caller then return end - dv.ClearMemory = CurTime() + 0.1 + local dv = GetDriver(seat) + if not (dv and dv.IsDVTaxiDriver) then return end + if ply ~= dv.Caller then return end + dv.ClearMemory = CurTime() + 0.1 end) diff --git a/lua/decentvehicle/base/en.lua b/lua/decentvehicle/base/en.lua index 27409ab..ea2d251 100644 --- a/lua/decentvehicle/base/en.lua +++ b/lua/decentvehicle/base/en.lua @@ -4,108 +4,108 @@ -- and DangerKiddy(DK) (https://steamcommunity.com/profiles/76561198132964487/). return { - CVars = { - AutoLoad = "Decent Vehicle: Whether or not Decent Vehicle automatically loads waypoints on startup.", - DetectionRange = "Decent Vehicle: A vehicle within this distance will drive automatically.", - DetectionRangeELS = "Decent Vehicle: Detection range of finding cars with ELS to give way.", - DriveSide = [[Decent Vehicle: Determines which side of road Decent Vehicles think. + CVars = { + AutoLoad = "Decent Vehicle: Whether or not Decent Vehicle automatically loads waypoints on startup.", + DetectionRange = "Decent Vehicle: A vehicle within this distance will drive automatically.", + DetectionRangeELS = "Decent Vehicle: Detection range of finding cars with ELS to give way.", + DriveSide = [[Decent Vehicle: Determines which side of road Decent Vehicles think. 0: Right (Europe, America, etc.) 1: Left (UK, Australia, etc.)]], - ForceHeadlights = "Decent Vehicle: Forces Decent Vehicle to enable headlights.", - LockVehicle = "Decent Vehicle: Whether or not Decent Vehicle prevents players from getting in.", - ShouldGoToRefuel = "Decent Vehicle: 1: Go to a fuel station to refuel. 0: Refuel automatically.", - StopInfrontofPerson = "Decent Vehicle: Whether or not Decent Vehicle stops when it sees something in front of it.", - TimeToStopEmergency = "Decent Vehicle: Time to turn off hazard lights in seconds.", - TurnOnLights = [[Decent Vehicle: The level of using lights. + ForceHeadlights = "Decent Vehicle: Forces Decent Vehicle to enable headlights.", + LockVehicle = "Decent Vehicle: Whether or not Decent Vehicle prevents players from getting in.", + ShouldGoToRefuel = "Decent Vehicle: 1: Go to a fuel station to refuel. 0: Refuel automatically.", + StopInfrontofPerson = "Decent Vehicle: Whether or not Decent Vehicle stops when it sees something in front of it.", + TimeToStopEmergency = "Decent Vehicle: Time to turn off hazard lights in seconds.", + TurnOnLights = [[Decent Vehicle: The level of using lights. 0: Disabled 1: Only use running lights 2: Use running lights and headlights 3: Use all lights]], - }, - DeletedWaypoints = "Decent Vehicle: Waypoints are deleted!", - Errors = { - AttachmentNotFound = "Decent Vehicle: attachment vehicle_feet_passenger0 is not found!", - WaypointNotFound = "Decent Vehicle: Waypoint is not found!", - }, - GeneratedWaypoints = "Decent Vehicle: Waypoints are generated!", - LoadedWaypoints = "Decent Vehicle: Waypoints are restored!", - OldVersionNotify = "Decent Vehicle: This is an old version. Check for updates!", - OnDelete = "You are about to DELETE the waypoints.", - OnGenerate = "You are about to GENERATE the waypoints.", - OnLoad = "You are about to LOAD the waypoints.", - OnSave = "You are about to SAVE the waypoints.", - SavedWaypoints = "Decent Vehicle: Waypoints are saved!", - SaveLoad_Cancel = "Cancel", - SaveLoad_OK = "OK", - Tools = { - AlwaysDrawWaypoints = "Always draw waypoints", - AutoLoad = "Load waypoints on startup", - AutoLoadHelp = "If checked, Decent Vehicle will automatically load waypoints when the map is loaded.", - Bidirectional = "Bi-directional link", - BidirectionalHelp = "Connect bi-directional link automatically.", - Category = "GreatZenkakuMan's tools", - Delete = "Delete waypoints", - Description = "Create your own routes for vehicles!", - DescriptionInMenu = "Create routes for Decent Vehicles.", - DetectionRange = "Detection range for spawning", - DetectionRangeELS = "Detection range for finding cars with ELS", - DrawDistance = "Draw distance", - DrawDistanceHelp = "The maximum distance to draw waypoints.", - DrawWaypoints = "Draw waypoints", - DriveSide = "Is left side of the road", - ForceHeadlights = "Force headlights", - ForceHeadlightsHelp = "Forces Decent Vehicle to enable headlights.", - FuelStation = "Fuel station", - FuelStationHelp = "Decent Vehicles will go here to refuel its car.", - Generate = "Generate waypoints", - Instructions = "Select a waypoint or a traffic light to link. Select a vehicle driven by a Decent Vehicle to assign its waypoint group.", - Left = { - "Create a new waypoint.", - "Select another waypoint you want to link to. Select the same waypoint to remove it.", - }, - LightLevel = { - All = "Full lights", - Headlights = "Running lights and headlights", - None = "No light", - Running = "Only running lights", - Title = "Light level", - }, - LockVehicle = "Lock vehicle", - LockVehicleHelp = "If checked, Decent Vehicle prevents other players from getting in.", - MaxSpeed = "Max speed [km/h]", - Name = "Decent Vehicle Waypoint Tool", - PrintName = "Decent Vehicle Waypoint Tool", - Restore = "Restore waypoints", - Right = {"Update waypoint."}, - Save = "Save waypoints", - ServerSettings = "Server settings", - ShouldGoToRefuel = "Should go finding a fuel station", - ShowInfo = { - FuelStation = "Is fuel station: ", - Group = "Group: ", - ID = "ID: ", - SpeedLimit = "Speed limit [km/h]: ", - UseTurnLights = "Use turn lights: ", - WaitUntilNext = "Wait until next [seconds]: ", - }, - ShowUpdates = "Notify the latest updates", - ShowUpdatesHelp = "If checked, some notifications are shown when this addon is updated.", - StopInfrontofPerson = "Stop when it sees something", - StopInfrontofPersonHelp = "If checked, Decent Vehicle stops running if it sees something in front of it.", - UpdateRadius = "Update radius", - UpdateRadiusHelp = "Waypoints in this radius will be updated at a time when you press E + Right click.", - UseTurnLights = "Use turn signals", - UseTurnLightsHelp = "Decent Vehicles will use turn signals when they go to the waypoint.", - WaitTime = "Wait time [seconds]", - WaitTimeHelp = "After Decent Vehicles reached the waypoint, they wait for this seconds.", - WaypointGroup = "Waypoint group", - WaypointGroupHelp = [[You can force Decent Vehicles to run along specified group of waypoints. + }, + DeletedWaypoints = "Decent Vehicle: Waypoints are deleted!", + Errors = { + AttachmentNotFound = "Decent Vehicle: attachment vehicle_feet_passenger0 is not found!", + WaypointNotFound = "Decent Vehicle: Waypoint is not found!", + }, + GeneratedWaypoints = "Decent Vehicle: Waypoints are generated!", + LoadedWaypoints = "Decent Vehicle: Waypoints are restored!", + OldVersionNotify = "Decent Vehicle: This is an old version. Check for updates!", + OnDelete = "You are about to DELETE the waypoints.", + OnGenerate = "You are about to GENERATE the waypoints.", + OnLoad = "You are about to LOAD the waypoints.", + OnSave = "You are about to SAVE the waypoints.", + SavedWaypoints = "Decent Vehicle: Waypoints are saved!", + SaveLoad_Cancel = "Cancel", + SaveLoad_OK = "OK", + Tools = { + AlwaysDrawWaypoints = "Always draw waypoints", + AutoLoad = "Load waypoints on startup", + AutoLoadHelp = "If checked, Decent Vehicle will automatically load waypoints when the map is loaded.", + Bidirectional = "Bi-directional link", + BidirectionalHelp = "Connect bi-directional link automatically.", + Category = "GreatZenkakuMan's tools", + Delete = "Delete waypoints", + Description = "Create your own routes for vehicles!", + DescriptionInMenu = "Create routes for Decent Vehicles.", + DetectionRange = "Detection range for spawning", + DetectionRangeELS = "Detection range for finding cars with ELS", + DrawDistance = "Draw distance", + DrawDistanceHelp = "The maximum distance to draw waypoints.", + DrawWaypoints = "Draw waypoints", + DriveSide = "Is left side of the road", + ForceHeadlights = "Force headlights", + ForceHeadlightsHelp = "Forces Decent Vehicle to enable headlights.", + FuelStation = "Fuel station", + FuelStationHelp = "Decent Vehicles will go here to refuel its car.", + Generate = "Generate waypoints", + Instructions = "Select a waypoint or a traffic light to link. Select a vehicle driven by a Decent Vehicle to assign its waypoint group.", + Left = { + "Create a new waypoint.", + "Select another waypoint you want to link to. Select the same waypoint to remove it.", + }, + LightLevel = { + All = "Full lights", + Headlights = "Running lights and headlights", + None = "No light", + Running = "Only running lights", + Title = "Light level", + }, + LockVehicle = "Lock vehicle", + LockVehicleHelp = "If checked, Decent Vehicle prevents other players from getting in.", + MaxSpeed = "Max speed [km/h]", + Name = "Decent Vehicle Waypoint Tool", + PrintName = "Decent Vehicle Waypoint Tool", + Restore = "Restore waypoints", + Right = {"Update waypoint."}, + Save = "Save waypoints", + ServerSettings = "Server settings", + ShouldGoToRefuel = "Should go finding a fuel station", + ShowInfo = { + FuelStation = "Is fuel station: ", + Group = "Group: ", + ID = "ID: ", + SpeedLimit = "Speed limit [km/h]: ", + UseTurnLights = "Use turn lights: ", + WaitUntilNext = "Wait until next [seconds]: ", + }, + ShowUpdates = "Notify the latest updates", + ShowUpdatesHelp = "If checked, some notifications are shown when this addon is updated.", + StopInfrontofPerson = "Stop when it sees something", + StopInfrontofPersonHelp = "If checked, Decent Vehicle stops running if it sees something in front of it.", + UpdateRadius = "Update radius", + UpdateRadiusHelp = "Waypoints in this radius will be updated at a time when you press E + Right click.", + UseTurnLights = "Use turn signals", + UseTurnLightsHelp = "Decent Vehicles will use turn signals when they go to the waypoint.", + WaitTime = "Wait time [seconds]", + WaitTimeHelp = "After Decent Vehicles reached the waypoint, they wait for this seconds.", + WaypointGroup = "Waypoint group", + WaypointGroupHelp = [[You can force Decent Vehicles to run along specified group of waypoints. 0 means all vehicles can go there.]], - }, - UndoText = "Undone Decent Vehicle's waypoint", - -- VersionPrefix = "Version", - WireSupport = { - ToolDesc = "Provides some data of Decent Vehicle's waypoints for use with the wire system.", - ToolName = "[DV] Wire Waypoint Manager", - }, + }, + UndoText = "Undone Decent Vehicle's waypoint", + -- VersionPrefix = "Version", + WireSupport = { + ToolDesc = "Provides some data of Decent Vehicle's waypoints for use with the wire system.", + ToolName = "[DV] Wire Waypoint Manager", + }, } diff --git a/lua/decentvehicle/base/ja.lua b/lua/decentvehicle/base/ja.lua index 09762c7..62a1818 100644 --- a/lua/decentvehicle/base/ja.lua +++ b/lua/decentvehicle/base/ja.lua @@ -4,108 +4,108 @@ -- and DangerKiddy(DK) (https://steamcommunity.com/profiles/76561198132964487/). return { - CVars = { - AutoLoad = "Decent Vehicle: マップ読み込み時に自動的にウェイポイントを読み込むかどうか。", - DetectionRange = "Decent Vehicle: スポーン時に車両を検索する範囲。", - DetectionRangeELS = "Decent Vehicle: 運転中、非常灯付きの車を検知する範囲。", - DriveSide = [[Decent Vehicle: 左側通行か右側通行か。 + CVars = { + AutoLoad = "Decent Vehicle: マップ読み込み時に自動的にウェイポイントを読み込むかどうか。", + DetectionRange = "Decent Vehicle: スポーン時に車両を検索する範囲。", + DetectionRangeELS = "Decent Vehicle: 運転中、非常灯付きの車を検知する範囲。", + DriveSide = [[Decent Vehicle: 左側通行か右側通行か。 0: 右側通行 (ヨーロッパやアメリカなど) 1: 左側通行 (イギリスやオーストラリアなど)]], - ForceHeadlights = "Decent Vehicle: 常にヘッドライトを点灯させるかどうか。", - LockVehicle = "Decent Vehicle: 1にすると、Decent Vehicleの操縦する車両にプレイヤーが乗れないようになる。", - ShouldGoToRefuel = "Decent Vehicle: 1: ガソリンスタンドに向かって給油する 0: 自動的に給油されるようにする", - StopInfrontofPerson = "Decent Vehicle: 走行中、前方に物を検知した時に停止するかどうか。", - TimeToStopEmergency = "Decent Vehicle: 衝突時、ハザードランプを消すまでの時間。", - TurnOnLights = [[Decent Vehicle: 使用するライトのレベル。 + ForceHeadlights = "Decent Vehicle: 常にヘッドライトを点灯させるかどうか。", + LockVehicle = "Decent Vehicle: 1にすると、Decent Vehicleの操縦する車両にプレイヤーが乗れないようになる。", + ShouldGoToRefuel = "Decent Vehicle: 1: ガソリンスタンドに向かって給油する 0: 自動的に給油されるようにする", + StopInfrontofPerson = "Decent Vehicle: 走行中、前方に物を検知した時に停止するかどうか。", + TimeToStopEmergency = "Decent Vehicle: 衝突時、ハザードランプを消すまでの時間。", + TurnOnLights = [[Decent Vehicle: 使用するライトのレベル。 0: 無効 1: デイライトのみ 2: デイライトとヘッドライト 3: 可能なものすべて]], - }, - DeletedWaypoints = "Decent Vehicle: ウェイポイントが削除されました!", - Errors = { - AttachmentNotFound = "Decent Vehicle: アタッチメント vehicle_feet_passenger0 が見つかりません!", - WaypointNotFound = "Decent Vehicle: ウェイポイントが見つかりません!", - }, - GeneratedWaypoints = "Decent Vehicle: ウェイポイントが生成されました!", - LoadedWaypoints = "Decent Vehicle: ウェイポイントが読み込まれました!", - OldVersionNotify = "Decent Vehicle: 古いバージョンを使用しているようです。 アップデートを確認してください!", - OnDelete = "保存されたウェイポイントを削除します。", - OnGenerate = "ウェイポイントの自動生成を行います。", - OnLoad = "ウェイポイントの読み込みを行います。", - OnSave = "ウェイポイントの保存を行います。", - SavedWaypoints = "Decent Vehicle: ウェイポイントが保存されました!", - SaveLoad_Cancel = "キャンセル", - SaveLoad_OK = "OK", - Tools = { - AlwaysDrawWaypoints = "常にウェイポイントを表示する", - AutoLoad = "ウェイポイントの自動読み込み", - AutoLoadHelp = "マップの開始時にウェイポイントを自動的に読み込むかどうか。", - Bidirectional = "双方向に接続", - BidirectionalHelp = "自動的に双方向に接続します。", - Category = "GreatZenkakuMan's tools", - Delete = "ウェイポイントの削除", - Description = "乗り物のために道を作ろう!", - DescriptionInMenu = "Decent Vehicleのためのルートを構築する。", - DetectionRange = "スポーン時の車両検出範囲", - DetectionRangeELS = "緊急車両の検出範囲", - DrawDistance = "描画距離", - DrawDistanceHelp = "ウェイポイントを描画する最大の距離。", - DrawWaypoints = "ウェイポイントを描画する", - DriveSide = "左側通行", - ForceHeadlights = "ヘッドライトを常に点灯する", - ForceHeadlightsHelp = "チェックを入れると、Decent Vehicleは昼夜問わずヘッドライトを点灯するようになる。", - FuelStation = "ガソリンスタンド", - FuelStationHelp = "給油のために向かう地点であるかどうか。", - Generate = "ウェイポイントの生成", - Instructions = "ウェイポイントや信号をクリックして接続する。または、Decent Vehicleが運転する乗り物をクリックするとグループ番号を割り当てられる。", - Left = { - "新しいウェイポイントを作成する。", - "接続したいウェイポイントをクリックする。同じものをもう一度クリックすると消去する。", - }, - LightLevel = { - All = "すべて", - Headlights = "デイライトとヘッドライト", - None = "無効", - Running = "デイライトのみ", - Title = "ライトのレベル" - }, - LockVehicle = "車両をロックする", - LockVehicleHelp = "チェックを入れると、他のプレイヤーがDecent Vehicleの操縦する車両に乗れなくなる。", - MaxSpeed = "最大速度 [km/h]", - Name = "Decent Vehicle ウェイポイントツール", - PrintName = "Decent Vehicle ウェイポイントツール", - Restore = "ウェイポイントの読み込み", - Right = {"ウェイポイントを更新する。"}, - Save = "ウェイポイントの保存", - ServerSettings = "サーバー側の設定", - ShouldGoToRefuel = "ガソリンスタンドへ向かう", - ShowInfo = { - FuelStation = "ガソリンスタンド: ", - Group = "グループ番号: ", - ID = "ID: ", - SpeedLimit = "最大速度 [km/h]: ", - UseTurnLights = "ウィンカーを使う: ", - WaitUntilNext = "待ち時間 [秒]: ", - }, - ShowUpdates = "アップデートを通知する", - ShowUpdatesHelp = "チェックすると、アップデートされたときに通知が出るようになる。", - StopInfrontofPerson = "前方に物がある時に停止", - StopInfrontofPersonHelp = "Decent Vehicleが前方に物を検知した時に停止するかどうか。", - UpdateRadius = "アップデートの適用半径", - UpdateRadiusHelp = "E + 右クリックでこの範囲にあるウェイポイントが一度に更新される。", - UseTurnLights = "ウィンカーを使う", - UseTurnLightsHelp = "これが有効化されたウェイポイントへ向かうとき、ウィンカーを使うようになる。", - WaitTime = "待ち時間 [秒]", - WaitTimeHelp = "ウェイポイントの到着後に指定した時間だけ待つようになる。", - WaypointGroup = "グループ番号", - WaypointGroupHelp = [[一部のDecent Vehicleに対して向かうべき道を制限できる。 + }, + DeletedWaypoints = "Decent Vehicle: ウェイポイントが削除されました!", + Errors = { + AttachmentNotFound = "Decent Vehicle: アタッチメント vehicle_feet_passenger0 が見つかりません!", + WaypointNotFound = "Decent Vehicle: ウェイポイントが見つかりません!", + }, + GeneratedWaypoints = "Decent Vehicle: ウェイポイントが生成されました!", + LoadedWaypoints = "Decent Vehicle: ウェイポイントが読み込まれました!", + OldVersionNotify = "Decent Vehicle: 古いバージョンを使用しているようです。 アップデートを確認してください!", + OnDelete = "保存されたウェイポイントを削除します。", + OnGenerate = "ウェイポイントの自動生成を行います。", + OnLoad = "ウェイポイントの読み込みを行います。", + OnSave = "ウェイポイントの保存を行います。", + SavedWaypoints = "Decent Vehicle: ウェイポイントが保存されました!", + SaveLoad_Cancel = "キャンセル", + SaveLoad_OK = "OK", + Tools = { + AlwaysDrawWaypoints = "常にウェイポイントを表示する", + AutoLoad = "ウェイポイントの自動読み込み", + AutoLoadHelp = "マップの開始時にウェイポイントを自動的に読み込むかどうか。", + Bidirectional = "双方向に接続", + BidirectionalHelp = "自動的に双方向に接続します。", + Category = "GreatZenkakuMan's tools", + Delete = "ウェイポイントの削除", + Description = "乗り物のために道を作ろう!", + DescriptionInMenu = "Decent Vehicleのためのルートを構築する。", + DetectionRange = "スポーン時の車両検出範囲", + DetectionRangeELS = "緊急車両の検出範囲", + DrawDistance = "描画距離", + DrawDistanceHelp = "ウェイポイントを描画する最大の距離。", + DrawWaypoints = "ウェイポイントを描画する", + DriveSide = "左側通行", + ForceHeadlights = "ヘッドライトを常に点灯する", + ForceHeadlightsHelp = "チェックを入れると、Decent Vehicleは昼夜問わずヘッドライトを点灯するようになる。", + FuelStation = "ガソリンスタンド", + FuelStationHelp = "給油のために向かう地点であるかどうか。", + Generate = "ウェイポイントの生成", + Instructions = "ウェイポイントや信号をクリックして接続する。または、Decent Vehicleが運転する乗り物をクリックするとグループ番号を割り当てられる。", + Left = { + "新しいウェイポイントを作成する。", + "接続したいウェイポイントをクリックする。同じものをもう一度クリックすると消去する。", + }, + LightLevel = { + All = "すべて", + Headlights = "デイライトとヘッドライト", + None = "無効", + Running = "デイライトのみ", + Title = "ライトのレベル" + }, + LockVehicle = "車両をロックする", + LockVehicleHelp = "チェックを入れると、他のプレイヤーがDecent Vehicleの操縦する車両に乗れなくなる。", + MaxSpeed = "最大速度 [km/h]", + Name = "Decent Vehicle ウェイポイントツール", + PrintName = "Decent Vehicle ウェイポイントツール", + Restore = "ウェイポイントの読み込み", + Right = {"ウェイポイントを更新する。"}, + Save = "ウェイポイントの保存", + ServerSettings = "サーバー側の設定", + ShouldGoToRefuel = "ガソリンスタンドへ向かう", + ShowInfo = { + FuelStation = "ガソリンスタンド: ", + Group = "グループ番号: ", + ID = "ID: ", + SpeedLimit = "最大速度 [km/h]: ", + UseTurnLights = "ウィンカーを使う: ", + WaitUntilNext = "待ち時間 [秒]: ", + }, + ShowUpdates = "アップデートを通知する", + ShowUpdatesHelp = "チェックすると、アップデートされたときに通知が出るようになる。", + StopInfrontofPerson = "前方に物がある時に停止", + StopInfrontofPersonHelp = "Decent Vehicleが前方に物を検知した時に停止するかどうか。", + UpdateRadius = "アップデートの適用半径", + UpdateRadiusHelp = "E + 右クリックでこの範囲にあるウェイポイントが一度に更新される。", + UseTurnLights = "ウィンカーを使う", + UseTurnLightsHelp = "これが有効化されたウェイポイントへ向かうとき、ウィンカーを使うようになる。", + WaitTime = "待ち時間 [秒]", + WaitTimeHelp = "ウェイポイントの到着後に指定した時間だけ待つようになる。", + WaypointGroup = "グループ番号", + WaypointGroupHelp = [[一部のDecent Vehicleに対して向かうべき道を制限できる。 0にすると誰でも通れるウェイポイントになる。]], - }, - UndoText = "Decent Vehicleのウェイポイントを元に戻した", - -- VersionPrefix = "バージョン", - WireSupport = { - ToolDesc = "Decent Vehicleのウェイポイントに関する情報をWireが利用できるようにする。", - ToolName = "[DV] Wire ウェイポイント マネージャ", - }, + }, + UndoText = "Decent Vehicleのウェイポイントを元に戻した", + -- VersionPrefix = "バージョン", + WireSupport = { + ToolDesc = "Decent Vehicleのウェイポイントに関する情報をWireが利用できるようにする。", + ToolName = "[DV] Wire ウェイポイント マネージャ", + }, } diff --git a/lua/decentvehicle/base/ru.lua b/lua/decentvehicle/base/ru.lua index d4eb6d3..e5abbee 100644 --- a/lua/decentvehicle/base/ru.lua +++ b/lua/decentvehicle/base/ru.lua @@ -12,7 +12,7 @@ return { 0: Правостороннее (Европа, Америка итд.) 1: Левостороннее (Британия, Австралия итд.)]], ForceHeadlights = "Decent Vehicle: Заставляет Decent Vehicle включить фары", - LockVehicle = "Decent Vehicle: Закрывать транспорт при спавне?", + LockVehicle = "Decent Vehicle: Закрывать транспорт при спавне?", ShouldGoToRefuel = "Decent Vehicle: 1: Ехать на АЗС чтобы заправитьсч. 0: заправляться автоматичкски.", StopInfrontofPerson = "Decent Vehicle: Останавливаться или нет, если видно что то спереди.", TimeToStopEmergency = "Decent Vehicle: Время в секундах чтобы выключить аварийные сигналы.", @@ -22,16 +22,16 @@ return { 2: Ходовые и фары 3: Использовать все.]], }, - DeletedWaypoints = "Decent Vehicle: Точки удалены!", + DeletedWaypoints = "Decent Vehicle: Точки удалены!", Errors = { AttachmentNotFound = "Decent Vehicle: attachment vehicle_feet_passenger0 не найден!", WaypointNotFound = "Decent Vehicle: Точка не найден!", }, - GeneratedWaypoints = "Decent Vehicle: Точки сгенерировались!", - LoadedWaypoints = "Decent Vehicle: Точки загружены!", + GeneratedWaypoints = "Decent Vehicle: Точки сгенерировались!", + LoadedWaypoints = "Decent Vehicle: Точки загружены!", OldVersionNotify = "Decent Vehicle: Эта версия устарела!", - OnDelete = "Вы собираетесь УДАЛИТЬ точки.", - OnGenerate = "Вы собираетесь СГЕНЕРИРОВАТЬ точки.", + OnDelete = "Вы собираетесь УДАЛИТЬ точки.", + OnGenerate = "Вы собираетесь СГЕНЕРИРОВАТЬ точки.", OnLoad = "Вы собираетесь ЗАГРУЗИТЬ точки.", OnSave = "Вы собираетесь СОХРАНИТЬ точки.", SavedWaypoints = "Decent Vehicle: Точки сохранены!", @@ -44,20 +44,20 @@ return { Bidirectional = "Bi-directional соединение", BidirectionalHelp = "Connect bi-directional link automatically.", Category = "GreatZenkakuMan's tools", - Delete = "Удалить точки", + Delete = "Удалить точки", Description = "Создайте свой маршрут для транспорта!", DescriptionInMenu = "Создать маршруты для Decent Vehicle", DetectionRange = "Радиус для спавна", DetectionRangeELS = "Радиус для определения машин с ELS", - DrawDistance = "Дистанция отрисовки", - DrawDistanceHelp = "Дистанция, на которой будут отрисовываться точки", + DrawDistance = "Дистанция отрисовки", + DrawDistanceHelp = "Дистанция, на которой будут отрисовываться точки", DrawWaypoints = "Отображать точки", DriveSide = "Левостороннее движение", - ForceHeadlights = "Включить фары", - ForceHeadlightsHelp = "Заставляет Decent Vehicle включить фары", + ForceHeadlights = "Включить фары", + ForceHeadlightsHelp = "Заставляет Decent Vehicle включить фары", FuelStation = "Заправка", FuelStationHelp = "Decent Vehicle будет ехать сюда чтобы заправиться.", - Generate = "Сгенерировать точки", + Generate = "Сгенерировать точки", Instructions = "Выберете точку и/или светофор чтобы соединить их. Выберете транспорт управляемый Decent Vehicle, чтобы назначить ему группу.", Left = { "Создать новую точку.", @@ -70,8 +70,8 @@ return { Running = "Только ходовые", Title = "Уровень освещения", }, - LockVehicle = "Закрывать транспорт", - LockVehicleHelp = "Закрывать транспорт при спавне?", + LockVehicle = "Закрывать транспорт", + LockVehicleHelp = "Закрывать транспорт при спавне?", MaxSpeed = "Максисальная скорость [км/ч]", Name = "Decent Vehicle Waypoint Tool", PrintName = "Decent Vehicle Waypoint Tool", @@ -103,5 +103,5 @@ return { 0 значит, что все могут тут ездить.]], }, UndoText = "Отмена точки", - -- VersionPrefix = "Версия", + -- VersionPrefix = "Версия", } diff --git a/lua/decentvehicle/npc_decentvehicle/en.lua b/lua/decentvehicle/npc_decentvehicle/en.lua index a0161d9..1422fa2 100644 --- a/lua/decentvehicle/npc_decentvehicle/en.lua +++ b/lua/decentvehicle/npc_decentvehicle/en.lua @@ -4,5 +4,5 @@ -- and DangerKiddy(DK) (https://steamcommunity.com/profiles/76561198132964487/). return { - npc_decentvehicle = "Decent Vehicle", + npc_decentvehicle = "Decent Vehicle", } diff --git a/lua/decentvehicle/npc_dvtaxi/en.lua b/lua/decentvehicle/npc_dvtaxi/en.lua index 5d8bf06..8cdc1c2 100644 --- a/lua/decentvehicle/npc_dvtaxi/en.lua +++ b/lua/decentvehicle/npc_dvtaxi/en.lua @@ -5,20 +5,20 @@ -- Proof-read and edited by Arctic (https://steamcommunity.com/id/ArcticWinterZzZ/). return { - npc_dvtaxi = "Decent Taxi", - Taxi = { - Arrived = "Decent Taxi: Your taxi is here!", - ArrivedDestination = "Decent Taxi: We're here!", - Busy = "Decent Taxi: No taxis are available!", - Button = "Ready", - Coming = "Decent Taxi: A taxi is coming to your location.", - Fare = " That'll be $%s", - Getin = "Decent Taxi: Where are we going to today?", - Getoff = "Decent Taxi: Good luck!", - NoDriverFound = "Decent Taxi: There are no taxis on the map!", - NotEnoughMoney = "Decent Taxi: You don't have enough money!", - ShowCarName = " It's a %s.", - StartGoing = "Decent Taxi: Let's go!", - UnitPrice = "Decent Vehicle: Taxi fare for one kilometer", - }, + npc_dvtaxi = "Decent Taxi", + Taxi = { + Arrived = "Decent Taxi: Your taxi is here!", + ArrivedDestination = "Decent Taxi: We're here!", + Busy = "Decent Taxi: No taxis are available!", + Button = "Ready", + Coming = "Decent Taxi: A taxi is coming to your location.", + Fare = " That'll be $%s", + Getin = "Decent Taxi: Where are we going to today?", + Getoff = "Decent Taxi: Good luck!", + NoDriverFound = "Decent Taxi: There are no taxis on the map!", + NotEnoughMoney = "Decent Taxi: You don't have enough money!", + ShowCarName = " It's a %s.", + StartGoing = "Decent Taxi: Let's go!", + UnitPrice = "Decent Vehicle: Taxi fare for one kilometer", + }, } diff --git a/lua/decentvehicle/npc_dvtaxi/ja.lua b/lua/decentvehicle/npc_dvtaxi/ja.lua index 14445e7..4e65546 100644 --- a/lua/decentvehicle/npc_dvtaxi/ja.lua +++ b/lua/decentvehicle/npc_dvtaxi/ja.lua @@ -4,20 +4,20 @@ -- and DangerKiddy(DK) (https://steamcommunity.com/profiles/76561198132964487/). return { - npc_dvtaxi = "Decent Taxi", - Taxi = { - Arrived = "Decent Taxi: タクシーが到着しました!", - ArrivedDestination = "Decent Taxi: 目的地に到着しました!", - Busy = "Decent Taxi: 別のお客様が予約しておりますので...", - Button = "呼ぶ", - Coming = "Decent Taxi: タクシーがそちらへ向かいます!", - Fare = " %sドルいただきます。", - Getin = "Decent Taxi: こんにちは。どちらへ向かいますか?", - Getoff = "Decent Taxi: ありがとうございました!", - NoDriverFound = "Decent Taxi: タクシー運転手がいません!", - NotEnoughMoney = "Decent Taxi: お金が足りません!", - ShowCarName = "向かう車は%sです。", - StartGoing = "Decent Taxi: 出発します!", - UnitPrice = "Decent Vehicle: 1キロメートルあたりのタクシー運賃。", - }, + npc_dvtaxi = "Decent Taxi", + Taxi = { + Arrived = "Decent Taxi: タクシーが到着しました!", + ArrivedDestination = "Decent Taxi: 目的地に到着しました!", + Busy = "Decent Taxi: 別のお客様が予約しておりますので...", + Button = "呼ぶ", + Coming = "Decent Taxi: タクシーがそちらへ向かいます!", + Fare = " %sドルいただきます。", + Getin = "Decent Taxi: こんにちは。どちらへ向かいますか?", + Getoff = "Decent Taxi: ありがとうございました!", + NoDriverFound = "Decent Taxi: タクシー運転手がいません!", + NotEnoughMoney = "Decent Taxi: お金が足りません!", + ShowCarName = "向かう車は%sです。", + StartGoing = "Decent Taxi: 出発します!", + UnitPrice = "Decent Vehicle: 1キロメートルあたりのタクシー運賃。", + }, } diff --git a/lua/decentvehicle/npc_dvtaxi/ru.lua b/lua/decentvehicle/npc_dvtaxi/ru.lua index dfd3d8c..dc541ee 100644 --- a/lua/decentvehicle/npc_dvtaxi/ru.lua +++ b/lua/decentvehicle/npc_dvtaxi/ru.lua @@ -4,20 +4,20 @@ -- and DangerKiddy(DK) (https://steamcommunity.com/profiles/76561198132964487/). return { - npc_dvtaxi = "Decent Taxi", - Taxi = { - Arrived = "Decent Taxi: Your taxi is here!", - ArrivedDestination = "Decent Taxi: We're here!", - Busy = "Decent Taxi: No taxis are available!", - Button = "Ready", - Coming = "Decent Taxi: A taxi is coming to your location.", - Fare = " That'll be $%s", - Getin = "Decent Taxi: Where are we going to today?", - Getoff = "Decent Taxi: Good luck!", - NoDriverFound = "Decent Taxi: There are no taxis on the map!", - NotEnoughMoney = "Decent Taxi: You don't have enough money!", - ShowCarName = " It's a %s.", - StartGoing = "Decent Taxi: Let's go!", - UnitPrice = "Decent Vehicle: Taxi fare for one kilometer", - }, + npc_dvtaxi = "Decent Taxi", + Taxi = { + Arrived = "Decent Taxi: Your taxi is here!", + ArrivedDestination = "Decent Taxi: We're here!", + Busy = "Decent Taxi: No taxis are available!", + Button = "Ready", + Coming = "Decent Taxi: A taxi is coming to your location.", + Fare = " That'll be $%s", + Getin = "Decent Taxi: Where are we going to today?", + Getoff = "Decent Taxi: Good luck!", + NoDriverFound = "Decent Taxi: There are no taxis on the map!", + NotEnoughMoney = "Decent Taxi: You don't have enough money!", + ShowCarName = " It's a %s.", + StartGoing = "Decent Taxi: Let's go!", + UnitPrice = "Decent Vehicle: Taxi fare for one kilometer", + }, } diff --git a/lua/entities/ent_dv_traffic_light/cl_init.lua b/lua/entities/ent_dv_traffic_light/cl_init.lua index 762b1e3..5dbeed5 100644 --- a/lua/entities/ent_dv_traffic_light/cl_init.lua +++ b/lua/entities/ent_dv_traffic_light/cl_init.lua @@ -9,57 +9,57 @@ local material = Material "sprites/light_ignorez" local Colors = {Color(0, 255, 0), Color(255, 191, 0), Color(255, 0, 0)} local SpritePos = {-11.2, 0, 11.2} function ENT:DrawTranslucent() - self:DrawModel() - - local color = self:GetNWInt "DVTL_LightColor" - self.SpriteColor = Colors[color] - self.SpritePos = SpritePos[color] - - local LightPos = self:GetPos() + self:GetForward() * -2 + self:GetUp() * self.SpritePos - local dlight = DynamicLight(self:EntIndex()) - if not dlight then return true end - dlight.pos = LightPos - dlight.r = self.SpriteColor.r - dlight.g = self.SpriteColor.g - dlight.b = self.SpriteColor.b - dlight.brightness = 2 - dlight.decay = 0 - dlight.size = 128 - dlight.dietime = CurTime() + 1 - - if util.TraceLine { - start = EyePos(), - endpos = LightPos, - filter = {self, LocalPlayer()}, - mask = MASK_VISIBLE_AND_NPCS, - } .Hit then return end - - local ViewNormal = self:GetPos() - EyePos() - local Distance = ViewNormal:Length() - ViewNormal:Normalize() - - local ViewDot = ViewNormal:Dot(self:GetForward()) - if ViewDot < 0 then return end - - local Visible = util.PixelVisible(LightPos, 16, self.PixVis) - if (Visible or 0) < 5e-3 then return end + self:DrawModel() - local Size = math.Clamp(Distance * Visible * ViewDot * 2, 48, 128) - local Alpha = math.Clamp((1000 - math.Clamp(Distance, 32, 800)) * Visible * ViewDot, 0, 100) - render.SetMaterial(material) - render.DrawSprite(LightPos, Size, Size, ColorAlpha(self.SpriteColor, Alpha)) - render.DrawSprite(LightPos, Size * .2, Size * .2, ColorAlpha(color_white, Alpha)) + local color = self:GetNWInt "DVTL_LightColor" + self.SpriteColor = Colors[color] + self.SpritePos = SpritePos[color] + + local LightPos = self:GetPos() + self:GetForward() * -2 + self:GetUp() * self.SpritePos + local dlight = DynamicLight(self:EntIndex()) + if not dlight then return true end + dlight.pos = LightPos + dlight.r = self.SpriteColor.r + dlight.g = self.SpriteColor.g + dlight.b = self.SpriteColor.b + dlight.brightness = 2 + dlight.decay = 0 + dlight.size = 128 + dlight.dietime = CurTime() + 1 + + if util.TraceLine { + start = EyePos(), + endpos = LightPos, + filter = {self, LocalPlayer()}, + mask = MASK_VISIBLE_AND_NPCS, + } .Hit then return end + + local ViewNormal = self:GetPos() - EyePos() + local Distance = ViewNormal:Length() + ViewNormal:Normalize() + + local ViewDot = ViewNormal:Dot(self:GetForward()) + if ViewDot < 0 then return end + + local Visible = util.PixelVisible(LightPos, 16, self.PixVis) + if (Visible or 0) < 5e-3 then return end + + local Size = math.Clamp(Distance * Visible * ViewDot * 2, 48, 128) + local Alpha = math.Clamp((1000 - math.Clamp(Distance, 32, 800)) * Visible * ViewDot, 0, 100) + render.SetMaterial(material) + render.DrawSprite(LightPos, Size, Size, ColorAlpha(self.SpriteColor, Alpha)) + render.DrawSprite(LightPos, Size * .2, Size * .2, ColorAlpha(color_white, Alpha)) end function ENT:Initialize() - self:SetPattern(1) - self:SetNWInt("DVTL_LightColor", 1) - self.PixVis = util.GetPixelVisibleHandle() + self:SetPattern(1) + self:SetNWInt("DVTL_LightColor", 1) + self.PixVis = util.GetPixelVisibleHandle() end function ENT:OnRemove() - local dlight = DynamicLight(self:EntIndex()) - if not dlight then return end - dlight.dietime = CurTime() - dlight.brightness = 0 + local dlight = DynamicLight(self:EntIndex()) + if not dlight then return end + dlight.dietime = CurTime() + dlight.brightness = 0 end diff --git a/lua/entities/ent_dv_traffic_light/init.lua b/lua/entities/ent_dv_traffic_light/init.lua index 3f3105d..ddb6849 100644 --- a/lua/entities/ent_dv_traffic_light/init.lua +++ b/lua/entities/ent_dv_traffic_light/init.lua @@ -13,49 +13,49 @@ local ly = "decentvehicle/trafficlight/ly" local lg = "decentvehicle/trafficlight/lg" local lightg = "decentvehicle/trafficlight/lightg" local LightTable = { - {lightg, lg, lightg}, - {lightg, lightg, ly}, - {lr, lightg, lightg}, + {lightg, lg, lightg}, + {lightg, lightg, ly}, + {lr, lightg, lightg}, } function ENT:Initialize() - self:SetModel "models/decentvehicle/trafficlight.mdl" - self:PhysicsInit(SOLID_VPHYSICS) - self:SetMoveType(MOVETYPE_VPHYSICS) + self:SetModel "models/decentvehicle/trafficlight.mdl" + self:PhysicsInit(SOLID_VPHYSICS) + self:SetMoveType(MOVETYPE_VPHYSICS) - local phys = self:GetPhysicsObject() - if not IsValid(phys) then return end - phys:SetMass(50) - phys:Wake() + local phys = self:GetPhysicsObject() + if not IsValid(phys) then return end + phys:SetMass(50) + phys:Wake() - self:DrawShadow(false) - self:Fire "DisableCollision" - self:SetNWInt("DVTL_LightColor", 1) - self:SetPattern(1) + self:DrawShadow(false) + self:Fire "DisableCollision" + self:SetNWInt("DVTL_LightColor", 1) + self:SetPattern(1) - self.Waypoints = {} + self.Waypoints = {} end function ENT:SpawnFunction(ply, tr, ClassName) - if not tr.Hit then return end - local SpawnPos = tr.HitPos + tr.HitNormal - local ent = ents.Create(ClassName) - if not IsValid(ent) then return end - ent:SetPos(SpawnPos + vector_up * 18) - ent:SetAngles(Angle(0, ply:GetAngles().yaw, 0)) - ent:Spawn() - return ent + if not tr.Hit then return end + local SpawnPos = tr.HitPos + tr.HitNormal + local ent = ents.Create(ClassName) + if not IsValid(ent) then return end + ent:SetPos(SpawnPos + vector_up * 18) + ent:SetAngles(Angle(0, ply:GetAngles().yaw, 0)) + ent:Spawn() + return ent end function ENT:Think() - local p = self:GetPattern() - if not p then return end - local tl = dvd.TrafficLights[p] - if not tl then return end - local color = tl.Light - self:SetNWInt("DVTL_LightColor", color) - - for i = 1, 3 do - self:SetSubMaterial(i, LightTable[color][i]) - end + local p = self:GetPattern() + if not p then return end + local tl = dvd.TrafficLights[p] + if not tl then return end + local color = tl.Light + self:SetNWInt("DVTL_LightColor", color) + + for i = 1, 3 do + self:SetSubMaterial(i, LightTable[color][i]) + end end diff --git a/lua/entities/ent_dv_traffic_light/shared.lua b/lua/entities/ent_dv_traffic_light/shared.lua index 92d6067..f09619f 100644 --- a/lua/entities/ent_dv_traffic_light/shared.lua +++ b/lua/entities/ent_dv_traffic_light/shared.lua @@ -13,13 +13,13 @@ ENT.Editable = true ENT.IsDVTrafficLight = true function ENT:SetupDataTables() - self:NetworkVar("Int", 0, "Pattern", { - KeyName = "pattern", - Edit = { - type = "Int", - order = 1, - min = 1, - max = #DecentVehicleDestination.TrafficLights, - }, - }) -end + self:NetworkVar("Int", 0, "Pattern", { + KeyName = "pattern", + Edit = { + type = "Int", + order = 1, + min = 1, + max = #DecentVehicleDestination.TrafficLights, + }, + }) +end diff --git a/lua/entities/ent_dvtaxi_station.lua b/lua/entities/ent_dvtaxi_station.lua index 192db89..80ccd3e 100644 --- a/lua/entities/ent_dvtaxi_station.lua +++ b/lua/entities/ent_dvtaxi_station.lua @@ -15,51 +15,52 @@ ENT.IsDVTaxiStation = true local dvd = DecentVehicleDestination function ENT:SetupDataTables() - self:NetworkVar("String", 0, "StationName", { - KeyName = "stationname", - Edit = {type = "Name", order = 4} - }) + self:NetworkVar("String", 0, "StationName", { + KeyName = "stationname", + Edit = {type = "Name", order = 4} + }) end if CLIENT then - function ENT:Draw() - self:DrawModel() - end - - return + function ENT:Draw() + self:DrawModel() + end + + return end + function ENT:Initialize() - self:SetModel "models/decentvehicle/ent_dvtaxi_station.mdl" - - self:PhysicsInitShadow() - self:SetMoveType(MOVETYPE_VPHYSICS) - self:SetSolid(SOLID_VPHYSICS) - self:SetUseType(SIMPLE_USE) - self:DrawShadow(false) - dvd.TaxiStations[self] = true + self:SetModel "models/decentvehicle/ent_dvtaxi_station.mdl" + + self:PhysicsInitShadow() + self:SetMoveType(MOVETYPE_VPHYSICS) + self:SetSolid(SOLID_VPHYSICS) + self:SetUseType(SIMPLE_USE) + self:DrawShadow(false) + dvd.TaxiStations[self] = true end function ENT:OnRemove() - dvd.TaxiStations[self] = nil + dvd.TaxiStations[self] = nil end function ENT:Use(activator, caller) - if not caller:IsPlayer() then return end - - net.Start "Decent Vehicle: Open a taxi menu" - net.WriteEntity(self) - net.Send(caller) + if not caller:IsPlayer() then return end + + net.Start "Decent Vehicle: Open a taxi menu" + net.WriteEntity(self) + net.Send(caller) end function ENT:SpawnFunction(ply, tr, ClassName) - if not tr.Hit then return end - local pos = tr.HitPos + tr.HitNormal - local ang = dvd.GetDir(tr.StartPos, tr.HitPos):Angle() - local ent = ents.Create(ClassName) - ent:SetAngles(Angle(0, ang.yaw, 0)) - ent:SetPos(pos) - ent:Spawn() - - return ent + if not tr.Hit then return end + local pos = tr.HitPos + tr.HitNormal + local ang = dvd.GetDir(tr.StartPos, tr.HitPos):Angle() + local ent = ents.Create(ClassName) + ent:SetAngles(Angle(0, ang.yaw, 0)) + ent:SetPos(pos) + ent:Spawn() + + return ent end diff --git a/lua/entities/env_dv_save.lua b/lua/entities/env_dv_save.lua index 0aa9860..a691ee2 100644 --- a/lua/entities/env_dv_save.lua +++ b/lua/entities/env_dv_save.lua @@ -7,11 +7,11 @@ AddCSLuaFile() ENT.Type = "point" local dvd = DecentVehicleDestination function ENT:Initialize() - if #ents.FindByClass(self.ClassName) > 1 then self:Remove() return end - dvd.SaveEntity = self + if #ents.FindByClass(self.ClassName) > 1 then self:Remove() return end + dvd.SaveEntity = self end if CLIENT then return end function ENT:PreEntityCopy() - duplicator.StoreEntityModifier(self, "Decent Vehicle: Save waypoints", dvd.GetSaveTable()) + duplicator.StoreEntityModifier(self, "Decent Vehicle: Save waypoints", dvd.GetSaveTable()) end diff --git a/lua/entities/gmod_wire_dvmanager.lua b/lua/entities/gmod_wire_dvmanager.lua index bbf46b1..d013fe3 100644 --- a/lua/entities/gmod_wire_dvmanager.lua +++ b/lua/entities/gmod_wire_dvmanager.lua @@ -13,92 +13,92 @@ ENT.IsDVWireManager = true local dvd = DecentVehicleDestination function ENT:OnRemove() - dvd.WireManagers[self] = nil + dvd.WireManagers[self] = nil end if CLIENT then - function ENT:Initialize() - dvd.WireManagers[self] = true - end + function ENT:Initialize() + dvd.WireManagers[self] = true + end - return + return end local IOList = { - "Group #", - "Is fuel station", - "Speed limit", - "Use turn lights", - "Wait time", + "Group #", + "Is fuel station", + "Speed limit", + "Use turn lights", + "Wait time", } function ENT:Initialize() - self:PhysicsInit(SOLID_VPHYSICS) - self:SetMoveType(MOVETYPE_VPHYSICS) - self:DrawShadow(false) - self:SetNWInt("WaypointID", -1) - self.Inputs = Wire_CreateInputs(self, IOList) - self.Outputs = Wire_CreateOutputs(self, IOList) - dvd.WireManagers[self] = true + self:PhysicsInit(SOLID_VPHYSICS) + self:SetMoveType(MOVETYPE_VPHYSICS) + self:DrawShadow(false) + self:SetNWInt("WaypointID", -1) + self.Inputs = Wire_CreateInputs(self, IOList) + self.Outputs = Wire_CreateOutputs(self, IOList) + dvd.WireManagers[self] = true end function ENT:LinkEnt(e) - if not isnumber(e) then return false end - local w = dvd.Waypoints[e] - if not w then return false end - self:SetNWInt("WaypointID", e) - self.waypointid = e - self:ShowOutput() - return true + if not isnumber(e) then return false end + local w = dvd.Waypoints[e] + if not w then return false end + self:SetNWInt("WaypointID", e) + self.waypointid = e + self:ShowOutput() + return true end function ENT:UnlinkEnt() - self:SetNWInt("WaypointID", -1) - self.waypointid = nil - self:ShowOutput() + self:SetNWInt("WaypointID", -1) + self.waypointid = nil + self:ShowOutput() end function ENT:Setup(waypointid) - self:ShowOutput() - if not isnumber(waypointid) then return end - self.waypointid = waypointid - self:SetNWInt("WaypointID", waypointid) + self:ShowOutput() + if not isnumber(waypointid) then return end + self.waypointid = waypointid + self:SetNWInt("WaypointID", waypointid) end function ENT:OnRestore() - self.BaseClass.OnRestore(self) - self:SetNWInt("WaypointID", self.waypointid) - self:ShowOutput() + self.BaseClass.OnRestore(self) + self:SetNWInt("WaypointID", self.waypointid) + self:ShowOutput() end function ENT:TriggerInput(iname, value) - local id = self:GetNWInt "WaypointID" - if not isnumber(id) or id < 0 then return end - local w = dvd.Waypoints[id] - if not w then return end - if iname == "Group #" then - w.Group = math.floor(value) - elseif iname == "Is fuel station" then - w.FuelStation = value == 1 - elseif iname == "Speed limit" then - w.SpeedLimit = value * dvd.KmphToHUps - elseif iname == "Use turn lights" then - w.UseTurnLights = value == 1 - elseif iname == "Wait time" then - w.WaitUntilNext = value - else - return - end - - self:ShowOutput() - if player.GetCount() == 0 then return end - net.Start "Decent Vehicle: Send waypoint info" - net.WriteUInt(id, 24) - net.WriteUInt(w.Group, 16) - net.WriteFloat(w.SpeedLimit) - net.WriteFloat(w.WaitUntilNext) - net.WriteBool(w.UseTurnLights) - net.WriteBool(w.FuelStation) - net.Broadcast() + local id = self:GetNWInt "WaypointID" + if not isnumber(id) or id < 0 then return end + local w = dvd.Waypoints[id] + if not w then return end + if iname == "Group #" then + w.Group = math.floor(value) + elseif iname == "Is fuel station" then + w.FuelStation = value == 1 + elseif iname == "Speed limit" then + w.SpeedLimit = value * dvd.KmphToHUps + elseif iname == "Use turn lights" then + w.UseTurnLights = value == 1 + elseif iname == "Wait time" then + w.WaitUntilNext = value + else + return + end + + self:ShowOutput() + if player.GetCount() == 0 then return end + net.Start "Decent Vehicle: Send waypoint info" + net.WriteUInt(id, 24) + net.WriteUInt(w.Group, 16) + net.WriteFloat(w.SpeedLimit) + net.WriteFloat(w.WaitUntilNext) + net.WriteBool(w.UseTurnLights) + net.WriteBool(w.FuelStation) + net.Broadcast() end local Output = [[Linked to: #%d @@ -108,24 +108,24 @@ Speed limit = %.2f km/s Use turn lights = %s Wait time = %.2f sec.]] function ENT:ShowOutput() - local i = self:GetNWInt "WaypointID" - if not isnumber(i) or i < 0 then - self:SetOverlayText "Not linked yet" - return - end - - local w = dvd.Waypoints[i] - if not w then - self:SetOverlayText "Linked to an invalid waypoint" - return - end - - self:SetOverlayText(Output:format(i, w.Group, tostring(w.FuelStation), w.SpeedLimit / dvd.KmphToHUps, tostring(w.UseTurnLights), w.WaitUntilNext)) - Wire_TriggerOutput(self, "Group #", w.Group) - Wire_TriggerOutput(self, "Is fuel station", w.FuelStation) - Wire_TriggerOutput(self, "Speed limit", w.SpeedLimit / dvd.KmphToHUps) - Wire_TriggerOutput(self, "Use turn lights", w.UseTurnLights) - Wire_TriggerOutput(self, "Wait time", w.WaitUntilNext) + local i = self:GetNWInt "WaypointID" + if not isnumber(i) or i < 0 then + self:SetOverlayText "Not linked yet" + return + end + + local w = dvd.Waypoints[i] + if not w then + self:SetOverlayText "Linked to an invalid waypoint" + return + end + + self:SetOverlayText(Output:format(i, w.Group, tostring(w.FuelStation), w.SpeedLimit / dvd.KmphToHUps, tostring(w.UseTurnLights), w.WaitUntilNext)) + Wire_TriggerOutput(self, "Group #", w.Group) + Wire_TriggerOutput(self, "Is fuel station", w.FuelStation) + Wire_TriggerOutput(self, "Speed limit", w.SpeedLimit / dvd.KmphToHUps) + Wire_TriggerOutput(self, "Use turn lights", w.UseTurnLights) + Wire_TriggerOutput(self, "Wait time", w.WaitUntilNext) end duplicator.RegisterEntityClass("gmod_wire_dvmanager", WireLib.MakeWireEnt, "Data", "waypointid") diff --git a/lua/entities/npc_decentvehicle/api.lua b/lua/entities/npc_decentvehicle/api.lua index 3df7787..362d6d1 100644 --- a/lua/entities/npc_decentvehicle/api.lua +++ b/lua/entities/npc_decentvehicle/api.lua @@ -6,554 +6,554 @@ local dvd = DecentVehicleDestination local TurnOnLights = dvd.CVars.TurnOnLights local LIGHTLEVEL = { - NONE = 0, - RUNNING = 1, - HEADLIGHTS = 2, - ALL = 3, + NONE = 0, + RUNNING = 1, + HEADLIGHTS = 2, + ALL = 3, } function ENT:GetMaxSteeringAngle() - if self.v.IsScar then - return self.v.MaxSteerForce * 3 -- Obviously this is not actually steering angle - elseif self.v.IsSimfphyscar then - return self.v.VehicleData.steerangle - else - local mph = self.v:GetSpeed() - if mph < self.SteeringSpeedFast then - return Lerp((mph - self.SteeringSpeedSlow) - / (self.SteeringSpeedFast - self.SteeringSpeedSlow), - self.SteeringAngleSlow, self.SteeringAngleFast) - else - return Lerp((mph - self.SteeringSpeedFast) - / (self.BoostSpeed - self.SteeringSpeedFast), - self.SteeringAngleFast, self.SteeringAngleBoost) - end - end + if self.v.IsScar then + return self.v.MaxSteerForce * 3 -- Obviously this is not actually steering angle + elseif self.v.IsSimfphyscar then + return self.v.VehicleData.steerangle + else + local mph = self.v:GetSpeed() + if mph < self.SteeringSpeedFast then + return Lerp((mph - self.SteeringSpeedSlow) + / (self.SteeringSpeedFast - self.SteeringSpeedSlow), + self.SteeringAngleSlow, self.SteeringAngleFast) + else + return Lerp((mph - self.SteeringSpeedFast) + / (self.BoostSpeed - self.SteeringSpeedFast), + self.SteeringAngleFast, self.SteeringAngleBoost) + end + end end function ENT:GetTraceFilter() - local filter = table.Add({self, self.v}, constraint.GetAllConstrainedEntities(self.v)) - if self.v.IsScar then - table.Add(filter, self.v.Seats or {}) - table.Add(filter, self.v.Wheels) - table.Add(filter, self.v.StabilizerProp) - elseif self.v.IsSimfphyscar then - table.Add(filter, self.v.VehicleData.filter) - else - table.Add(filter, self.v:GetChildren()) - end - - return filter + local filter = table.Add({self, self.v}, constraint.GetAllConstrainedEntities(self.v)) + if self.v.IsScar then + table.Add(filter, self.v.Seats or {}) + table.Add(filter, self.v.Wheels) + table.Add(filter, self.v.StabilizerProp) + elseif self.v.IsSimfphyscar then + table.Add(filter, self.v.VehicleData.filter) + else + table.Add(filter, self.v:GetChildren()) + end + + return filter end function ENT:GetRunningLights() - if self.v.IsScar then - return self.v:GetNWBool "HeadlightsOn" - elseif self.v.IsSimfphyscar then - return self.SimfphysRunningLights - elseif vcmod_main - and isfunction(self.v.VC_getStates) then - local states = self.v:VC_getStates() - return istable(states) and states.RunningLights - end + if self.v.IsScar then + return self.v:GetNWBool "HeadlightsOn" + elseif self.v.IsSimfphyscar then + return self.SimfphysRunningLights + elseif vcmod_main + and isfunction(self.v.VC_getStates) then + local states = self.v:VC_getStates() + return istable(states) and states.RunningLights + end end function ENT:GetFogLights() - if self.v.IsScar then - return self.v:GetNWBool "HeadlightsOn" - elseif self.v.IsSimfphyscar then - return self.SimfphysFogLights - elseif vcmod_main - and isfunction(self.v.VC_getStates) then - local states = self.v:VC_getStates() - return istable(states) and states.FogLights - end + if self.v.IsScar then + return self.v:GetNWBool "HeadlightsOn" + elseif self.v.IsSimfphyscar then + return self.SimfphysFogLights + elseif vcmod_main + and isfunction(self.v.VC_getStates) then + local states = self.v:VC_getStates() + return istable(states) and states.FogLights + end end function ENT:GetLights(highbeams) - if self.v.IsScar then - return self.v:GetNWBool "HeadlightsOn" - elseif self.v.IsSimfphyscar then - return Either(highbeams, self.v.LampsActivated, self.v.LightsActivated) - elseif vcmod_main - and isfunction(self.v.VC_getStates) then - local states = self.v:VC_getStates() - return istable(states) and Either(highbeams, states.HighBeams, states.LowBeams) - elseif Photon - and isfunction(self.v.ELS_Illuminate) then - return self.v:ELS_Illuminate() - end + if self.v.IsScar then + return self.v:GetNWBool "HeadlightsOn" + elseif self.v.IsSimfphyscar then + return Either(highbeams, self.v.LampsActivated, self.v.LightsActivated) + elseif vcmod_main + and isfunction(self.v.VC_getStates) then + local states = self.v:VC_getStates() + return istable(states) and Either(highbeams, states.HighBeams, states.LowBeams) + elseif Photon + and isfunction(self.v.ELS_Illuminate) then + return self.v:ELS_Illuminate() + end end function ENT:GetTurnLight(left) - if self.v.IsScar then -- Does SCAR have turn lights? - elseif self.v.IsSimfphyscar then - return Either(left, self.TurnLightLeft, self.TurnLightRight) - elseif vcmod_main - and isfunction(self.v.VC_getStates) then - local states = self.v:VC_getStates() - return istable(states) and Either(left, states.TurnLightLeft, states.TurnLightRight) - elseif Photon - and isfunction(self.v.CAR_TurnLeft) - and isfunction(self.v.CAR_TurnRight) then - return Either(left, self.v:CAR_TurnLeft(), self.v:CAR_TurnRight()) - end + if self.v.IsScar then -- Does SCAR have turn lights? + elseif self.v.IsSimfphyscar then + return Either(left, self.TurnLightLeft, self.TurnLightRight) + elseif vcmod_main + and isfunction(self.v.VC_getStates) then + local states = self.v:VC_getStates() + return istable(states) and Either(left, states.TurnLightLeft, states.TurnLightRight) + elseif Photon + and isfunction(self.v.CAR_TurnLeft) + and isfunction(self.v.CAR_TurnRight) then + return Either(left, self.v:CAR_TurnLeft(), self.v:CAR_TurnRight()) + end end function ENT:GetHazardLights() - if self.v.IsScar then - elseif self.v.IsSimfphyscar then - return self.HazardLights - elseif vcmod_main - and isfunction(self.v.VC_getStates) then - local states = self.v:VC_getStates() - return istable(states) and states.HazardLights - elseif Photon - and isfunction(self.v.CAR_Hazards) then - return self.v:CAR_Hazards() - end + if self.v.IsScar then + elseif self.v.IsSimfphyscar then + return self.HazardLights + elseif vcmod_main + and isfunction(self.v.VC_getStates) then + local states = self.v:VC_getStates() + return istable(states) and states.HazardLights + elseif Photon + and isfunction(self.v.CAR_Hazards) then + return self.v:CAR_Hazards() + end end function ENT:GetELS(v) - local vehicle = v or self.v - if not (IsValid(vehicle) and vehicle:IsVehicle()) then return end - if vehicle.IsScar then - return vehicle.SirenIsOn - elseif vehicle.IsSimfphyscar then - return vehicle:GetEMSEnabled() - elseif vcmod_main and vcmod_els - and isfunction(vehicle.VC_getELSLightsOn) then - return vehicle:VC_getELSLightsOn() - elseif Photon - and isfunction(self.v.ELS_Siren) - and isfunction(self.v.ELS_Lights) then - return self.v:ELS_Siren() and self.v:ELS_Lights() - end + local vehicle = v or self.v + if not (IsValid(vehicle) and vehicle:IsVehicle()) then return end + if vehicle.IsScar then + return vehicle.SirenIsOn + elseif vehicle.IsSimfphyscar then + return vehicle:GetEMSEnabled() + elseif vcmod_main and vcmod_els + and isfunction(vehicle.VC_getELSLightsOn) then + return vehicle:VC_getELSLightsOn() + elseif Photon + and isfunction(self.v.ELS_Siren) + and isfunction(self.v.ELS_Lights) then + return self.v:ELS_Siren() and self.v:ELS_Lights() + end end function ENT:GetELSSound(v) - local vehicle = v or self.v - if not (IsValid(vehicle) and vehicle:IsVehicle()) then return end - if vehicle.IsScar then - return vehicle.SirenIsOn - elseif vehicle.IsSimfphyscar then - return vehicle.ems and vehicle.ems:IsPlaying() - elseif vcmod_main and vcmod_els - and isfunction(vehicle.VC_getELSSoundOn) - and isfunction(vehicle.VC_getStates) then - local states = vehicle:VC_getStates() - return vehicle:VC_getELSSoundOn() or istable(states) and states.ELS_ManualOn - elseif Photon - and isfunction(self.v.ELS_Siren) then - return self.v:ELS_Siren() - end + local vehicle = v or self.v + if not (IsValid(vehicle) and vehicle:IsVehicle()) then return end + if vehicle.IsScar then + return vehicle.SirenIsOn + elseif vehicle.IsSimfphyscar then + return vehicle.ems and vehicle.ems:IsPlaying() + elseif vcmod_main and vcmod_els + and isfunction(vehicle.VC_getELSSoundOn) + and isfunction(vehicle.VC_getStates) then + local states = vehicle:VC_getStates() + return vehicle:VC_getELSSoundOn() or istable(states) and states.ELS_ManualOn + elseif Photon + and isfunction(self.v.ELS_Siren) then + return self.v:ELS_Siren() + end end function ENT:GetHorn(v) - local vehicle = v or self.v - if not (IsValid(vehicle) and vehicle:IsVehicle()) then return end - if vehicle.IsScar then - return vehicle.Horn:IsPlaying() - elseif vehicle.IsSimfphyscar then - return vehicle.HornKeyIsDown - elseif vcmod_main - and isfunction(vehicle.VC_getStates) then - local states = vehicle:VC_getStates() - return istable(states) and states.HornOn - elseif Photon - and isnumber(EMV_HORN) - and isfunction(vehicle.ELS_Horn) then - return vehicle:GetDTBool(EMV_HORN) - end + local vehicle = v or self.v + if not (IsValid(vehicle) and vehicle:IsVehicle()) then return end + if vehicle.IsScar then + return vehicle.Horn:IsPlaying() + elseif vehicle.IsSimfphyscar then + return vehicle.HornKeyIsDown + elseif vcmod_main + and isfunction(vehicle.VC_getStates) then + local states = vehicle:VC_getStates() + return istable(states) and states.HornOn + elseif Photon + and isnumber(EMV_HORN) + and isfunction(vehicle.ELS_Horn) then + return vehicle:GetDTBool(EMV_HORN) + end end function ENT:GetLocked(v) - local vehicle = v or self.v - if not (IsValid(vehicle) and vehicle:IsVehicle()) then return end - if vehicle.IsScar then - return vehicle:IsLocked() - elseif vehicle.IsSimfphyscar then - return vehicle.VehicleLocked - elseif vcmod_main - and isfunction(vehicle.VC_isLocked) then - return vehicle:VC_isLocked() - else - return tonumber(vehicle:GetKeyValues().VehicleLocked) ~= 0 - end + local vehicle = v or self.v + if not (IsValid(vehicle) and vehicle:IsVehicle()) then return end + if vehicle.IsScar then + return vehicle:IsLocked() + elseif vehicle.IsSimfphyscar then + return vehicle.VehicleLocked + elseif vcmod_main + and isfunction(vehicle.VC_isLocked) then + return vehicle:VC_isLocked() + else + return tonumber(vehicle:GetKeyValues().VehicleLocked) ~= 0 + end end function ENT:GetEngineStarted(v) - local vehicle = v or self.v - if not (IsValid(vehicle) and vehicle:IsVehicle()) then return end - if vehicle.IsScar then - return vehicle.IsOn - elseif vehicle.IsSimfphyscar then - return vehicle:EngineActive() - else - return vehicle:IsEngineStarted() - end + local vehicle = v or self.v + if not (IsValid(vehicle) and vehicle:IsVehicle()) then return end + if vehicle.IsScar then + return vehicle.IsOn + elseif vehicle.IsSimfphyscar then + return vehicle:EngineActive() + else + return vehicle:IsEngineStarted() + end end function ENT:SetRunningLights(on) - local lightlevel = TurnOnLights:GetInt() - on = on and lightlevel ~= LIGHTLEVEL.NONE - if on == self:GetRunningLights() then return end - if self.v.IsScar then - elseif self.v.IsSimfphyscar then - self.SimfphysRunningLights = on - self.v:SetFogLightsEnabled(not on) - numpad.Activate(self, KEY_V, false) - self.keystate = nil - elseif vcmod_main - and isfunction(self.v.VC_setRunningLights) then - self.v:VC_setRunningLights(on) - end + local lightlevel = TurnOnLights:GetInt() + on = on and lightlevel ~= LIGHTLEVEL.NONE + if on == self:GetRunningLights() then return end + if self.v.IsScar then + elseif self.v.IsSimfphyscar then + self.SimfphysRunningLights = on + self.v:SetFogLightsEnabled(not on) + numpad.Activate(self, KEY_V, false) + self.keystate = nil + elseif vcmod_main + and isfunction(self.v.VC_setRunningLights) then + self.v:VC_setRunningLights(on) + end end function ENT:SetFogLights(on) - local lightlevel = TurnOnLights:GetInt() - on = on and lightlevel == LIGHTLEVEL.ALL - if on == self:GetFogLights() then return end - if self.v.IsScar then - elseif self.v.IsSimfphyscar then - self.SimfphysFogLights = on - self.v:SetFogLightsEnabled(not on) - numpad.Activate(self, KEY_V, false) - self.keystate = nil - elseif vcmod_main - and isfunction(self.v.VC_setFogLights) then - self.v:VC_setFogLights(on) - end + local lightlevel = TurnOnLights:GetInt() + on = on and lightlevel == LIGHTLEVEL.ALL + if on == self:GetFogLights() then return end + if self.v.IsScar then + elseif self.v.IsSimfphyscar then + self.SimfphysFogLights = on + self.v:SetFogLightsEnabled(not on) + numpad.Activate(self, KEY_V, false) + self.keystate = nil + elseif vcmod_main + and isfunction(self.v.VC_setFogLights) then + self.v:VC_setFogLights(on) + end end local function SCAREmulateKey(self, key, state, func, ...) - local dummy = player.GetByID(1) - local dummyinput = dummy.ScarSpecialKeyInput - local controller = self.v.AIController - self.v.AIController = dummy - dummy.ScarSpecialKeyInput = {[key] = state} - if isfunction(func) then func(self.v, ...) end - self.v.AIController = controller - dummy.ScarSpecialKeyInput = dummyinput + local dummy = player.GetByID(1) + local dummyinput = dummy.ScarSpecialKeyInput + local controller = self.v.AIController + self.v.AIController = dummy + dummy.ScarSpecialKeyInput = {[key] = state} + if isfunction(func) then func(self.v, ...) end + self.v.AIController = controller + dummy.ScarSpecialKeyInput = dummyinput end function ENT:SetLights(on, highbeams) - local lightlevel = TurnOnLights:GetInt() - on = on and lightlevel >= LIGHTLEVEL.HEADLIGHTS - if self.v.IsScar then - if on == self:GetLights() then return end - self.v.IncreaseFrontLightCol = not on - SCAREmulateKey(self, "ToggleHeadlights", 3, self.v.UpdateLights) - elseif self.v.IsSimfphyscar then - local LightsActivated = self:GetLights() - if on ~= LightsActivated then - self.v.LightsActivated = not on - self.v.KeyPressedTime = CurTime() - .23 - numpad.Deactivate(self, KEY_F, false) - end - - if on and highbeams ~= self:GetLights(true) then - self.v.LampsActivated = not highbeams - self.v.KeyPressedTime = CurTime() - if LightsActivated then - numpad.Deactivate(self, KEY_F, false) - else - timer.Simple(.05, function() - if not (IsValid(self) and IsValid(self.v)) then return end - numpad.Deactivate(self, KEY_F, false) - end) - end - end - - self.keystate = nil - elseif vcmod_main - and isfunction(self.v.VC_setHighBeams) - and isfunction(self.v.VC_setLowBeams) then - if on == self:GetLights(highbeams) then return end - if highbeams then - self.v:VC_setHighBeams(on) - else - self.v:VC_setLowBeams(on) - end - elseif Photon - and isfunction(self.v.ELS_IllumOn) - and isfunction(self.v.ELS_IllumOff) - and isfunction(self.v.ELS_Illuminate) then - if on == self:GetLights(highbeams) then return end - if on then - self.v:ELS_IllumOn() - else - self.v:ELS_IllumOff() - end - end + local lightlevel = TurnOnLights:GetInt() + on = on and lightlevel >= LIGHTLEVEL.HEADLIGHTS + if self.v.IsScar then + if on == self:GetLights() then return end + self.v.IncreaseFrontLightCol = not on + SCAREmulateKey(self, "ToggleHeadlights", 3, self.v.UpdateLights) + elseif self.v.IsSimfphyscar then + local LightsActivated = self:GetLights() + if on ~= LightsActivated then + self.v.LightsActivated = not on + self.v.KeyPressedTime = CurTime() - .23 + numpad.Deactivate(self, KEY_F, false) + end + + if on and highbeams ~= self:GetLights(true) then + self.v.LampsActivated = not highbeams + self.v.KeyPressedTime = CurTime() + if LightsActivated then + numpad.Deactivate(self, KEY_F, false) + else + timer.Simple(.05, function() + if not (IsValid(self) and IsValid(self.v)) then return end + numpad.Deactivate(self, KEY_F, false) + end) + end + end + + self.keystate = nil + elseif vcmod_main + and isfunction(self.v.VC_setHighBeams) + and isfunction(self.v.VC_setLowBeams) then + if on == self:GetLights(highbeams) then return end + if highbeams then + self.v:VC_setHighBeams(on) + else + self.v:VC_setLowBeams(on) + end + elseif Photon + and isfunction(self.v.ELS_IllumOn) + and isfunction(self.v.ELS_IllumOff) + and isfunction(self.v.ELS_Illuminate) then + if on == self:GetLights(highbeams) then return end + if on then + self.v:ELS_IllumOn() + else + self.v:ELS_IllumOff() + end + end end local SIMFPHYS = {OFF = 0, HAZARD = 1, LEFT = 2, RIGHT = 3} function ENT:SetTurnLight(on, left) - if on == self:GetTurnLight(left) then return end - if self.v.IsScar then - elseif self.v.IsSimfphyscar then - if player.GetCount() > 0 then - net.Start "simfphys_turnsignal" - net.WriteEntity(self.v) - net.WriteInt(on and (left and SIMFPHYS.LEFT or SIMFPHYS.RIGHT) or SIMFPHYS.OFF, 32) - net.Broadcast() - end - - self.TurnLightLeft = on and left - self.TurnLightRight = on and not left - self.HazardLights = false - elseif vcmod_main - and isfunction(self.v.VC_setTurnLightLeft) - and isfunction(self.v.VC_setTurnLightRight) then - self.v:VC_setTurnLightLeft(on and left) - self.v:VC_setTurnLightRight(on and not left) - elseif Photon - and isfunction(self.v.CAR_TurnLeft) - and isfunction(self.v.CAR_TurnRight) - and isfunction(self.v.CAR_StopSignals) then - if on then - if left then - self.v:CAR_TurnLeft(true) - else - self.v:CAR_TurnRight(true) - end - else - self.v:CAR_StopSignals() - end - end + if on == self:GetTurnLight(left) then return end + if self.v.IsScar then + elseif self.v.IsSimfphyscar then + if player.GetCount() > 0 then + net.Start "simfphys_turnsignal" + net.WriteEntity(self.v) + net.WriteInt(on and (left and SIMFPHYS.LEFT or SIMFPHYS.RIGHT) or SIMFPHYS.OFF, 32) + net.Broadcast() + end + + self.TurnLightLeft = on and left + self.TurnLightRight = on and not left + self.HazardLights = false + elseif vcmod_main + and isfunction(self.v.VC_setTurnLightLeft) + and isfunction(self.v.VC_setTurnLightRight) then + self.v:VC_setTurnLightLeft(on and left) + self.v:VC_setTurnLightRight(on and not left) + elseif Photon + and isfunction(self.v.CAR_TurnLeft) + and isfunction(self.v.CAR_TurnRight) + and isfunction(self.v.CAR_StopSignals) then + if on then + if left then + self.v:CAR_TurnLeft(true) + else + self.v:CAR_TurnRight(true) + end + else + self.v:CAR_StopSignals() + end + end end function ENT:SetHazardLights(on) - if on == self:GetHazardLights() then return end - if self.v.IsScar then - elseif self.v.IsSimfphyscar then - if player.GetCount() > 0 then - net.Start "simfphys_turnsignal" - net.WriteEntity(self.v) - net.WriteInt(on and SIMFPHYS.HAZARD or SIMFPHYS.OFF, 32) - net.Broadcast() - end - - self.TurnLightLeft = false - self.TurnLightRight = false - self.HazardLights = true - elseif vcmod_main - and isfunction(self.v.VC_setHazardLights) then - self.v:VC_setHazardLights(on) - elseif Photon - and isfunction(self.v.CAR_Hazards) - and isfunction(self.v.CAR_StopSignals) then - if on then - self.v:CAR_Hazards(true) - else - self.v:CAR_StopSignals() - end - end + if on == self:GetHazardLights() then return end + if self.v.IsScar then + elseif self.v.IsSimfphyscar then + if player.GetCount() > 0 then + net.Start "simfphys_turnsignal" + net.WriteEntity(self.v) + net.WriteInt(on and SIMFPHYS.HAZARD or SIMFPHYS.OFF, 32) + net.Broadcast() + end + + self.TurnLightLeft = false + self.TurnLightRight = false + self.HazardLights = true + elseif vcmod_main + and isfunction(self.v.VC_setHazardLights) then + self.v:VC_setHazardLights(on) + elseif Photon + and isfunction(self.v.CAR_Hazards) + and isfunction(self.v.CAR_StopSignals) then + if on then + self.v:CAR_Hazards(true) + else + self.v:CAR_StopSignals() + end + end end function ENT:SetELS(on) - if on == self:GetELS() then return end - if self.v.IsScar then - if self.v.SirenIsOn == nil then return end - if not self.v.SirenSound then return end - if on then self:SetHorn(false) end - self.v.SirenIsOn = on - self.v:SetNWBool("SirenIsOn", on) - if on then - self.v.SirenSound:Play() - else - self.v.SirenSound:Stop() - end - elseif self.v.IsSimfphyscar then - local dt = on and 0 or .5 - self.v.emson = not on - self.v.KeyPressedTime = CurTime() - dt - numpad.Deactivate(self, KEY_H, false) - elseif vcmod_main and vcmod_els - and isfunction(self.v.VC_setELSLights) - and isfunction(self.v.VC_setELSSound) then - self.v:VC_setELSLights(on) - self.v:VC_setELSSound(on) - elseif Photon - and isfunction(self.v.ELS_SirenOn) - and isfunction(self.v.ELS_SirenOff) - and isfunction(self.v.ELS_LightsOff) then - if on then - self.v:ELS_SirenOn() - else - self.v:ELS_SirenOff() - self.v:ELS_LightsOff() - end - end + if on == self:GetELS() then return end + if self.v.IsScar then + if self.v.SirenIsOn == nil then return end + if not self.v.SirenSound then return end + if on then self:SetHorn(false) end + self.v.SirenIsOn = on + self.v:SetNWBool("SirenIsOn", on) + if on then + self.v.SirenSound:Play() + else + self.v.SirenSound:Stop() + end + elseif self.v.IsSimfphyscar then + local dt = on and 0 or .5 + self.v.emson = not on + self.v.KeyPressedTime = CurTime() - dt + numpad.Deactivate(self, KEY_H, false) + elseif vcmod_main and vcmod_els + and isfunction(self.v.VC_setELSLights) + and isfunction(self.v.VC_setELSSound) then + self.v:VC_setELSLights(on) + self.v:VC_setELSSound(on) + elseif Photon + and isfunction(self.v.ELS_SirenOn) + and isfunction(self.v.ELS_SirenOff) + and isfunction(self.v.ELS_LightsOff) then + if on then + self.v:ELS_SirenOn() + else + self.v:ELS_SirenOff() + self.v:ELS_LightsOff() + end + end end function ENT:SetELSSound(on) - if on == self:GetELSSound() then return end - if self.v.IsScar then - if not self.v.SirenSound then return end - if on then - self.v.SirenSound:Play() - else - self.v.SirenSound:Stop() - end - elseif self.v.IsSimfphyscar then - if self.v.ems then - if on and not self.v.ems:IsPlaying() then - self.v.ems:Play() - elseif not on and self.v.ems:IsPlaying() then - self.v.ems:Stop() - end - end - elseif vcmod_main and vcmod_els - and isfunction(self.v.VC_setELSSound) then - self.v:VC_setELSSound(on) - elseif Photon - and isfunction(self.v.ELS_SirenOn) - and isfunction(self.v.ELS_SirenOff) - and isfunction(self.v.ELS_LightsOff) then - if on then - self.v:ELS_SirenOn() - else - self.v:ELS_SirenOff() - end - - self.v:ELS_LightsOff() - end + if on == self:GetELSSound() then return end + if self.v.IsScar then + if not self.v.SirenSound then return end + if on then + self.v.SirenSound:Play() + else + self.v.SirenSound:Stop() + end + elseif self.v.IsSimfphyscar then + if self.v.ems then + if on and not self.v.ems:IsPlaying() then + self.v.ems:Play() + elseif not on and self.v.ems:IsPlaying() then + self.v.ems:Stop() + end + end + elseif vcmod_main and vcmod_els + and isfunction(self.v.VC_setELSSound) then + self.v:VC_setELSSound(on) + elseif Photon + and isfunction(self.v.ELS_SirenOn) + and isfunction(self.v.ELS_SirenOff) + and isfunction(self.v.ELS_LightsOff) then + if on then + self.v:ELS_SirenOn() + else + self.v:ELS_SirenOff() + end + + self.v:ELS_LightsOff() + end end function ENT:SetHorn(on) - if on == self:GetHorn() then return end - if self.v.IsScar then - if on then - self.v:HornOn() - else - self.v:HornOff() - end - elseif self.v.IsSimfphyscar then - if on then - numpad.Activate(self, KEY_H, false) - else - self.v.HornKeyIsDown = false - end - elseif vcmod_main - and isfunction(self.v.VC_getStates) - and isfunction(self.v.VC_setStates) then - local states = self.v:VC_getStates() - if not istable(states) then return end - states.HornOn = true - self.v:VC_setStates(states) - elseif Photon - and isfunction(self.v.ELS_Horn) then - self.v:ELS_Horn(on) - end + if on == self:GetHorn() then return end + if self.v.IsScar then + if on then + self.v:HornOn() + else + self.v:HornOff() + end + elseif self.v.IsSimfphyscar then + if on then + numpad.Activate(self, KEY_H, false) + else + self.v.HornKeyIsDown = false + end + elseif vcmod_main + and isfunction(self.v.VC_getStates) + and isfunction(self.v.VC_setStates) then + local states = self.v:VC_getStates() + if not istable(states) then return end + states.HornOn = true + self.v:VC_setStates(states) + elseif Photon + and isfunction(self.v.ELS_Horn) then + self.v:ELS_Horn(on) + end end function ENT:SetLocked(locked) - if locked == self:GetLocked() then return end - if self.v.IsScar then - if locked then - self.v:Lock() - else - self.v:UnLock() - end - elseif self.v.IsSimfphyscar then - if locked then - self.v:Lock() - else - self.v:UnLock() - end - else - for _, seat in pairs(self.v:GetChildren()) do -- For Sligwolf's vehicles - if not (seat:IsVehicle() and seat.__SW_Vars) then continue end - seat:Fire(locked and "Lock" or "Unlock") - end - - if vcmod_main - and isfunction(self.v.VC_lock) - and isfunction(self.v.VC_unLock) then - if locked then - self.v:VC_lock() - else - self.v:VC_unLock() - end - else - self.v:Fire(locked and "Lock" or "Unlock") - end - end + if locked == self:GetLocked() then return end + if self.v.IsScar then + if locked then + self.v:Lock() + else + self.v:UnLock() + end + elseif self.v.IsSimfphyscar then + if locked then + self.v:Lock() + else + self.v:UnLock() + end + else + for _, seat in pairs(self.v:GetChildren()) do -- For Sligwolf's vehicles + if not (seat:IsVehicle() and seat.__SW_Vars) then continue end + seat:Fire(locked and "Lock" or "Unlock") + end + + if vcmod_main + and isfunction(self.v.VC_lock) + and isfunction(self.v.VC_unLock) then + if locked then + self.v:VC_lock() + else + self.v:VC_unLock() + end + else + self.v:Fire(locked and "Lock" or "Unlock") + end + end end function ENT:SetEngineStarted(on) - if on == self:GetEngineStarted() then return end - if self.v.IsScar then -- SCAR automatically starts the engine. - self:SetLocked(not on) - self.v.AIController = on and self or nil - if not on then self.v:TurnOffCar() end - elseif self.v.IsSimfphyscar then - self.v:SetActive(on) - if on then - self.v:StartEngine() - else - self.v:StopEngine() - end - elseif isfunction(self.v.StartEngine) then - self.v:StartEngine(on) - end + if on == self:GetEngineStarted() then return end + if self.v.IsScar then -- SCAR automatically starts the engine. + self:SetLocked(not on) + self.v.AIController = on and self or nil + if not on then self.v:TurnOffCar() end + elseif self.v.IsSimfphyscar then + self.v:SetActive(on) + if on then + self.v:StartEngine() + else + self.v:StopEngine() + end + elseif isfunction(self.v.StartEngine) then + self.v:StartEngine(on) + end end function ENT:SetHandbrake(brake) - self.HandBrake = brake - if self.v.IsScar then - if brake then - self.v:HandBrakeOn() - else - self.v:HandBrakeOff() - end - elseif self.v.IsSimfphyscar then - self.v.PressedKeys.Space = brake - elseif isfunction(self.v.SetHandbrake) then - self.v:SetHandbrake(brake) - end + self.HandBrake = brake + if self.v.IsScar then + if brake then + self.v:HandBrakeOn() + else + self.v:HandBrakeOff() + end + elseif self.v.IsSimfphyscar then + self.v.PressedKeys.Space = brake + elseif isfunction(self.v.SetHandbrake) then + self.v:SetHandbrake(brake) + end end function ENT:SetThrottle(throttle) - self.Throttle = throttle - if self.v.IsScar then - if throttle > 0 then - self.v:GoForward(throttle) - elseif throttle < 0 then - self.v:GoBack(-throttle) - else - self.v:GoNeutral() - end - elseif self.v.IsSimfphyscar then - self.v.PressedKeys.W = throttle > .01 - self.v.PressedKeys.S = throttle < -.01 - elseif isfunction(self.v.SetThrottle) then - self.v:SetThrottle(throttle) - end + self.Throttle = throttle + if self.v.IsScar then + if throttle > 0 then + self.v:GoForward(throttle) + elseif throttle < 0 then + self.v:GoBack(-throttle) + else + self.v:GoNeutral() + end + elseif self.v.IsSimfphyscar then + self.v.PressedKeys.W = throttle > .01 + self.v.PressedKeys.S = throttle < -.01 + elseif isfunction(self.v.SetThrottle) then + self.v:SetThrottle(throttle) + end end function ENT:SetSteering(steering) - steering = math.Clamp(steering, -1, 1) - self.Steering = steering - if self.v.IsScar then - if steering > 0 then - self.v:TurnRight(steering) - elseif steering < 0 then - self.v:TurnLeft(-steering) - else - self.v:NotTurning() - end - elseif self.v.IsSimfphyscar then - local s = self.v:GetVehicleSteer() - self.v:PlayerSteerVehicle(self, -math.min(steering, 0), math.max(steering, 0)) - self.v.PressedKeys.A = steering < -.01 and steering < s and s < 0 - self.v.PressedKeys.D = steering > .01 and 0 < s and s < steering - elseif isfunction(self.v.SetSteering) then - self.v:SetSteering(steering, 0) - end - - local pose = self:GetPoseParameter "vehicle_steer" or 0 - self:SetPoseParameter("vehicle_steer", pose + (steering - pose) / 10) + steering = math.Clamp(steering, -1, 1) + self.Steering = steering + if self.v.IsScar then + if steering > 0 then + self.v:TurnRight(steering) + elseif steering < 0 then + self.v:TurnLeft(-steering) + else + self.v:NotTurning() + end + elseif self.v.IsSimfphyscar then + local s = self.v:GetVehicleSteer() + self.v:PlayerSteerVehicle(self, -math.min(steering, 0), math.max(steering, 0)) + self.v.PressedKeys.A = steering < -.01 and steering < s and s < 0 + self.v.PressedKeys.D = steering > .01 and 0 < s and s < steering + elseif isfunction(self.v.SetSteering) then + self.v:SetSteering(steering, 0) + end + + local pose = self:GetPoseParameter "vehicle_steer" or 0 + self:SetPoseParameter("vehicle_steer", pose + (steering - pose) / 10) end diff --git a/lua/entities/npc_decentvehicle/cl_init.lua b/lua/entities/npc_decentvehicle/cl_init.lua index 277f601..d7e2abf 100644 --- a/lua/entities/npc_decentvehicle/cl_init.lua +++ b/lua/entities/npc_decentvehicle/cl_init.lua @@ -8,17 +8,17 @@ include "playermeta.lua" local dvd = DecentVehicleDestination function ENT:Think() - self:SetDriverPosition() - self:SetSequence(self:GetNWInt "Sequence") + self:SetDriverPosition() + self:SetSequence(self:GetNWInt "Sequence") end function ENT:Draw() - local seat = self:GetNWEntity "Seat" - if IsValid(seat) then - self:SetPos(seat:LocalToWorld(self:GetNWVector "Pos")) - self:SetAngles(seat:LocalToWorldAngles(self:GetNWAngle "Ang")) - self:SetupBones() - end - - self:DrawModel() + local seat = self:GetNWEntity "Seat" + if IsValid(seat) then + self:SetPos(seat:LocalToWorld(self:GetNWVector "Pos")) + self:SetAngles(seat:LocalToWorldAngles(self:GetNWAngle "Ang")) + self:SetupBones() + end + + self:DrawModel() end diff --git a/lua/entities/npc_decentvehicle/init.lua b/lua/entities/npc_decentvehicle/init.lua index db76ce9..3503cee 100644 --- a/lua/entities/npc_decentvehicle/init.lua +++ b/lua/entities/npc_decentvehicle/init.lua @@ -17,76 +17,76 @@ local CorrectFindInSphere = ents.FindInSphere local HasFixedOnLocalizedPhysics = false local VCModFixedAroundNPCDriver = false -- This is a stupid solution. for _, a in ipairs(engine.GetAddons()) do - if tonumber(a.wsid) == 531849338 then - CorrectFindInSphere = ents.RealFindInSphere or CorrectFindInSphere - if not ents.RealFindInSphere then -- Just to make sure - timer.Simple(1, function() - CorrectFindInSphere = ents.RealFindInSphere or CorrectFindInSphere - end) - end - end + if tonumber(a.wsid) == 531849338 then + CorrectFindInSphere = ents.RealFindInSphere or CorrectFindInSphere + if not ents.RealFindInSphere then -- Just to make sure + timer.Simple(1, function() + CorrectFindInSphere = ents.RealFindInSphere or CorrectFindInSphere + end) + end + end end -ENT.sPID = Vector(1, 0, 0) -- PID parameters for steering -ENT.tPID = Vector(1, 0, 0) -- PID parameters for throttle -ENT.Throttle = 0 -ENT.Steering = 0 -ENT.HandBrake = false -ENT.Waypoint = nil -ENT.NextWaypoint = nil -ENT.PrevWaypoint = nil -ENT.WaypointList = {} -- For navigation -ENT.WaypointOffset = 0 -- For giving way -ENT.SteeringInt = 0 -- Steering integration -ENT.SteeringOld = 0 -- Steering difference = (diff - self.SteeringOld) / FrameTime() -ENT.ThrottleInt = 0 -- Throttle integration -ENT.ThrottleOld = 0 -- Throttle difference = (diff - self.ThrottleOld) / FrameTime() -ENT.Prependicular = 0 -- If the next waypoint needs to turn quickly, this is close to 1. -ENT.RelativeSpeed = 0 -- Current speed / maximum speed -ENT.WaitUntilNext = CurTime() -ENT.RefuelThreshold = .25 -- If the fuel is less than this fraction, the vehicle finds a fuel station. -ENT.MaxSpeedCoefficient = 1 -- Multiplying this on the maximum speed of the vehicle. -ENT.UseLeftTurnLight = false -- Which turn light the vehicle should turn on. -ENT.Emergency = CurTime() -ENT.IsGivingWay = CurTime() -- Giving way if CurTime() < ENT.IsGivingWay -ENT.NextDoLights = CurTime() -ENT.NextGiveWay = CurTime() -ENT.NextTrace = CurTime() -ENT.StopByTrace = CurTime() +ENT.sPID = Vector(1, 0, 0) -- PID parameters for steering +ENT.tPID = Vector(1, 0, 0) -- PID parameters for throttle +ENT.Throttle = 0 +ENT.Steering = 0 +ENT.HandBrake = false +ENT.Waypoint = nil +ENT.NextWaypoint = nil +ENT.PrevWaypoint = nil +ENT.WaypointList = {} -- For navigation +ENT.WaypointOffset = 0 -- For giving way +ENT.SteeringInt = 0 -- Steering integration +ENT.SteeringOld = 0 -- Steering difference = (diff - self.SteeringOld) / FrameTime() +ENT.ThrottleInt = 0 -- Throttle integration +ENT.ThrottleOld = 0 -- Throttle difference = (diff - self.ThrottleOld) / FrameTime() +ENT.Prependicular = 0 -- If the next waypoint needs to turn quickly, this is close to 1. +ENT.RelativeSpeed = 0 -- Current speed / maximum speed +ENT.WaitUntilNext = CurTime() +ENT.RefuelThreshold = .25 -- If the fuel is less than this fraction, the vehicle finds a fuel station. +ENT.MaxSpeedCoefficient = 1 -- Multiplying this on the maximum speed of the vehicle. +ENT.UseLeftTurnLight = false -- Which turn light the vehicle should turn on. +ENT.Emergency = CurTime() +ENT.IsGivingWay = CurTime() -- Giving way if CurTime() < ENT.IsGivingWay +ENT.NextDoLights = CurTime() +ENT.NextGiveWay = CurTime() +ENT.NextTrace = CurTime() +ENT.StopByTrace = CurTime() ENT.Preference = { -- Some preferences for Decent Vehicle here - DoTrace = true, -- Whether or not it does some traces - GiveWay = true, -- Whether or not it gives way for vehicles with ELS - GiveWayTime = 5, -- Time to reset the offset for giving way - GobackDuration = 0.7, -- Duration of going back on stuck - GobackTime = 10, -- Time to start going back on stuck - LockVehicle = false, -- Whether or not it allows other players to get in - LockVehicleDependsOnCVar = true, -- Whether or not LockVehicle depends on CVar - ShouldGoback = true, -- Whether or not it should go backward on stuck - StopAtTL = true, -- Whether or not it stops at traffic lights with red sign - StopEmergency = true, -- Whether or not it stops on crash - StopEmergencyDuration = 5, -- Duration of stopping on crash - StopEmergencyDurationDependsOnCVar = true, -- Same as LockVehicle, but for StopEmergencyDuration - StopInfrontofPerson = true, -- Whether or not it stops when it sees something in front of it - StopInfrontofPersonDependsOnCVar = true, -- Same as LockVehicle, but for StopInfrontofPerson - TraceMaxBound = 64, -- Maximum hull size of trace: max = Vector(1, 1, 1) * this value, min = -max - TraceMinLength = 200, -- Minimum trace length in hammer units - WaitUntilNext = true, -- Whether or not it waits on WaitUntilNext + DoTrace = true, -- Whether or not it does some traces + GiveWay = true, -- Whether or not it gives way for vehicles with ELS + GiveWayTime = 5, -- Time to reset the offset for giving way + GobackDuration = 0.7, -- Duration of going back on stuck + GobackTime = 10, -- Time to start going back on stuck + LockVehicle = false, -- Whether or not it allows other players to get in + LockVehicleDependsOnCVar = true, -- Whether or not LockVehicle depends on CVar + ShouldGoback = true, -- Whether or not it should go backward on stuck + StopAtTL = true, -- Whether or not it stops at traffic lights with red sign + StopEmergency = true, -- Whether or not it stops on crash + StopEmergencyDuration = 5, -- Duration of stopping on crash + StopEmergencyDurationDependsOnCVar = true, -- Same as LockVehicle, but for StopEmergencyDuration + StopInfrontofPerson = true, -- Whether or not it stops when it sees something in front of it + StopInfrontofPersonDependsOnCVar = true, -- Same as LockVehicle, but for StopInfrontofPerson + TraceMaxBound = 64, -- Maximum hull size of trace: max = Vector(1, 1, 1) * this value, min = -max + TraceMinLength = 200, -- Minimum trace length in hammer units + WaitUntilNext = true, -- Whether or not it waits on WaitUntilNext } ENT.Interval = { -- The interval of execution. - DoLights = 1 / 10, -- Checking lights - GiveWay = 1 / 20, -- Checking for giving way - Trace = 1 / 15, -- The time between doing a trace and next time. + DoLights = 1 / 10, -- Checking lights + GiveWay = 1 / 20, -- Checking for giving way + Trace = 1 / 15, -- The time between doing a trace and next time. } -- Constant values used in Atmos -local TIME_NOON = 12 -- 12:00 pm -local TIME_MIDNIGHT = 0 -- 12:00 am -local TIME_DAWN_START = 4 -- 4:00 am -local TIME_DAWN_END = 6.5 -- 6:30 am -local TIME_DUSK_START = 19 -- 7:00 pm -local TIME_DUSK_END = 20.5 -- 8:30 pm +local TIME_NOON = 12 -- 12:00 pm +local TIME_MIDNIGHT = 0 -- 12:00 am +local TIME_DAWN_START = 4 -- 4:00 am +local TIME_DAWN_END = 6.5 -- 6:30 am +local TIME_DUSK_START = 19 -- 7:00 pm +local TIME_DUSK_END = 20.5 -- 8:30 pm local dvd = DecentVehicleDestination local vector_one = Vector(1, 1, 1) @@ -104,511 +104,511 @@ local DriveSide = dvd.CVars.DriveSide local LockVehicle = dvd.CVars.LockVehicle local StopInfrontofPerson = dvd.CVars.StopInfrontofPerson local Interval = { - DoLights = 1 / 10, - GiveWay = 1 / 20, - Trace = 1 / 20, -- DV will trace 20 times per second by default + DoLights = 1 / 10, + GiveWay = 1 / 20, + Trace = 1 / 20, -- DV will trace 20 times per second by default } local NightSkyTextureList = { - sky_borealis01 = true, - sky_day01_09 = true, - sky_day02_09 = true, + sky_borealis01 = true, + sky_day01_09 = true, + sky_day02_09 = true, } local function IsObstacle(tr) - return tr and (IsValid(tr.Entity) or tr.HitWorld and tr.HitNormal:Dot(vector_up) < .7) + return tr and (IsValid(tr.Entity) or tr.HitWorld and tr.HitNormal:Dot(vector_up) < .7) end -- A filter function of selecting a next waypoint. local function FilterUTurnAndGroup(self, waypoint, n) - if not dvd.WaypointAvailable(n, self.Group) then return false end - local pos = self.v:GetPos() - local w = dvd.Waypoints[n] - if waypoint.Target:DistToSqr(pos) < 1e4 then return true end - return (waypoint.Target - pos):Dot(w.Target - waypoint.Target) > 0 + if not dvd.WaypointAvailable(n, self.Group) then return false end + local pos = self.v:GetPos() + local w = dvd.Waypoints[n] + if waypoint.Target:DistToSqr(pos) < 1e4 then return true end + return (waypoint.Target - pos):Dot(w.Target - waypoint.Target) > 0 end local function GetNight() - if dvd.CVars.ForceHeadlights:GetBool() then return true end - if istable(StormFox) then return StormFox.IsNight() end - if istable(AtmosGlobal) and isnumber(AtmosGlobal.m_Time) then - local t = AtmosGlobal.m_Time - return t > TIME_DUSK_END or t < TIME_DAWN_END - end - - local skyname = GetConVar "sv_skyname" :GetString() - return NightSkyTextureList[skyname] or tobool(skyname:lower():find "night") + if dvd.CVars.ForceHeadlights:GetBool() then return true end + if istable(StormFox) then return StormFox.IsNight() end + if istable(AtmosGlobal) and isnumber(AtmosGlobal.m_Time) then + local t = AtmosGlobal.m_Time + return t > TIME_DUSK_END or t < TIME_DAWN_END + end + + local skyname = GetConVar "sv_skyname" :GetString() + return NightSkyTextureList[skyname] or tobool(skyname:lower():find "night") end local function GetFogInfo() - local FogEditor = ents.FindByClass "edit_fog" - for i, f in ipairs(FogEditor) do - if istable(FogEditor) or FogEditor:EntIndex() < f:EntIndex() then - FogEditor = f - end - end - - if IsValid(FogEditor) and isfunction(FogEditor.GetFogEnd) then - return true, FogEditor:GetFogEnd() - end - - if not StormFox then - local FogTable = ents.FindByClass "env_fog_controller" - local FogController - for i = 1, #FogTable do - local f = FogTable[i] - if not IsValid(f) then continue end - if IsValid(FogController) and FogController:EntIndex() > f:EntIndex() then continue end - FogController = f - end - - if not IsValid(FogController) then return false, 0 end - local keyvalues = FogController:GetKeyValues() - return keyvalues.fogenable > 0, keyvalues.fogend - end - - local enabled = GetConVar "sf_enablefog" - return enabled and enabled:GetBool() - and StormFox.GetWeather() == "Fog", StormFox.GetData "Fogend" + local FogEditor = ents.FindByClass "edit_fog" + for i, f in ipairs(FogEditor) do + if istable(FogEditor) or FogEditor:EntIndex() < f:EntIndex() then + FogEditor = f + end + end + + if IsValid(FogEditor) and isfunction(FogEditor.GetFogEnd) then + return true, FogEditor:GetFogEnd() + end + + if not StormFox then + local FogTable = ents.FindByClass "env_fog_controller" + local FogController + for i = 1, #FogTable do + local f = FogTable[i] + if not IsValid(f) then continue end + if IsValid(FogController) and FogController:EntIndex() > f:EntIndex() then continue end + FogController = f + end + + if not IsValid(FogController) then return false, 0 end + local keyvalues = FogController:GetKeyValues() + return keyvalues.fogenable > 0, keyvalues.fogend + end + + local enabled = GetConVar "sf_enablefog" + return enabled and enabled:GetBool() + and StormFox.GetWeather() == "Fog", StormFox.GetData "Fogend" end function ENT:CarCollide(data) - self = self.v and self or self.DecentVehicle - if not self then return end - if self.Preference.StopEmergency and data.Speed > 200 and not data.HitEntity:IsPlayer() then - local duration = self.Preference.StopEmergencyDuration - if not duration or self.Preference.StopEmergencyDurationDependsOnCVar then - duration = TimeToStopEmergency:GetFloat() - end - - self.Emergency = CurTime() + duration - end - - hook.Run("Decent Vehicle: OnCollide", self, data) + self = self.v and self or self.DecentVehicle + if not self then return end + if self.Preference.StopEmergency and data.Speed > 200 and not data.HitEntity:IsPlayer() then + local duration = self.Preference.StopEmergencyDuration + if not duration or self.Preference.StopEmergencyDurationDependsOnCVar then + duration = TimeToStopEmergency:GetFloat() + end + + self.Emergency = CurTime() + duration + end + + hook.Run("Decent Vehicle: OnCollide", self, data) end function ENT:EstimateAccel() - local accel = 0 - if self.v.IsScar then - local phys = self.v:GetPhysicsObject() - local velVec = phys:GetVelocity() - local vel = velVec:Length() - local dir = velVec:Dot(self:GetForward()) - local force = 1 - if self.v.DriveStatus == 1 then -- Brake or forward - if dir < 0 and vel > 40 then -- BRAKE - force = self.v.BreakForce - elseif self.v.IsOn and vel < self.v.MaxSpeed and self.v:HasFuel() then -- FORWARD - force = self.v.Acceleration - end - else -- Brake or reverse - if dir > vel * .9 and vel > 10 then -- BRAKE - force = self.v.BreakForce * 1.5 - elseif self.v.IsOn and vel < self.v.ReverseMaxSpeed and self.v:HasFuel() then -- REVERSE - force = self.v.ReverseForce - end - end - - accel = math.max(force * self.v.WheelTorqTraction, 1) - elseif self.v.IsSimfphyscar then - accel = self.v:GetMaxTorque() * 2 - math.Clamp(self.v.ForwardSpeed, -self.v.Brake, self.v.Brake) - else - local forward = self.v:GetForward() - local gearratio = self.GearRatio[self.v:GetOperatingParams().gear + 1] - local numwheels = self.v:GetWheelCount() - local wheelangvelocity = 0 - local wheeldirvelocity = 0 - local damping, rotdamping = 0, 0 - for i = 0, numwheels - 1 do - local w = self.v:GetWheel(i) - wheelangvelocity = wheelangvelocity + math.rad(math.abs(w:GetAngleVelocity().x)) / numwheels - wheeldirvelocity = wheeldirvelocity + w:GetVelocity():Dot(forward) / numwheels - end - - for i, a in ipairs(self.v:GetVehicleParams().axles) do - damping = damping + a.wheels_damping * wheeldirvelocity / a.wheels_mass - rotdamping = rotdamping + a.wheels_rotdamping * wheelangvelocity - end - - accel = 552 * (self.HorsePower * self.AxleRatio * gearratio - rotdamping * math.sqrt(2)) - * self.WheelCoefficient / self.Mass - damping * math.sqrt(2) + physenv.GetGravity():Dot(forward) - end - - return hook.Run("Decent Vehicle: EstimateAccel", self, accel) or accel + local accel = 0 + if self.v.IsScar then + local phys = self.v:GetPhysicsObject() + local velVec = phys:GetVelocity() + local vel = velVec:Length() + local dir = velVec:Dot(self:GetForward()) + local force = 1 + if self.v.DriveStatus == 1 then -- Brake or forward + if dir < 0 and vel > 40 then -- BRAKE + force = self.v.BreakForce + elseif self.v.IsOn and vel < self.v.MaxSpeed and self.v:HasFuel() then -- FORWARD + force = self.v.Acceleration + end + else -- Brake or reverse + if dir > vel * .9 and vel > 10 then -- BRAKE + force = self.v.BreakForce * 1.5 + elseif self.v.IsOn and vel < self.v.ReverseMaxSpeed and self.v:HasFuel() then -- REVERSE + force = self.v.ReverseForce + end + end + + accel = math.max(force * self.v.WheelTorqTraction, 1) + elseif self.v.IsSimfphyscar then + accel = self.v:GetMaxTorque() * 2 - math.Clamp(self.v.ForwardSpeed, -self.v.Brake, self.v.Brake) + else + local forward = self.v:GetForward() + local gearratio = self.GearRatio[self.v:GetOperatingParams().gear + 1] + local numwheels = self.v:GetWheelCount() + local wheelangvelocity = 0 + local wheeldirvelocity = 0 + local damping, rotdamping = 0, 0 + for i = 0, numwheels - 1 do + local w = self.v:GetWheel(i) + wheelangvelocity = wheelangvelocity + math.rad(math.abs(w:GetAngleVelocity().x)) / numwheels + wheeldirvelocity = wheeldirvelocity + w:GetVelocity():Dot(forward) / numwheels + end + + for i, a in ipairs(self.v:GetVehicleParams().axles) do + damping = damping + a.wheels_damping * wheeldirvelocity / a.wheels_mass + rotdamping = rotdamping + a.wheels_rotdamping * wheelangvelocity + end + + accel = 552 * (self.HorsePower * self.AxleRatio * gearratio - rotdamping * math.sqrt(2)) + * self.WheelCoefficient / self.Mass - damping * math.sqrt(2) + physenv.GetGravity():Dot(forward) + end + + return hook.Run("Decent Vehicle: EstimateAccel", self, accel) or accel end function ENT:GetVehicleParams() - if self.v.IsScar then - self.BrakePower = self.v.BreakForce / 1000 - self.MaxSpeed = self.v.MaxSpeed - self.MaxRevSpeed = self.v.ReverseMaxSpeed - self.Mass = self.v.CarMass - elseif self.v.IsSimfphyscar then - self.BrakePower = self.v:GetBrakePower() - self.Mass = self.v.Mass - self.MaxSpeed = self.Mass * self.v.Efficiency * self.v.PeakTorque / self.v.MaxGrip - self.MaxRevSpeed = self.MaxSpeed * math.abs(math.min(unpack(self.v.Gears)) / math.max(unpack(self.v.Gears))) - local positive_offset, num_positive, negative_offset, num_negative = 0, 0, 0, 0 - for _, w in ipairs(self.v.Wheels) do - local pos = self.v:WorldToLocal(w:GetPos()).y - if pos > 0 then - positive_offset, num_positive = positive_offset + pos, num_positive + 1 - else - negative_offset, num_negative = negative_offset + pos, num_negative + 1 - end - end - - self.WheelBase = positive_offset / math.max(num_positive, 1) - negative_offset / math.max(num_negative, 1) - elseif isfunction(self.v.GetVehicleParams) then - local params = self.v:GetVehicleParams() - local axles = params.axles - local body = params.body - local engine = params.engine - local steering = params.steering - self.BrakePower = 0 - self.AxleFactor = 0 - self.Mass = body.massOverride - self.WheelRadius = 0 - local minr, maxr = math.huge, -math.huge - for _, axle in ipairs(axles) do - self.BrakePower = self.BrakePower + axle.brakeFactor - self.AxleFactor = self.AxleFactor + axle.torqueFactor / axle.wheels_radius - self.Mass = self.Mass + axle.wheels_mass * params.wheelsPerAxle - self.WheelRadius = self.WheelRadius + axle.wheels_radius / #axles - minr, maxr = math.min(minr, axle.wheels_radius), math.max(maxr, axle.wheels_radius) - end - - self.WheelBase = #axles > 1 and axles[1].offset:Distance(axles[2].offset) or 1 - self.WheelRatio = minr / maxr - self.WheelCoefficient = 1 / math.sqrt(self.WheelRadius * self.WheelRatio) - self.BoostSpeed = engine.boostMaxSpeed - self.MaxSpeed = engine.maxSpeed - self.MaxRevSpeed = engine.maxRevSpeed - self.HorsePower = engine.horsepower - self.GearCount = engine.gearCount - self.GearRatio = engine.gearRatio - self.AxleRatio = engine.axleRatio - - self.SteeringParams = steering - self.SteeringExponent = steering.steeringExponent - self.SteeringSpeedFast = steering.speedFast - self.SteeringSpeedSlow = steering.speedSlow - self.SteeringAngleBoost = steering.degreesBoost - self.SteeringAngleFast = steering.degreesFast - self.SteeringAngleSlow = steering.degreesSlow - self.SteeringRateFast = steering.steeringRateFast - self.SteeringRateSlow = steering.steeringRateSlow - self.SteeringRestRateFast = steering.steeringRestRateFast - self.SteeringRestRateSlow = steering.steeringRestRateSlow - end + if self.v.IsScar then + self.BrakePower = self.v.BreakForce / 1000 + self.MaxSpeed = self.v.MaxSpeed + self.MaxRevSpeed = self.v.ReverseMaxSpeed + self.Mass = self.v.CarMass + elseif self.v.IsSimfphyscar then + self.BrakePower = self.v:GetBrakePower() + self.Mass = self.v.Mass + self.MaxSpeed = self.Mass * self.v.Efficiency * self.v.PeakTorque / self.v.MaxGrip + self.MaxRevSpeed = self.MaxSpeed * math.abs(math.min(unpack(self.v.Gears)) / math.max(unpack(self.v.Gears))) + local positive_offset, num_positive, negative_offset, num_negative = 0, 0, 0, 0 + for _, w in ipairs(self.v.Wheels) do + local pos = self.v:WorldToLocal(w:GetPos()).y + if pos > 0 then + positive_offset, num_positive = positive_offset + pos, num_positive + 1 + else + negative_offset, num_negative = negative_offset + pos, num_negative + 1 + end + end + + self.WheelBase = positive_offset / math.max(num_positive, 1) - negative_offset / math.max(num_negative, 1) + elseif isfunction(self.v.GetVehicleParams) then + local params = self.v:GetVehicleParams() + local axles = params.axles + local body = params.body + local engine = params.engine + local steering = params.steering + self.BrakePower = 0 + self.AxleFactor = 0 + self.Mass = body.massOverride + self.WheelRadius = 0 + local minr, maxr = math.huge, -math.huge + for _, axle in ipairs(axles) do + self.BrakePower = self.BrakePower + axle.brakeFactor + self.AxleFactor = self.AxleFactor + axle.torqueFactor / axle.wheels_radius + self.Mass = self.Mass + axle.wheels_mass * params.wheelsPerAxle + self.WheelRadius = self.WheelRadius + axle.wheels_radius / #axles + minr, maxr = math.min(minr, axle.wheels_radius), math.max(maxr, axle.wheels_radius) + end + + self.WheelBase = #axles > 1 and axles[1].offset:Distance(axles[2].offset) or 1 + self.WheelRatio = minr / maxr + self.WheelCoefficient = 1 / math.sqrt(self.WheelRadius * self.WheelRatio) + self.BoostSpeed = engine.boostMaxSpeed + self.MaxSpeed = engine.maxSpeed + self.MaxRevSpeed = engine.maxRevSpeed + self.HorsePower = engine.horsepower + self.GearCount = engine.gearCount + self.GearRatio = engine.gearRatio + self.AxleRatio = engine.axleRatio + + self.SteeringParams = steering + self.SteeringExponent = steering.steeringExponent + self.SteeringSpeedFast = steering.speedFast + self.SteeringSpeedSlow = steering.speedSlow + self.SteeringAngleBoost = steering.degreesBoost + self.SteeringAngleFast = steering.degreesFast + self.SteeringAngleSlow = steering.degreesSlow + self.SteeringRateFast = steering.steeringRateFast + self.SteeringRateSlow = steering.steeringRateSlow + self.SteeringRestRateFast = steering.steeringRestRateFast + self.SteeringRestRateSlow = steering.steeringRestRateSlow + end end function ENT:GetVehiclePrefix() - if self.v.IsScar then - return "SCAR_" - elseif self.v.IsSimfphyscar then - return "Simfphys_" - else - return "Source_" - end + if self.v.IsScar then + return "SCAR_" + elseif self.v.IsSimfphyscar then + return "Simfphys_" + else + return "Source_" + end end function ENT:GetVehicleIdentifier() - local id = "" - if self.v.IsScar then - id = self.v:GetClass() - elseif self.v.IsSimfphyscar then - id = self.v:GetModel() - else - id = self.v:GetModel() - end - - return self:GetVehiclePrefix() .. id + local id = "" + if self.v.IsScar then + id = self.v:GetClass() + elseif self.v.IsSimfphyscar then + id = self.v:GetModel() + else + id = self.v:GetModel() + end + + return self:GetVehiclePrefix() .. id end function ENT:AttachModel() - local seat = self.v - if self.v.IsScar then - seat = self.v.Seats and self.v.Seats[1] - elseif self.v.IsSimfphyscar then - seat = self.v.DriverSeat - end - - if not IsValid(seat) then return end - local anim = dvd.DriverAnimation[self:GetVehicleIdentifier()] or dvd.DriverAnimation[self:GetVehiclePrefix()] or "drive_jeep" - self:SetModel(istable(self.Model) and self.Model[math.random(#self.Model)] - or self.Model or dvd.DefaultDriverModel[math.random(#dvd.DefaultDriverModel)]) - self:SetNWEntity("Seat", seat) - self:SetNWEntity("Vehicle", self.v) - self:SetNWInt("Sequence", self:LookupSequence(anim)) - self:SetParent(seat) - seat:SetSequence(0) -- Resets the sequence first to correct the seat position - - timer.Simple(.1, function() -- Entity:Sequence() will not work properly if it is - if not IsValid(seat) then return end -- called directly after calling Entity:SetModel(). - if not IsValid(self) then return end - if not IsValid(self.v) then return end - local a = seat:GetAttachment(assert(seat:LookupAttachment "vehicle_driver_eyes", dvd.Texts.Errors.AttachmentNotFound)) - local d = dvd.SeatPos[self:GetVehicleIdentifier()] or dvd.SeatPos[self:GetVehiclePrefix()] or Vector(-8, 0, -32) - local seatang = seat:WorldToLocalAngles(a.Ang) - local seatpos = seat:WorldToLocal(a.Pos + a.Ang:Forward() * d.x + a.Ang:Right() * d.y + a.Ang:Up() * d.z) - self:SetNWVector("Pos", seatpos) - self:SetNWAngle("Ang", seatang) - self:SetSequence(anim) - - for i = 0, self:GetFlexNum() - 1 do - self:SetFlexWeight(i, self:GetFlexBounds(i)) - end - end) + local seat = self.v + if self.v.IsScar then + seat = self.v.Seats and self.v.Seats[1] + elseif self.v.IsSimfphyscar then + seat = self.v.DriverSeat + end + + if not IsValid(seat) then return end + local anim = dvd.DriverAnimation[self:GetVehicleIdentifier()] or dvd.DriverAnimation[self:GetVehiclePrefix()] or "drive_jeep" + self:SetModel(istable(self.Model) and self.Model[math.random(#self.Model)] + or self.Model or dvd.DefaultDriverModel[math.random(#dvd.DefaultDriverModel)]) + self:SetNWEntity("Seat", seat) + self:SetNWEntity("Vehicle", self.v) + self:SetNWInt("Sequence", self:LookupSequence(anim)) + self:SetParent(seat) + seat:SetSequence(0) -- Resets the sequence first to correct the seat position + + timer.Simple(.1, function() -- Entity:Sequence() will not work properly if it is + if not IsValid(seat) then return end -- called directly after calling Entity:SetModel(). + if not IsValid(self) then return end + if not IsValid(self.v) then return end + local a = seat:GetAttachment(assert(seat:LookupAttachment "vehicle_driver_eyes", dvd.Texts.Errors.AttachmentNotFound)) + local d = dvd.SeatPos[self:GetVehicleIdentifier()] or dvd.SeatPos[self:GetVehiclePrefix()] or Vector(-8, 0, -32) + local seatang = seat:WorldToLocalAngles(a.Ang) + local seatpos = seat:WorldToLocal(a.Pos + a.Ang:Forward() * d.x + a.Ang:Right() * d.y + a.Ang:Up() * d.z) + self:SetNWVector("Pos", seatpos) + self:SetNWAngle("Ang", seatang) + self:SetSequence(anim) + + for i = 0, self:GetFlexNum() - 1 do + self:SetFlexWeight(i, self:GetFlexBounds(i)) + end + end) end function ENT:IsDestroyed() - if self.v:IsFlagSet(FL_DISSOLVING) then return true end - if self.v.IsScar then - return self.v:IsDestroyed() - elseif self.v.IsSimfphyscar then - return self.v:GetCurHealth() <= 0 - elseif isfunction(self.v.VC_GetHealth) then - local health = self.v:VC_GetHealth(false) - return isnumber(health) and health <= 0 - end + if self.v:IsFlagSet(FL_DISSOLVING) then return true end + if self.v.IsScar then + return self.v:IsDestroyed() + elseif self.v.IsSimfphyscar then + return self.v:GetCurHealth() <= 0 + elseif isfunction(self.v.VC_GetHealth) then + local health = self.v:VC_GetHealth(false) + return isnumber(health) and health <= 0 + end end function ENT:GetCurrentMaxSpeed() - local destlength = self.Waypoint.Target:Distance(self.v:WorldSpaceCenter()) - local maxspeed = math.Clamp(self.Waypoint.SpeedLimit, 1, self.MaxSpeed) - if self.PrevWaypoint then - local total = self.Waypoint.Target:Distance(self.PrevWaypoint.Target) - local frac = (1 - destlength / total)^2 - if self.NextWaypoint then -- The speed limit is affected by connected waypoints - maxspeed = Lerp(frac, maxspeed, math.Clamp(self.NextWaypoint.SpeedLimit, 1, self.MaxSpeed)) - end - - -- If the waypoint has a sharp corner, slow down - maxspeed = maxspeed * Lerp(frac, 1, 1 - self.Prependicular * .9) - if self.Waypoint.TrafficLight and self.Waypoint.TrafficLight:GetNWInt "DVTL_LightColor" == 3 then - maxspeed = maxspeed * (1 - frac) - end - end - - maxspeed = maxspeed * math.max(1 - self.v:GetPhysicsObject():GetAngleVelocity():Dot(self:GetVehicleUp()) / 60, 0) - maxspeed = maxspeed * math.Clamp(self.MaxSpeedCoefficient, 0, 1) - return hook.Run("Decent Vehicle: GetCurrentMaxSpeed", self, maxspeed) or maxspeed + local destlength = self.Waypoint.Target:Distance(self.v:WorldSpaceCenter()) + local maxspeed = math.Clamp(self.Waypoint.SpeedLimit, 1, self.MaxSpeed) + if self.PrevWaypoint then + local total = self.Waypoint.Target:Distance(self.PrevWaypoint.Target) + local frac = (1 - destlength / total)^2 + if self.NextWaypoint then -- The speed limit is affected by connected waypoints + maxspeed = Lerp(frac, maxspeed, math.Clamp(self.NextWaypoint.SpeedLimit, 1, self.MaxSpeed)) + end + + -- If the waypoint has a sharp corner, slow down + maxspeed = maxspeed * Lerp(frac, 1, 1 - self.Prependicular * .9) + if self.Waypoint.TrafficLight and self.Waypoint.TrafficLight:GetNWInt "DVTL_LightColor" == 3 then + maxspeed = maxspeed * (1 - frac) + end + end + + maxspeed = maxspeed * math.max(1 - self.v:GetPhysicsObject():GetAngleVelocity():Dot(self:GetVehicleUp()) / 60, 0) + maxspeed = maxspeed * math.Clamp(self.MaxSpeedCoefficient, 0, 1) + return hook.Run("Decent Vehicle: GetCurrentMaxSpeed", self, maxspeed) or maxspeed end function ENT:IsValidVehicle() - if not IsValid(self.v) then return end -- The tied vehicle goes NULL. - if not self.v:IsVehicle() then return end -- Somehow it becomes non-vehicle entity. - if not self.v.DecentVehicle then return end -- Somehow it's a normal vehicle. - if not IsValid(self:GetNWEntity "Seat") then return end -- It couldn't find the driver seat. - if self ~= self.v.DecentVehicle then return end -- It has a different driver. - if self.v:WaterLevel() > 1 then return end -- It falls into water. - if self:IsDestroyed() then return end -- It is destroyed. - return true + if not IsValid(self.v) then return end -- The tied vehicle goes NULL. + if not self.v:IsVehicle() then return end -- Somehow it becomes non-vehicle entity. + if not self.v.DecentVehicle then return end -- Somehow it's a normal vehicle. + if not IsValid(self:GetNWEntity "Seat") then return end -- It couldn't find the driver seat. + if self ~= self.v.DecentVehicle then return end -- It has a different driver. + if self.v:WaterLevel() > 1 then return end -- It falls into water. + if self:IsDestroyed() then return end -- It is destroyed. + return true end function ENT:AtTrafficLight() - if self.FormLine then return true end - if not self.PrevWaypoint then return end - if not self.PrevWaypoint.TrafficLight then return end - if self:GetVehicleForward():Dot(self.PrevWaypoint.Target - self.v:WorldSpaceCenter()) < 0 - and self.PrevWaypoint.Target:Distance(self.v:WorldSpaceCenter()) > self.v:BoundingRadius() then return end - if self.PrevWaypoint.TrafficLight:GetNWInt "DVTL_LightColor" == 3 then return true end + if self.FormLine then return true end + if not self.PrevWaypoint then return end + if not self.PrevWaypoint.TrafficLight then return end + if self:GetVehicleForward():Dot(self.PrevWaypoint.Target - self.v:WorldSpaceCenter()) < 0 + and self.PrevWaypoint.Target:Distance(self.v:WorldSpaceCenter()) > self.v:BoundingRadius() then return end + if self.PrevWaypoint.TrafficLight:GetNWInt "DVTL_LightColor" == 3 then return true end end function ENT:ShouldStopGoingback() - if self.FormLine then return end - if not self.Preference.ShouldGoback then return true end - if IsValid(self.TraceBack.Entity) or self.TraceBack.HitWorld - and self.TraceBack.HitNormal:Dot(vector_up) < .7 then - self.StopByTrace = CurTime() + FrameTime() -- Reset going back timer - return true - end - - local ent = self.Trace.Entity - if not (IsValid(ent) and ent.DecentVehicle) then return end - - ent = ent.DecentVehicle - if ent:GetELS() then return true end - if CurTime() > ent.WaitUntilNext then return end - if CurTime() > ent.Emergency then return end - return true + if self.FormLine then return end + if not self.Preference.ShouldGoback then return true end + if IsValid(self.TraceBack.Entity) or self.TraceBack.HitWorld + and self.TraceBack.HitNormal:Dot(vector_up) < .7 then + self.StopByTrace = CurTime() + FrameTime() -- Reset going back timer + return true + end + + local ent = self.Trace.Entity + if not (IsValid(ent) and ent.DecentVehicle) then return end + + ent = ent.DecentVehicle + if ent:GetELS() then return true end + if CurTime() > ent.WaitUntilNext then return end + if CurTime() > ent.Emergency then return end + return true end function ENT:ShouldStop() - if not self.Waypoint then return true end - if CurTime() < self.WaitUntilNext then return true end - if CurTime() < self.Emergency then return true end - if self.Preference.StopInfrontofPerson and CurTime() > self.StopByTrace - and CurTime() < self.StopByTrace + GobackTime then return true end - if self.Preference.StopAtTL and self:AtTrafficLight() then return true end + if not self.Waypoint then return true end + if CurTime() < self.WaitUntilNext then return true end + if CurTime() < self.Emergency then return true end + if self.Preference.StopInfrontofPerson and CurTime() > self.StopByTrace + and CurTime() < self.StopByTrace + GobackTime then return true end + if self.Preference.StopAtTL and self:AtTrafficLight() then return true end end function ENT:ShouldRefuel() - if self.v.IsScar then - return self.v:GetFuelPercent() < self.RefuelThreshold - elseif self.v.IsSimfphyscar then - return self.v:GetFuel() / self.v:GetMaxFuel() < self.RefuelThreshold - elseif isfunction(self.v.VC_fuelGet) - and isfunction(self.v.VC_fuelGetMax) then - return self.v:VC_fuelGet(false) / self.v:VC_fuelGetMax() < self.RefuelThreshold - end + if self.v.IsScar then + return self.v:GetFuelPercent() < self.RefuelThreshold + elseif self.v.IsSimfphyscar then + return self.v:GetFuel() / self.v:GetMaxFuel() < self.RefuelThreshold + elseif isfunction(self.v.VC_fuelGet) + and isfunction(self.v.VC_fuelGetMax) then + return self.v:VC_fuelGet(false) / self.v:VC_fuelGetMax() < self.RefuelThreshold + end end function ENT:Refuel() - hook.Run("Decent Vehicle: OnRefuel", self) - if self.v.IsScar then - self.v:Refuel() - elseif self.v.IsSimfphyscar then - self.v:SetFuel(self.v:GetMaxFuel()) - elseif isfunction(self.v.VC_fuelSet) - and isfunction(self.v.VC_fuelGetMax) then - self.v:VC_fuelSet(self.v:VC_fuelGetMax()) - end + hook.Run("Decent Vehicle: OnRefuel", self) + if self.v.IsScar then + self.v:Refuel() + elseif self.v.IsSimfphyscar then + self.v:SetFuel(self.v:GetMaxFuel()) + elseif isfunction(self.v.VC_fuelSet) + and isfunction(self.v.VC_fuelGetMax) then + self.v:VC_fuelSet(self.v:VC_fuelGetMax()) + end end function ENT:FindFuelStation() - local routes = select(2, dvd.GetFuelStations()) - local destinations = {} - for i, id in ipairs(routes) do - destinations[id] = true - end + local routes = select(2, dvd.GetFuelStations()) + local destinations = {} + for i, id in ipairs(routes) do + destinations[id] = true + end - local route = dvd.GetRoute(select(2, dvd.GetNearestWaypoint(self.Waypoint.Target)), destinations, self.Group) - if not route then return end + local route = dvd.GetRoute(select(2, dvd.GetNearestWaypoint(self.Waypoint.Target)), destinations, self.Group) + if not route then return end - self.WaypointList = route - return true + self.WaypointList = route + return true end function ENT:FindRoute(routetype) - if #self.WaypointList > 0 then return end - if not isfunction(self["Find" .. routetype]) then return end - if not self["Find" .. routetype](self) then return end - self.NextWaypoint = table.remove(self.WaypointList) + if #self.WaypointList > 0 then return end + if not isfunction(self["Find" .. routetype]) then return end + if not self["Find" .. routetype](self) then return end + self.NextWaypoint = table.remove(self.WaypointList) end function ENT:StopDriving() - hook.Run("Decent Vehicle: StopDriving", self) - self:SetHandbrake(true) - self:SetThrottle(0) - self:SetSteering(0) - self.SteeringInt, self.SteeringOld = 0, 0 - self.ThrottleInt, self.ThrottleOld = 0, 0 - if IsValid(self.NPCDriver) then - self.NPCDriver:SetSaveValue("m_vecDesiredPosition", vector_origin) - self.NPCDriver:SetSaveValue("m_vecDesiredPosition", vector_origin) - end + hook.Run("Decent Vehicle: StopDriving", self) + self:SetHandbrake(true) + self:SetThrottle(0) + self:SetSteering(0) + self.SteeringInt, self.SteeringOld = 0, 0 + self.ThrottleInt, self.ThrottleOld = 0, 0 + if IsValid(self.NPCDriver) then + self.NPCDriver:SetSaveValue("m_vecDesiredPosition", vector_origin) + self.NPCDriver:SetSaveValue("m_vecDesiredPosition", vector_origin) + end end -- Drive the vehicle toward ENT.Waypoint.Target. -- Returns: --- bool arrived | Has the vehicle arrived at the current destination. +-- bool arrived | Has the vehicle arrived at the current destination. function ENT:DriveToWaypoint() - if not self.Waypoint then return end - local sPID = dvd.PID.Steering[self:GetVehicleIdentifier()] or self.sPID - local tPID = dvd.PID.Throttle[self:GetVehicleIdentifier()] or self.tPID - local throttle = 1 -- The output throttle - local steering = 0 -- The output steering - local handbrake = false -- The output handbrake - local vehiclepos = self.v:WorldSpaceCenter() - local waypointpos = self.Waypoint.Target - local startpos = self.PrevWaypoint and self.PrevWaypoint.Target - local bound = self.v:BoundingRadius() - local forward = self:GetVehicleForward() - local up = self:GetVehicleUp() - local velocity = self.v:GetVelocity() - local velocitydot = velocity:Dot(forward) - local currentspeed = math.abs(velocitydot) - local maxspeed = self:GetCurrentMaxSpeed() - local relspeed = currentspeed / maxspeed - local targetpos = waypointpos - if startpos and not self.Waypoint.TrafficLight then - local way_length = startpos:Distance(waypointpos) - local start_to_vehicle = vehiclepos - startpos - if not start_to_vehicle:IsEqualTol(vector_origin, 1) and way_length > 0 then - local way_direction = dvd.GetDir(startpos, waypointpos) - local offset = self.WaypointOffset * vector_up:Cross(way_direction) - start_to_vehicle = start_to_vehicle - offset - local distance = way_direction:Cross(start_to_vehicle):Dot(up) - local length = way_direction:Dot(start_to_vehicle) + bound * 1.5 - local speed_dependant = bound * 1.5 - distance - local frac = math.max(length, length - speed_dependant * relspeed) / way_length - local p1, p2 = startpos + offset, waypointpos + offset - if frac > 1 and self.NextWaypoint then - local nextpos = self.NextWaypoint.Target - frac, p1, p2 = math.max(frac - 1, 0), p2, nextpos + offset - end - - targetpos = Lerp(frac, p1, p2) - end - end - debugoverlay.Cross(targetpos, 30, .1, Color(0, 255, 0), true) - - local dest = targetpos - vehiclepos - local todestination = dest:GetNormalized() - local cross = todestination:Cross(forward) - local steering_angle = math.deg(math.asin(math.Clamp(cross:Dot(up), -1, 1))) / math.abs(self:GetMaxSteeringAngle()) - local steering_differece = (steering_angle - self.SteeringOld) / FrameTime() - self.SteeringInt = self.SteeringInt + steering_angle * FrameTime() - self.SteeringOld = steering_angle - steering = sPID.x * steering_angle + sPID.y * self.SteeringInt + sPID.z * steering_differece - if steering ~= steering then steering = 0 end - - local estimateaccel = math.abs(self:EstimateAccel()) - local speed_difference = maxspeed - currentspeed - local throttle_difference = (speed_difference - self.ThrottleOld) / FrameTime() - self.ThrottleInt = self.ThrottleInt + speed_difference * FrameTime() - self.ThrottleOld = speed_difference - throttle = tPID.x * speed_difference + tPID.y * self.ThrottleInt + tPID.z * throttle_difference - if throttle ~= throttle then throttle = 0 end - - -- Prevents from going backward - local goback = forward:Dot(todestination) - local approaching = velocity:Dot(todestination) / velocity:Length() - -- Handbrake when intending to go backward and actually moving forward or vise-versa - goback = Either(velocitydot > 0, goback < -.5, goback < .5) and -1 or 1 - handbrake = currentspeed > 10 and goback * velocitydot < 0 - or currentspeed > math.max(100, maxspeed * .2) and math.abs(approaching) < .5 - - if goback < 0 then - steering = steering > 0 and -1 or 1 - elseif handbrake and not (self.v.IsScar or self.v.IsSimfphyscar) then - steering = -steering - end - - local gobacktime = self.Preference.GobackTime or self.GobackTime - local duration = self.Preference.GobackDuration or GobackDuration - local GobackByTrace = CurTime() - self.StopByTrace - gobacktime - if not self:ShouldStopGoingback() and 0 < GobackByTrace and GobackByTrace < duration then - goback = -1 - handbrake = false - else - if GobackByTrace > duration then - self.StopByTrace = CurTime() + FrameTime() -- Reset going back timer - end - - if not (self.v.IsScar or self.v.IsSimfphyscar) - and velocitydot * goback * throttle < 0 - and dvd.GetAng(physenv.GetGravity(), forward) < .1 then -- Exception #1: DV is going down - throttle = 0 -- The solution of the brake issue. - end - end - - if IsValid(self.NPCDriver) then - local desiredvelocity = todestination * maxspeed - self.NPCDriver:SetSaveValue("m_vecDesiredPosition", targetpos) - self.NPCDriver:SetSaveValue("m_vecDesiredVelocity", desiredvelocity) - end - - self.RelativeSpeed = relspeed - self:SetHandbrake(handbrake) - self:SetThrottle(math.Clamp(throttle / estimateaccel, -1, 1) * goback) - self:SetSteering(steering) - - hook.Run("Decent Vehicle: Drive", self) - local rest_length = dvd.GetDir(startpos or vehiclepos, waypointpos):Dot(waypointpos - vehiclepos) - local threshold = math.max(bound, math.max(0, velocitydot) * self.Prependicular) - return rest_length < threshold and not IsObstacle(self.TraceNextWaypoint) + if not self.Waypoint then return end + local sPID = dvd.PID.Steering[self:GetVehicleIdentifier()] or self.sPID + local tPID = dvd.PID.Throttle[self:GetVehicleIdentifier()] or self.tPID + local throttle = 1 -- The output throttle + local steering = 0 -- The output steering + local handbrake = false -- The output handbrake + local vehiclepos = self.v:WorldSpaceCenter() + local waypointpos = self.Waypoint.Target + local startpos = self.PrevWaypoint and self.PrevWaypoint.Target + local bound = self.v:BoundingRadius() + local forward = self:GetVehicleForward() + local up = self:GetVehicleUp() + local velocity = self.v:GetVelocity() + local velocitydot = velocity:Dot(forward) + local currentspeed = math.abs(velocitydot) + local maxspeed = self:GetCurrentMaxSpeed() + local relspeed = currentspeed / maxspeed + local targetpos = waypointpos + if startpos and not self.Waypoint.TrafficLight then + local way_length = startpos:Distance(waypointpos) + local start_to_vehicle = vehiclepos - startpos + if not start_to_vehicle:IsEqualTol(vector_origin, 1) and way_length > 0 then + local way_direction = dvd.GetDir(startpos, waypointpos) + local offset = self.WaypointOffset * vector_up:Cross(way_direction) + start_to_vehicle = start_to_vehicle - offset + local distance = way_direction:Cross(start_to_vehicle):Dot(up) + local length = way_direction:Dot(start_to_vehicle) + bound * 1.5 + local speed_dependant = bound * 1.5 - distance + local frac = math.max(length, length - speed_dependant * relspeed) / way_length + local p1, p2 = startpos + offset, waypointpos + offset + if frac > 1 and self.NextWaypoint then + local nextpos = self.NextWaypoint.Target + frac, p1, p2 = math.max(frac - 1, 0), p2, nextpos + offset + end + + targetpos = Lerp(frac, p1, p2) + end + end + debugoverlay.Cross(targetpos, 30, .1, Color(0, 255, 0), true) + + local dest = targetpos - vehiclepos + local todestination = dest:GetNormalized() + local cross = todestination:Cross(forward) + local steering_angle = math.deg(math.asin(math.Clamp(cross:Dot(up), -1, 1))) / math.abs(self:GetMaxSteeringAngle()) + local steering_differece = (steering_angle - self.SteeringOld) / FrameTime() + self.SteeringInt = self.SteeringInt + steering_angle * FrameTime() + self.SteeringOld = steering_angle + steering = sPID.x * steering_angle + sPID.y * self.SteeringInt + sPID.z * steering_differece + if steering ~= steering then steering = 0 end + + local estimateaccel = math.abs(self:EstimateAccel()) + local speed_difference = maxspeed - currentspeed + local throttle_difference = (speed_difference - self.ThrottleOld) / FrameTime() + self.ThrottleInt = self.ThrottleInt + speed_difference * FrameTime() + self.ThrottleOld = speed_difference + throttle = tPID.x * speed_difference + tPID.y * self.ThrottleInt + tPID.z * throttle_difference + if throttle ~= throttle then throttle = 0 end + + -- Prevents from going backward + local goback = forward:Dot(todestination) + local approaching = velocity:Dot(todestination) / velocity:Length() + -- Handbrake when intending to go backward and actually moving forward or vise-versa + goback = Either(velocitydot > 0, goback < -.5, goback < .5) and -1 or 1 + handbrake = currentspeed > 10 and goback * velocitydot < 0 + or currentspeed > math.max(100, maxspeed * .2) and math.abs(approaching) < .5 + + if goback < 0 then + steering = steering > 0 and -1 or 1 + elseif handbrake and not (self.v.IsScar or self.v.IsSimfphyscar) then + steering = -steering + end + + local gobacktime = self.Preference.GobackTime or self.GobackTime + local duration = self.Preference.GobackDuration or GobackDuration + local GobackByTrace = CurTime() - self.StopByTrace - gobacktime + if not self:ShouldStopGoingback() and 0 < GobackByTrace and GobackByTrace < duration then + goback = -1 + handbrake = false + else + if GobackByTrace > duration then + self.StopByTrace = CurTime() + FrameTime() -- Reset going back timer + end + + if not (self.v.IsScar or self.v.IsSimfphyscar) + and velocitydot * goback * throttle < 0 + and dvd.GetAng(physenv.GetGravity(), forward) < .1 then -- Exception #1: DV is going down + throttle = 0 -- The solution of the brake issue. + end + end + + if IsValid(self.NPCDriver) then + local desiredvelocity = todestination * maxspeed + self.NPCDriver:SetSaveValue("m_vecDesiredPosition", targetpos) + self.NPCDriver:SetSaveValue("m_vecDesiredVelocity", desiredvelocity) + end + + self.RelativeSpeed = relspeed + self:SetHandbrake(handbrake) + self:SetThrottle(math.Clamp(throttle / estimateaccel, -1, 1) * goback) + self:SetSteering(steering) + + hook.Run("Decent Vehicle: Drive", self) + local rest_length = dvd.GetDir(startpos or vehiclepos, waypointpos):Dot(waypointpos - vehiclepos) + local threshold = math.max(bound, math.max(0, velocitydot) * self.Prependicular) + return rest_length < threshold and not IsObstacle(self.TraceNextWaypoint) end function ENT:GetNPCDriver() @@ -616,465 +616,465 @@ function ENT:GetNPCDriver() end function ENT:DoLights() - if CurTime() < self.NextDoLights then return end - local fogenabled, fogend = GetFogInfo() - local fog = fogenabled and fogend < 5000 - self:SetRunningLights(self:GetEngineStarted()) - self:SetLights(GetNight() or fog, fog) - self:SetFogLights(fog) - self:SetTurnLight(self.Waypoint and self.Waypoint.UseTurnLights or false, self.UseLeftTurnLight) - self:SetHazardLights(CurTime() < self.Emergency) - self.NextDoLights = CurTime() + (self.Interval.DoLights or Interval.DoLights) + if CurTime() < self.NextDoLights then return end + local fogenabled, fogend = GetFogInfo() + local fog = fogenabled and fogend < 5000 + self:SetRunningLights(self:GetEngineStarted()) + self:SetLights(GetNight() or fog, fog) + self:SetFogLights(fog) + self:SetTurnLight(self.Waypoint and self.Waypoint.UseTurnLights or false, self.UseLeftTurnLight) + self:SetHazardLights(CurTime() < self.Emergency) + self.NextDoLights = CurTime() + (self.Interval.DoLights or Interval.DoLights) end function ENT:DoTrace() - if not self.Preference.DoTrace then return end - if not self.Waypoint then return end - if CurTime() < self.NextTrace then return end - local boundradius = self.v:BoundingRadius() / 2 - local filter = self:GetTraceFilter() - local forward = self:GetVehicleForward() - local right = self:GetVehicleRight() - local up = self:GetVehicleUp() - local vehiclepos = self.v:WorldSpaceCenter() - local velocity = self.v:GetVelocity() - local tracedir = Vector(velocity) - local tracemin = self.Preference.TraceMinLength or TraceMinLength - if velocity:LengthSqr() > tracemin^2 then - tracedir:Normalize() - else - tracedir = forward - end - - local velocitydot = velocity:Dot(tracedir) - local currentspeed = math.abs(velocitydot) - local trlength = math.max(tracemin, currentspeed * .8) - self.TraceLength = Lerp((CurTime() - self.StopByTrace) / GobackTime, trlength, self.TraceLength or trlength) - local kmph = currentspeed / dvd.KmphToHUps - local groundpos = util.QuickTrace(vehiclepos, -vector_up * 32768, filter).HitPos - local height = (vehiclepos.z - groundpos.z) / math.sqrt(2) - local bound = math.min(self.Preference.TraceMaxBound or TraceMax, height) - / Lerp(math.abs(math.sin(math.rad(self.v:GetAngles().yaw * 2))), 1, math.sqrt(2)) - local maxs = vector_one * bound - local mins = -maxs - local heightoffset = up * height * TraceHeightGap - local start = groundpos + heightoffset - local prevpos = self.PrevWaypoint and self.PrevWaypoint.Target or groundpos - local waypointpos = self.Waypoint.Target + heightoffset - local waypointdir = dvd.GetDir(start, waypointpos) - local pathdir = dvd.GetDir(prevpos, self.Waypoint.Target) - local sideoffset = pathdir:Cross(up) * bound * 2.5 - local startonpath = prevpos + pathdir * pathdir:Dot(start - prevpos) + heightoffset - local trwaypoint_isvalid = dvd.GetAng(waypointpos - start, tracedir) > .7 - - local boundsqr = bound^2 - local tr = { - start = start, - endpos = start + tracedir * self.TraceLength, - maxs = maxs, mins = mins, - filter = filter, - } - local trback = { - start = start, - endpos = start - tracedir * self.TraceLength / 2, - maxs = maxs, mins = mins, - filter = filter, - } - local trwaypoint = { - start = start, - endpos = waypointpos, - maxs = maxs, mins = mins, - filter = filter, - } - local trleft = { - start = startonpath - sideoffset, - endpos = startonpath - sideoffset + pathdir * self.TraceLength, - maxs = maxs, mins = mins, - filter = filter, - } - local trright = { - start = startonpath + sideoffset, - endpos = startonpath + sideoffset + pathdir * self.TraceLength, - maxs = maxs, mins = mins, - filter = filter, - } - if self.NextWaypoint then - local trnext = { - start = start, - endpos = self.NextWaypoint.Target + heightoffset, - maxs = maxs, mins = mins, - filter = filter, - } - self.TraceNextWaypoint = util.TraceHull(trnext) - debugoverlay.SweptBox(trnext.start, trnext.endpos, trnext.mins, trnext.maxs, angle_zero, self.Interval.Trace, Color(0, 255, 255)) - end - - self.Trace = util.TraceHull(tr) - self.TraceBack = util.TraceHull(trback) - self.TraceWaypoint = util.TraceHull(trwaypoint) - self.TraceLeft = util.TraceHull(trleft) - self.TraceRight = util.TraceHull(trright) - self.NextTrace = CurTime() + (self.Interval.Trace or Interval.Trace) - trwaypoint_isvalid = trwaypoint_isvalid and self.Trace.HitPos:Distance(tr.start) > self.TraceWaypoint.HitPos:Distance(tr.start) - debugoverlay.SweptBox(tr.start, tr.endpos, tr.mins, tr.maxs, angle_zero, self.Interval.Trace, Color(0, 255, 0)) - debugoverlay.SweptBox(trback.start, trback.endpos, trback.mins, trback.maxs, angle_zero, self.Interval.Trace, Color(255, 255, 0)) - debugoverlay.SweptBox(trwaypoint.start, trwaypoint.endpos, trwaypoint.mins, trwaypoint.maxs, angle_zero, self.Interval.Trace, Color(0, 255, 0)) - debugoverlay.SweptBox(trleft.start, trleft.endpos, trleft.mins, trleft.maxs, angle_zero, self.Interval.Trace, Color(255, 255, 0)) - debugoverlay.SweptBox(trright.start, trright.endpos, trright.mins, trright.maxs, angle_zero, self.Interval.Trace, Color(255, 255, 0)) - debugoverlay.SweptBox(tr.start, self.Trace.HitPos, tr.mins, tr.maxs, angle_zero, self.Interval.Trace) - - if self.TraceLeft.StartSolid then - trleft.start, trleft.endpos = startonpath, start - sideoffset - self.TraceLeft = util.TraceHull(trleft) - end - - if self.TraceRight.StartSolid then - trright.start, trright.endpos = startonpath, start + sideoffset - self.TraceRight = util.TraceHull(trright) - end - - local ent = self.Trace.Entity - local hitforward = IsObstacle(self.Trace) - local hitleft = IsObstacle(self.TraceLeft) - local hitright = IsObstacle(self.TraceRight) - local hitwaypoint = trwaypoint_isvalid and IsObstacle(self.TraceWaypoint) - if hitforward and not hitwaypoint and tracedir:Dot(waypointdir) > 0 then - local trhit = { - start = Lerp(.8, start, self.Trace.HitPos), - endpos = trwaypoint.endpos, - maxs = maxs, mins = mins, - filter = filter, - } - - debugoverlay.SweptBox(trhit.start, trhit.endpos, trhit.mins, trhit.maxs, angle_zero, self.Interval.Trace, Color(0, 255, 0)) - if tracedir:Dot(trhit.endpos - trhit.start) > 0 then - local tr = util.TraceHull(trhit) - hitforward = IsObstacle(tr) - end - end - - if trwaypoint_isvalid and not IsValid(ent) and IsValid(self.TraceWaypoint.Entity) then - ent = self.TraceWaypoint.Entity - end - - if not (hitforward or hitwaypoint) then - if CurTime() < self.StopByTrace + GobackTime then - self.StopByTrace = CurTime() + .1 - end - - self.FormLine = false - elseif IsValid(ent) then - local dv = ent.DecentVehicle - local dvTrace = dv and dv.Trace and dv.Trace.Entity - local dvTraceW = dv and dv.TraceWaypoint and dv.TraceWaypoint.Entity - self.FormLine = dv and dv:AtTrafficLight() - - if dv then - if dvTrace == self.v or dvTraceW == self.v - or (self:GetELSSound() and (hitleft or hitright) - and self.TraceLength * self.Trace.Fraction / boundradius > 1) then - self.StopByTrace = CurTime() + .1 - end - end - end - - if CurTime() > self.IsGivingWay then - if hitleft and not hitright then - self.WaypointOffset = -boundradius - elseif hitright and not hitleft then - self.WaypointOffset = boundradius - else - self.WaypointOffset = 0 - end - end - - hook.Run("Decent Vehicle: Trace", self, ent) + if not self.Preference.DoTrace then return end + if not self.Waypoint then return end + if CurTime() < self.NextTrace then return end + local boundradius = self.v:BoundingRadius() / 2 + local filter = self:GetTraceFilter() + local forward = self:GetVehicleForward() + local right = self:GetVehicleRight() + local up = self:GetVehicleUp() + local vehiclepos = self.v:WorldSpaceCenter() + local velocity = self.v:GetVelocity() + local tracedir = Vector(velocity) + local tracemin = self.Preference.TraceMinLength or TraceMinLength + if velocity:LengthSqr() > tracemin^2 then + tracedir:Normalize() + else + tracedir = forward + end + + local velocitydot = velocity:Dot(tracedir) + local currentspeed = math.abs(velocitydot) + local trlength = math.max(tracemin, currentspeed * .8) + self.TraceLength = Lerp((CurTime() - self.StopByTrace) / GobackTime, trlength, self.TraceLength or trlength) + local kmph = currentspeed / dvd.KmphToHUps + local groundpos = util.QuickTrace(vehiclepos, -vector_up * 32768, filter).HitPos + local height = (vehiclepos.z - groundpos.z) / math.sqrt(2) + local bound = math.min(self.Preference.TraceMaxBound or TraceMax, height) + / Lerp(math.abs(math.sin(math.rad(self.v:GetAngles().yaw * 2))), 1, math.sqrt(2)) + local maxs = vector_one * bound + local mins = -maxs + local heightoffset = up * height * TraceHeightGap + local start = groundpos + heightoffset + local prevpos = self.PrevWaypoint and self.PrevWaypoint.Target or groundpos + local waypointpos = self.Waypoint.Target + heightoffset + local waypointdir = dvd.GetDir(start, waypointpos) + local pathdir = dvd.GetDir(prevpos, self.Waypoint.Target) + local sideoffset = pathdir:Cross(up) * bound * 2.5 + local startonpath = prevpos + pathdir * pathdir:Dot(start - prevpos) + heightoffset + local trwaypoint_isvalid = dvd.GetAng(waypointpos - start, tracedir) > .7 + + local boundsqr = bound^2 + local tr = { + start = start, + endpos = start + tracedir * self.TraceLength, + maxs = maxs, mins = mins, + filter = filter, + } + local trback = { + start = start, + endpos = start - tracedir * self.TraceLength / 2, + maxs = maxs, mins = mins, + filter = filter, + } + local trwaypoint = { + start = start, + endpos = waypointpos, + maxs = maxs, mins = mins, + filter = filter, + } + local trleft = { + start = startonpath - sideoffset, + endpos = startonpath - sideoffset + pathdir * self.TraceLength, + maxs = maxs, mins = mins, + filter = filter, + } + local trright = { + start = startonpath + sideoffset, + endpos = startonpath + sideoffset + pathdir * self.TraceLength, + maxs = maxs, mins = mins, + filter = filter, + } + if self.NextWaypoint then + local trnext = { + start = start, + endpos = self.NextWaypoint.Target + heightoffset, + maxs = maxs, mins = mins, + filter = filter, + } + self.TraceNextWaypoint = util.TraceHull(trnext) + debugoverlay.SweptBox(trnext.start, trnext.endpos, trnext.mins, trnext.maxs, angle_zero, self.Interval.Trace, Color(0, 255, 255)) + end + + self.Trace = util.TraceHull(tr) + self.TraceBack = util.TraceHull(trback) + self.TraceWaypoint = util.TraceHull(trwaypoint) + self.TraceLeft = util.TraceHull(trleft) + self.TraceRight = util.TraceHull(trright) + self.NextTrace = CurTime() + (self.Interval.Trace or Interval.Trace) + trwaypoint_isvalid = trwaypoint_isvalid and self.Trace.HitPos:Distance(tr.start) > self.TraceWaypoint.HitPos:Distance(tr.start) + debugoverlay.SweptBox(tr.start, tr.endpos, tr.mins, tr.maxs, angle_zero, self.Interval.Trace, Color(0, 255, 0)) + debugoverlay.SweptBox(trback.start, trback.endpos, trback.mins, trback.maxs, angle_zero, self.Interval.Trace, Color(255, 255, 0)) + debugoverlay.SweptBox(trwaypoint.start, trwaypoint.endpos, trwaypoint.mins, trwaypoint.maxs, angle_zero, self.Interval.Trace, Color(0, 255, 0)) + debugoverlay.SweptBox(trleft.start, trleft.endpos, trleft.mins, trleft.maxs, angle_zero, self.Interval.Trace, Color(255, 255, 0)) + debugoverlay.SweptBox(trright.start, trright.endpos, trright.mins, trright.maxs, angle_zero, self.Interval.Trace, Color(255, 255, 0)) + debugoverlay.SweptBox(tr.start, self.Trace.HitPos, tr.mins, tr.maxs, angle_zero, self.Interval.Trace) + + if self.TraceLeft.StartSolid then + trleft.start, trleft.endpos = startonpath, start - sideoffset + self.TraceLeft = util.TraceHull(trleft) + end + + if self.TraceRight.StartSolid then + trright.start, trright.endpos = startonpath, start + sideoffset + self.TraceRight = util.TraceHull(trright) + end + + local ent = self.Trace.Entity + local hitforward = IsObstacle(self.Trace) + local hitleft = IsObstacle(self.TraceLeft) + local hitright = IsObstacle(self.TraceRight) + local hitwaypoint = trwaypoint_isvalid and IsObstacle(self.TraceWaypoint) + if hitforward and not hitwaypoint and tracedir:Dot(waypointdir) > 0 then + local trhit = { + start = Lerp(.8, start, self.Trace.HitPos), + endpos = trwaypoint.endpos, + maxs = maxs, mins = mins, + filter = filter, + } + + debugoverlay.SweptBox(trhit.start, trhit.endpos, trhit.mins, trhit.maxs, angle_zero, self.Interval.Trace, Color(0, 255, 0)) + if tracedir:Dot(trhit.endpos - trhit.start) > 0 then + local tr = util.TraceHull(trhit) + hitforward = IsObstacle(tr) + end + end + + if trwaypoint_isvalid and not IsValid(ent) and IsValid(self.TraceWaypoint.Entity) then + ent = self.TraceWaypoint.Entity + end + + if not (hitforward or hitwaypoint) then + if CurTime() < self.StopByTrace + GobackTime then + self.StopByTrace = CurTime() + .1 + end + + self.FormLine = false + elseif IsValid(ent) then + local dv = ent.DecentVehicle + local dvTrace = dv and dv.Trace and dv.Trace.Entity + local dvTraceW = dv and dv.TraceWaypoint and dv.TraceWaypoint.Entity + self.FormLine = dv and dv:AtTrafficLight() + + if dv then + if dvTrace == self.v or dvTraceW == self.v + or (self:GetELSSound() and (hitleft or hitright) + and self.TraceLength * self.Trace.Fraction / boundradius > 1) then + self.StopByTrace = CurTime() + .1 + end + end + end + + if CurTime() > self.IsGivingWay then + if hitleft and not hitright then + self.WaypointOffset = -boundradius + elseif hitright and not hitleft then + self.WaypointOffset = boundradius + else + self.WaypointOffset = 0 + end + end + + hook.Run("Decent Vehicle: Trace", self, ent) end function ENT:DoGiveWay() - if not self.Preference.GiveWay then return end - if CurTime() < self.IsGivingWay then return end - if CurTime() < self.NextGiveWay then return end - self.NextGiveWay = CurTime() + (self.Interval.GiveWay or Interval.GiveWay) - self.MaxSpeedCoefficient = 1 - for k, ent in pairs(CorrectFindInSphere(self:GetPos(), DetectionRangeELS:GetInt())) do - if not ent:IsVehicle() then continue end - if ent == self.v then continue end - if self:GetVehicleForward(ent):Dot(dvd.GetDir(ent:WorldSpaceCenter(), self.v:WorldSpaceCenter())) < -.7 then continue end - if not self:GetELSSound(ent) then continue end - - local left = IsObstacle(self.TraceLeft) - local right = IsObstacle(self.TraceRight) - local time = self.Preference.GiveWayTime or GiveWayTime - if (dvd.DriveSide == dvd.DRIVESIDE_LEFT or right) and not left then - self.IsGivingWay = CurTime() + time - self.WaypointOffset = self.v:BoundingRadius() / 3 - self.MaxSpeedCoefficient = .5 - elseif (dvd.DriveSide == dvd.DRIVESIDE_RIGHT or left) and not right then - self.IsGivingWay = CurTime() + time - self.WaypointOffset = -self.v:BoundingRadius() / 3 - self.MaxSpeedCoefficient = .5 - end - - return - end + if not self.Preference.GiveWay then return end + if CurTime() < self.IsGivingWay then return end + if CurTime() < self.NextGiveWay then return end + self.NextGiveWay = CurTime() + (self.Interval.GiveWay or Interval.GiveWay) + self.MaxSpeedCoefficient = 1 + for k, ent in pairs(CorrectFindInSphere(self:GetPos(), DetectionRangeELS:GetInt())) do + if not ent:IsVehicle() then continue end + if ent == self.v then continue end + if self:GetVehicleForward(ent):Dot(dvd.GetDir(ent:WorldSpaceCenter(), self.v:WorldSpaceCenter())) < -.7 then continue end + if not self:GetELSSound(ent) then continue end + + local left = IsObstacle(self.TraceLeft) + local right = IsObstacle(self.TraceRight) + local time = self.Preference.GiveWayTime or GiveWayTime + if (dvd.DriveSide == dvd.DRIVESIDE_LEFT or right) and not left then + self.IsGivingWay = CurTime() + time + self.WaypointOffset = self.v:BoundingRadius() / 3 + self.MaxSpeedCoefficient = .5 + elseif (dvd.DriveSide == dvd.DRIVESIDE_RIGHT or left) and not right then + self.IsGivingWay = CurTime() + time + self.WaypointOffset = -self.v:BoundingRadius() / 3 + self.MaxSpeedCoefficient = .5 + end + + return + end end function ENT:FindFirstWaypoint() - if self.Waypoint then return end - if #self.WaypointList > 0 then - self.Waypoint = table.remove(self.WaypointList) - self.NextWaypoint = table.remove(self.WaypointList) - return - end - - local pos = self.v:GetPos() - self.Waypoint = dvd.GetNearestWaypoint(pos, - function(testID, currentID, mindistance) - local w = dvd.Waypoints[testID] - return dvd.WaypointAvailable(testID, self.Group) - and dvd.GetDir(pos, w.Target):Dot(self:GetVehicleForward()) > 0 - end) - - if not self.Waypoint then return end - - self.NextWaypoint = dvd.GetRandomNeighbor(self.Waypoint, function(...) return FilterUTurnAndGroup(self, ...) end) - if not self.NextWaypoint and self.Waypoint.Target:Distance(pos) < self.v:BoundingRadius() then - self.Waypoint = nil - end + if self.Waypoint then return end + if #self.WaypointList > 0 then + self.Waypoint = table.remove(self.WaypointList) + self.NextWaypoint = table.remove(self.WaypointList) + return + end + + local pos = self.v:GetPos() + self.Waypoint = dvd.GetNearestWaypoint(pos, + function(testID, currentID, mindistance) + local w = dvd.Waypoints[testID] + return dvd.WaypointAvailable(testID, self.Group) + and dvd.GetDir(pos, w.Target):Dot(self:GetVehicleForward()) > 0 + end) + + if not self.Waypoint then return end + + self.NextWaypoint = dvd.GetRandomNeighbor(self.Waypoint, function(...) return FilterUTurnAndGroup(self, ...) end) + if not self.NextWaypoint and self.Waypoint.Target:Distance(pos) < self.v:BoundingRadius() then + self.Waypoint = nil + end end function ENT:SetupNextWaypoint() - if self.Preference.WaitUntilNext then - self.WaitUntilNext = CurTime() + (self.Waypoint.WaitUntilNext or 0) - end - - if self.NextWaypoint and self.NextWaypoint.UseTurnLights then - local prevpos = self.v:WorldSpaceCenter() - if self.PrevWaypoint then prevpos = self.PrevWaypoint.Target end - self.UseLeftTurnLight = (self.Waypoint.Target - prevpos):Cross( - self.NextWaypoint.Target - self.Waypoint.Target):Dot(self:GetVehicleUp()) > 0 - end - - self.PrevWaypoint, self.Waypoint = self.Waypoint, self.NextWaypoint - if not self.Waypoint then return end - self.NextWaypoint = table.remove(self.WaypointList) or - dvd.GetRandomNeighbor(self.Waypoint, function(...) return FilterUTurnAndGroup(self, ...) end) - - self.Prependicular = 0 - if self.NextWaypoint and self.PrevWaypoint then - self.Prependicular = 1 - dvd.GetAng3(self.PrevWaypoint.Target, self.Waypoint.Target, self.NextWaypoint.Target) - end + if self.Preference.WaitUntilNext then + self.WaitUntilNext = CurTime() + (self.Waypoint.WaitUntilNext or 0) + end + + if self.NextWaypoint and self.NextWaypoint.UseTurnLights then + local prevpos = self.v:WorldSpaceCenter() + if self.PrevWaypoint then prevpos = self.PrevWaypoint.Target end + self.UseLeftTurnLight = (self.Waypoint.Target - prevpos):Cross( + self.NextWaypoint.Target - self.Waypoint.Target):Dot(self:GetVehicleUp()) > 0 + end + + self.PrevWaypoint, self.Waypoint = self.Waypoint, self.NextWaypoint + if not self.Waypoint then return end + self.NextWaypoint = table.remove(self.WaypointList) or + dvd.GetRandomNeighbor(self.Waypoint, function(...) return FilterUTurnAndGroup(self, ...) end) + + self.Prependicular = 0 + if self.NextWaypoint and self.PrevWaypoint then + self.Prependicular = 1 - dvd.GetAng3(self.PrevWaypoint.Target, self.Waypoint.Target, self.NextWaypoint.Target) + end end function ENT:Think() - if not self:IsValidVehicle() then SafeRemoveEntity(self) return end - if self:ShouldStop() then - self:StopDriving() - self:FindFirstWaypoint() - elseif self:DriveToWaypoint() then -- When it arrives at the current waypoint. - hook.Run("Decent Vehicle: OnReachedWaypoint", self) - if self.Waypoint.FuelStation then self:Refuel() end - - self:SetupNextWaypoint() - elseif self:ShouldRefuel() then - if ShouldGoToRefuel:GetBool() then - self:FindRoute "FuelStation" - else - self:Refuel() - end - end - - self:DoGiveWay() - self:DoTrace() - self:DoLights() - self:NextThink(CurTime()) - self:SetDriverPosition() - return true + if not self:IsValidVehicle() then SafeRemoveEntity(self) return end + if self:ShouldStop() then + self:StopDriving() + self:FindFirstWaypoint() + elseif self:DriveToWaypoint() then -- When it arrives at the current waypoint. + hook.Run("Decent Vehicle: OnReachedWaypoint", self) + if self.Waypoint.FuelStation then self:Refuel() end + + self:SetupNextWaypoint() + elseif self:ShouldRefuel() then + if ShouldGoToRefuel:GetBool() then + self:FindRoute "FuelStation" + else + self:Refuel() + end + end + + self:DoGiveWay() + self:DoTrace() + self:DoLights() + self:NextThink(CurTime()) + self:SetDriverPosition() + return true end function ENT:Initialize() - -- Pick up a vehicle in the given sphere. - local mindistance, vehicle = math.huge - for k, v in pairs(CorrectFindInSphere(self:GetPos(), DetectionRange:GetFloat())) do - if not v:IsVehicle() then continue end - if IsValid(v:GetParent()) and v:GetParent():IsVehicle() then continue end - local d = self:GetPos():DistToSqr(v:GetPos()) - if d > mindistance then continue end - mindistance, vehicle = d, v - end - - if not IsValid(vehicle) or self:GetLocked(vehicle) then - SafeRemoveEntity(self) - return - end - - if vehicle.DecentVehicle then - SafeRemoveEntity(self) - SafeRemoveEntity(vehicle.DecentVehicle) - vehicle.DecentVehicle = nil - return - end - - if vehicle.IsScar and not vehicle:HasDriver() then - self.v, vehicle.DecentVehicle = vehicle, self - self.v.AIController = self - - -- Tanks or something sometimes make errors so disable thinking. - self.OldSpecialThink, self.v.SpecialThink = self.v.SpecialThink - elseif vehicle.IsSimfphyscar and vehicle:IsInitialized() and not IsValid(vehicle:GetDriver()) then - self.v, vehicle.DecentVehicle = vehicle, self - self.HeadLightsID = numpad.OnUp(self, KEY_F, "k_lgts", self.v, false) - self.FogLightsID = numpad.OnDown(self, KEY_V, "k_flgts", self.v, true) - self.ELSID = numpad.OnUp(self, KEY_H, "k_hrn", self.v, false) - self.HornID = numpad.OnDown(self, KEY_H, "k_hrn", self.v, true) - self.v.RemoteDriver = self - - self.OldPhysicsCollide = self.v.PhysicsCollide - function self.v.PhysicsCollide(...) - self.CarCollide(...) - return self.OldPhysicsCollide(...) - end - elseif isfunction(vehicle.GetWheelCount) and vehicle:GetWheelCount() -- Not a chair - and isfunction(vehicle.IsEngineEnabled) and vehicle:IsEngineEnabled() -- Engine is not locked - and not IsValid(vehicle:GetDriver()) then - self.v, vehicle.DecentVehicle = vehicle, self - self.OnCollideCallback = self.v:AddCallback("PhysicsCollide", self.CarCollide) - - if not isfunction(self.v.VC_getStates) or VCModFixedAroundNPCDriver then - local oldname = self.v:GetName() - self.v:SetName "decentvehicle" - self.NPCDriver = ents.Create "npc_vehicledriver" - self.NPCDriver:Spawn() - self.NPCDriver:SetKeyValue("Vehicle", "decentvehicle") - self.NPCDriver:Activate() - self.NPCDriver:Fire "StartForward" - self.NPCDriver:Fire("SetDriversMaxSpeed", "100") - self.NPCDriver:Fire("SetDriversMinSpeed", "0") - self.NPCDriver.InVehicle = self.InVehicle - self.NPCDriver.GetViewPunchAngles = self.GetViewPunchAngles -- For Seat Weaponizer 2 - self.NPCDriver.SetViewPunchAngles = self.SetViewPunchAngles -- Just to be sure - self.NPCDriver:SetHealth(0) -- This makes other NPCs think the driver is dead - self.NPCDriver:SetSaveValue("m_lifeState", -1) -- so that they don't attack it. - function self.NPCDriver.KeyDown(_, key) - return key == IN_FORWARD and self.Throttle > 0 - or key == IN_BACK and self.Throttle < 0 - or key == IN_MOVELEFT and self.Steering < 0 - or key == IN_MOVERIGHT and self.Steering > 0 - or key == IN_JUMP and self.HandBrake - or false - end - self.v:SetName(oldname or "") - end - end - - if not IsValid(self.v) then SafeRemoveEntity(self) return end - - local e = EffectData() - e:SetEntity(self.v) - if not self.DontUseSpawnEffect then - util.Effect("propspawn", e) -- Perform a spawn effect. - end - self:AttachModel() - self:DrawShadow(false) - self:GetVehicleParams() - self:PhysicsInitShadow() - self:SetEngineStarted(true) - self.v:DeleteOnRemove(self) - self.WaypointList = {} - self.Trace = {} - self.TraceBack = {} - self.TraceWaypoint = {} - self.TraceLeft = {} - self.TraceRight = {} - self.TraceNextWaypoint = {} - - self.Preference = table.Copy(self.Preference) - if self.Preference.LockVehicleDependsOnCVar then - self.Preference.LockVehicle = LockVehicle:GetBool() - end - - if self.Preference.StopInfrontofPersonDependsOnCVar then - self.Preference.StopInfrontofPerson = StopInfrontofPerson:GetBool() - end - - if self.Preference.LockVehicle then - self:SetLocked(true) - end - - if Photon and istable(self.v.VehicleTable) and self.v.VehicleTable.Photon then - self.v.PhotonUnitIDRequestTime = math.huge - if isfunction(self.v.IsBraking) then - self.OldPhotonIsBraking = self.v.IsBraking - self.v.IsBraking = self.IsBraking - end - - if isfunction(self.v.IsReversing) then - self.OldPhotonIsReversing = self.v.IsReversing - self.v.IsReversing = self.IsReversing - end - end + -- Pick up a vehicle in the given sphere. + local mindistance, vehicle = math.huge + for k, v in pairs(CorrectFindInSphere(self:GetPos(), DetectionRange:GetFloat())) do + if not v:IsVehicle() then continue end + if IsValid(v:GetParent()) and v:GetParent():IsVehicle() then continue end + local d = self:GetPos():DistToSqr(v:GetPos()) + if d > mindistance then continue end + mindistance, vehicle = d, v + end + + if not IsValid(vehicle) or self:GetLocked(vehicle) then + SafeRemoveEntity(self) + return + end + + if vehicle.DecentVehicle then + SafeRemoveEntity(self) + SafeRemoveEntity(vehicle.DecentVehicle) + vehicle.DecentVehicle = nil + return + end + + if vehicle.IsScar and not vehicle:HasDriver() then + self.v, vehicle.DecentVehicle = vehicle, self + self.v.AIController = self + + -- Tanks or something sometimes make errors so disable thinking. + self.OldSpecialThink, self.v.SpecialThink = self.v.SpecialThink + elseif vehicle.IsSimfphyscar and vehicle:IsInitialized() and not IsValid(vehicle:GetDriver()) then + self.v, vehicle.DecentVehicle = vehicle, self + self.HeadLightsID = numpad.OnUp(self, KEY_F, "k_lgts", self.v, false) + self.FogLightsID = numpad.OnDown(self, KEY_V, "k_flgts", self.v, true) + self.ELSID = numpad.OnUp(self, KEY_H, "k_hrn", self.v, false) + self.HornID = numpad.OnDown(self, KEY_H, "k_hrn", self.v, true) + self.v.RemoteDriver = self + + self.OldPhysicsCollide = self.v.PhysicsCollide + function self.v.PhysicsCollide(...) + self.CarCollide(...) + return self.OldPhysicsCollide(...) + end + elseif isfunction(vehicle.GetWheelCount) and vehicle:GetWheelCount() -- Not a chair + and isfunction(vehicle.IsEngineEnabled) and vehicle:IsEngineEnabled() -- Engine is not locked + and not IsValid(vehicle:GetDriver()) then + self.v, vehicle.DecentVehicle = vehicle, self + self.OnCollideCallback = self.v:AddCallback("PhysicsCollide", self.CarCollide) + + if not isfunction(self.v.VC_getStates) or VCModFixedAroundNPCDriver then + local oldname = self.v:GetName() + self.v:SetName "decentvehicle" + self.NPCDriver = ents.Create "npc_vehicledriver" + self.NPCDriver:Spawn() + self.NPCDriver:SetKeyValue("Vehicle", "decentvehicle") + self.NPCDriver:Activate() + self.NPCDriver:Fire "StartForward" + self.NPCDriver:Fire("SetDriversMaxSpeed", "100") + self.NPCDriver:Fire("SetDriversMinSpeed", "0") + self.NPCDriver.InVehicle = self.InVehicle + self.NPCDriver.GetViewPunchAngles = self.GetViewPunchAngles -- For Seat Weaponizer 2 + self.NPCDriver.SetViewPunchAngles = self.SetViewPunchAngles -- Just to be sure + self.NPCDriver:SetHealth(0) -- This makes other NPCs think the driver is dead + self.NPCDriver:SetSaveValue("m_lifeState", -1) -- so that they don't attack it. + function self.NPCDriver.KeyDown(_, key) + return key == IN_FORWARD and self.Throttle > 0 + or key == IN_BACK and self.Throttle < 0 + or key == IN_MOVELEFT and self.Steering < 0 + or key == IN_MOVERIGHT and self.Steering > 0 + or key == IN_JUMP and self.HandBrake + or false + end + self.v:SetName(oldname or "") + end + end + + if not IsValid(self.v) then SafeRemoveEntity(self) return end + + local e = EffectData() + e:SetEntity(self.v) + if not self.DontUseSpawnEffect then + util.Effect("propspawn", e) -- Perform a spawn effect. + end + self:AttachModel() + self:DrawShadow(false) + self:GetVehicleParams() + self:PhysicsInitShadow() + self:SetEngineStarted(true) + self.v:DeleteOnRemove(self) + self.WaypointList = {} + self.Trace = {} + self.TraceBack = {} + self.TraceWaypoint = {} + self.TraceLeft = {} + self.TraceRight = {} + self.TraceNextWaypoint = {} + + self.Preference = table.Copy(self.Preference) + if self.Preference.LockVehicleDependsOnCVar then + self.Preference.LockVehicle = LockVehicle:GetBool() + end + + if self.Preference.StopInfrontofPersonDependsOnCVar then + self.Preference.StopInfrontofPerson = StopInfrontofPerson:GetBool() + end + + if self.Preference.LockVehicle then + self:SetLocked(true) + end + + if Photon and istable(self.v.VehicleTable) and self.v.VehicleTable.Photon then + self.v.PhotonUnitIDRequestTime = math.huge + if isfunction(self.v.IsBraking) then + self.OldPhotonIsBraking = self.v.IsBraking + self.v.IsBraking = self.IsBraking + end + + if isfunction(self.v.IsReversing) then + self.OldPhotonIsReversing = self.v.IsReversing + self.v.IsReversing = self.IsReversing + end + end end function ENT:OnRemove() - if not IsValid(self.v) then return end - self.v:DontDeleteOnRemove(self) - self.v.DecentVehicle = nil - self:SetHandbrake(false) - self:SetSteering(0) - self:SetThrottle(0) - self:SetRunningLights(false) - self:SetFogLights(false) - self:SetLights(false, false) - self:SetLights(false, true) - self:SetHazardLights(false) - self:SetTurnLight(false, false) - self:SetTurnLight(false, true) - self:SetELS(false) - self:SetELSSound(false) - self:SetHorn(false) - self:SetEngineStarted(false) - self:SetLocked(false) - - if self.v.IsScar then -- If the vehicle is SCAR. - self.v.AIController = nil - self.v.SpecialThink, self.OldSpecialThink = self.OldSpecialThink - elseif self.v.IsSimfphyscar then -- The vehicle is Simfphys Vehicle. - self.v.PhysicsCollide, self.OldPhysicsCollide = self.OldPhysicsCollide - self.v.RemoteDriver = nil - self.v.PressedKeys.W = false - self.v.PressedKeys.A = false - self.v.PressedKeys.S = false - self.v.PressedKeys.D = false - self.v.PressedKeys.Space = false - - numpad.Remove(self.HeadLightsID) - numpad.Remove(self.FogLightsID) - numpad.Remove(self.ELSID) - numpad.Remove(self.HornID) - else - self.v:RemoveCallback("PhysicsCollide", self.OnCollideCallback) - self.v:SetSaveValue("m_nSpeed", 0) - if IsValid(self.NPCDriver) then - self.NPCDriver:Fire "Stop" - SafeRemoveEntity(self.NPCDriver) - end - end - - if Photon and istable(self.v.VehicleTable) and self.v.VehicleTable.Photon then - self.v.PhotonUnitIDRequestTime = nil - self.v.IsBraking = self.OldPhotonIsBraking - self.v.IsReversing = self.OldPhotonIsReversing - end - - local e = EffectData() - e:SetEntity(self.v) - if not self.DontUseSpawnEffect then - util.Effect("propspawn", e) -- Perform a spawn effect. - end + if not IsValid(self.v) then return end + self.v:DontDeleteOnRemove(self) + self.v.DecentVehicle = nil + self:SetHandbrake(false) + self:SetSteering(0) + self:SetThrottle(0) + self:SetRunningLights(false) + self:SetFogLights(false) + self:SetLights(false, false) + self:SetLights(false, true) + self:SetHazardLights(false) + self:SetTurnLight(false, false) + self:SetTurnLight(false, true) + self:SetELS(false) + self:SetELSSound(false) + self:SetHorn(false) + self:SetEngineStarted(false) + self:SetLocked(false) + + if self.v.IsScar then -- If the vehicle is SCAR. + self.v.AIController = nil + self.v.SpecialThink, self.OldSpecialThink = self.OldSpecialThink + elseif self.v.IsSimfphyscar then -- The vehicle is Simfphys Vehicle. + self.v.PhysicsCollide, self.OldPhysicsCollide = self.OldPhysicsCollide + self.v.RemoteDriver = nil + self.v.PressedKeys.W = false + self.v.PressedKeys.A = false + self.v.PressedKeys.S = false + self.v.PressedKeys.D = false + self.v.PressedKeys.Space = false + + numpad.Remove(self.HeadLightsID) + numpad.Remove(self.FogLightsID) + numpad.Remove(self.ELSID) + numpad.Remove(self.HornID) + else + self.v:RemoveCallback("PhysicsCollide", self.OnCollideCallback) + self.v:SetSaveValue("m_nSpeed", 0) + if IsValid(self.NPCDriver) then + self.NPCDriver:Fire "Stop" + SafeRemoveEntity(self.NPCDriver) + end + end + + if Photon and istable(self.v.VehicleTable) and self.v.VehicleTable.Photon then + self.v.PhotonUnitIDRequestTime = nil + self.v.IsBraking = self.OldPhotonIsBraking + self.v.IsReversing = self.OldPhotonIsReversing + end + + local e = EffectData() + e:SetEntity(self.v) + if not self.DontUseSpawnEffect then + util.Effect("propspawn", e) -- Perform a spawn effect. + end end if VCModFixedAroundNPCDriver then return end -- WORKAROUND!!! hook.Add("CanPlayerEnterVehicle", "Decent Vehicle: VCMod is not compatible with npc_vehicledriver", function(ply, vehicle, role) - if isfunction(vehicle.VC_getStates) and vehicle.DecentVehicle then return false end + if isfunction(vehicle.VC_getStates) and vehicle.DecentVehicle then return false end end) diff --git a/lua/entities/npc_decentvehicle/playermeta.lua b/lua/entities/npc_decentvehicle/playermeta.lua index 145cad0..3cad881 100644 --- a/lua/entities/npc_decentvehicle/playermeta.lua +++ b/lua/entities/npc_decentvehicle/playermeta.lua @@ -6,7 +6,7 @@ local dvd = DecentVehicleDestination local FakeViewOffset = vector_up * 32 local function FakeEyeTrace(self) - return util.QuickTrace(self:GetPos(), self:GetVehicleForward() * 16384, self) + return util.QuickTrace(self:GetPos(), self:GetVehicleForward() * 16384, self) end function ENT:AccountID() end -- For bots and in singleplayer, return no value @@ -165,47 +165,47 @@ function ENT:TranslateWeaponActivity() return ACT_INVALID end function ENT:UnfreezePhysicsObjects() end function ENT:UniqueID() return self:EntIndex() end function ENT:UniqueIDTable(key) - self.UniqueTable = self.UniqueTable or {} - self.UniqueTable[key] = self.UniqueTable[key] or {} - return self.UniqueTable[key] + self.UniqueTable = self.UniqueTable or {} + self.UniqueTable[key] = self.UniqueTable[key] or {} + return self.UniqueTable[key] end function ENT:UserID() return 0 end function ENT:ViewPunch() end function ENT:ViewPunchReset() end if CLIENT then - function ENT:AddPlayerOption() end - function ENT:GetFriendStatus() return "none" end - function ENT:GetPlayerInfo() - return { - customfiles = {"00000000", "00000000", "00000000", "00000000"}, - fakeplayer = true, - filesdownloaded = 0, - friendid = 0, - friendname = "", - guid = "BOT", - ishltv = false, - name = self.PrintName, - userid = 1, - } - end - function ENT:IsMuted() return false end - function ENT:IsSpeaking() return false end - function ENT:IsVoiceAudible() return false end - function ENT:KeyDown() return false end - function ENT:SetMuted() end - function ENT:ShouldDrawLocalPlayer() return false end - function ENT:ShowProfile() end - function ENT:SteamID64() end - function ENT:VoiceVolume() return 0 end - return + function ENT:AddPlayerOption() end + function ENT:GetFriendStatus() return "none" end + function ENT:GetPlayerInfo() + return { + customfiles = {"00000000", "00000000", "00000000", "00000000"}, + fakeplayer = true, + filesdownloaded = 0, + friendid = 0, + friendname = "", + guid = "BOT", + ishltv = false, + name = self.PrintName, + userid = 1, + } + end + function ENT:IsMuted() return false end + function ENT:IsSpeaking() return false end + function ENT:IsVoiceAudible() return false end + function ENT:KeyDown() return false end + function ENT:SetMuted() end + function ENT:ShouldDrawLocalPlayer() return false end + function ENT:ShowProfile() end + function ENT:SteamID64() end + function ENT:VoiceVolume() return 0 end + return end local InfoNum = { - cl_simfphys_ctenable = 1, - cl_simfphys_ctmul = .7, - cl_simfphys_ctang = 15, - cl_simfphys_auto = 1, + cl_simfphys_ctenable = 1, + cl_simfphys_ctmul = .7, + cl_simfphys_ctang = 15, + cl_simfphys_auto = 1, } function ENT:AddDeaths() end function ENT:AddFrags() end @@ -228,7 +228,7 @@ function ENT:Flashlight() end function ENT:Freeze() end function ENT:GetInfo() return "" end function ENT:GetInfoNum(key, default) --For Simfphys Vehicles - return InfoNum[key] or isnumber(default) and default or 0 + return InfoNum[key] or isnumber(default) and default or 0 end function ENT:GetPreferredCarryAngles() end function ENT:GetTimeoutSeconds() return 0 end @@ -242,12 +242,12 @@ function ENT:IsFullyAuthenticated() return false end function ENT:IsListenServerHost() return false end function ENT:IsTimingOut() return false end function ENT:KeyDown(key) - return key == IN_FORWARD and self.Throttle > 0 - or key == IN_BACK and self.Throttle < 0 - or key == IN_MOVELEFT and self.Steering < 0 - or key == IN_MOVERIGHT and self.Steering > 0 - or key == IN_JUMP and self.HandBrake - or false + return key == IN_FORWARD and self.Throttle > 0 + or key == IN_BACK and self.Throttle < 0 + or key == IN_MOVELEFT and self.Steering < 0 + or key == IN_MOVERIGHT and self.Steering > 0 + or key == IN_JUMP and self.HandBrake + or false end function ENT:Kick() end function ENT:Kill() end @@ -297,82 +297,82 @@ function ENT:UnLock() end function ENT:UnSpectate() end if Photon then - function ENT:IsBraking() - local dv = self.DecentVehicle - if not IsValid(dv) then return false end - return dv.HandBrake - end + function ENT:IsBraking() + local dv = self.DecentVehicle + if not IsValid(dv) then return false end + return dv.HandBrake + end - function ENT:IsReversing() - local dv = self.DecentVehicle - if not IsValid(dv) then return false end - return dv.Throttle < 0 and self:GetVelocity():Dot(dv:GetVehicleForward()) < 0 - end + function ENT:IsReversing() + local dv = self.DecentVehicle + if not IsValid(dv) then return false end + return dv.Throttle < 0 and self:GetVelocity():Dot(dv:GetVehicleForward()) < 0 + end end do -- Patches for Realistic bikes from CeiLciuZ - -- https://steamcommunity.com/id/ceilciuz/myworkshopfiles/?appid=4000 - function ENT:SetHelmet(int) - self:SetNW2Int("RealisticBike_Helmet", int) - end - - function ENT:GetHelmet() - return self:GetNW2Int("RealisticBike_Helmet") - end + -- https://steamcommunity.com/id/ceilciuz/myworkshopfiles/?appid=4000 + function ENT:SetHelmet(int) + self:SetNW2Int("RealisticBike_Helmet", int) + end - -- Pathces for RealisticBike KTM Duke 690 - -- https://steamcommunity.com/sharedfiles/filedetails/?id=1734895325 - function ENT:SetHaveHelmet_KTM_690(bool) - self:SetNW2Bool("RealisticBike_HaveHelmet_KTM_690", bool) - end + function ENT:GetHelmet() + return self:GetNW2Int("RealisticBike_Helmet") + end - function ENT:GetHaveHelmet_KTM_690() - return self:GetNW2Bool("RealisticBike_HaveHelmet_KTM_690") - end + -- Pathces for RealisticBike KTM Duke 690 + -- https://steamcommunity.com/sharedfiles/filedetails/?id=1734895325 + function ENT:SetHaveHelmet_KTM_690(bool) + self:SetNW2Bool("RealisticBike_HaveHelmet_KTM_690", bool) + end - function ENT:SetHelmetGlass_KTM_690(bool) - self:SetNW2Bool("RealisticBike_HelmetGlass_KTM_690", bool) - end + function ENT:GetHaveHelmet_KTM_690() + return self:GetNW2Bool("RealisticBike_HaveHelmet_KTM_690") + end - function ENT:GetHelmetGlass_KTM_690() - return self:GetNW2Bool("RealisticBike_HelmetGlass_KTM_690") - end - - -- Patches for RealisticBike Kawasaki Ninja H2 - -- https://steamcommunity.com/sharedfiles/filedetails/?id=1745931343 - function ENT:SetHaveHelmet_KAWA_NINJA_H2(bool) - self:SetNW2Bool("RealisticBike_HaveHelmet_KAWA_NINJA_H2", bool) - end + function ENT:SetHelmetGlass_KTM_690(bool) + self:SetNW2Bool("RealisticBike_HelmetGlass_KTM_690", bool) + end - function ENT:GetHaveHelmet_KAWA_NINJA_H2() - return self:GetNW2Bool("RealisticBike_HaveHelmet_KAWA_NINJA_H2") - end + function ENT:GetHelmetGlass_KTM_690() + return self:GetNW2Bool("RealisticBike_HelmetGlass_KTM_690") + end - function ENT:SetHelmetGlass_KAWA_NINJA_H2(bool) - self:SetNW2Bool("RealisticBike_HelmetGlass_KAWA_NINJA_H2", bool) - end + -- Patches for RealisticBike Kawasaki Ninja H2 + -- https://steamcommunity.com/sharedfiles/filedetails/?id=1745931343 + function ENT:SetHaveHelmet_KAWA_NINJA_H2(bool) + self:SetNW2Bool("RealisticBike_HaveHelmet_KAWA_NINJA_H2", bool) + end - function ENT:GetHelmetGlass_KAWA_NINJA_H2() - return self:GetNW2Bool("RealisticBike_HelmetGlass_KAWA_NINJA_H2") - end - - -- Patches for RealisticBike YAMAHA Yz 250 - -- https://steamcommunity.com/sharedfiles/filedetails/?id=1735177715 - function ENT:SetHaveHelmet_Yz_250(bool) - self:SetNW2Bool("RealisticBike_HaveHelmet_Yz_250", bool) - end + function ENT:GetHaveHelmet_KAWA_NINJA_H2() + return self:GetNW2Bool("RealisticBike_HaveHelmet_KAWA_NINJA_H2") + end - function ENT:GetHaveHelmet_Yz_250() - return self:GetNW2Bool("RealisticBike_HaveHelmet_Yz_250") - end + function ENT:SetHelmetGlass_KAWA_NINJA_H2(bool) + self:SetNW2Bool("RealisticBike_HelmetGlass_KAWA_NINJA_H2", bool) + end - function ENT:SetHelmetGlass_Yz_250(bool) - self:SetNW2Bool("RealisticBike_HelmetGlass_Yz_250", bool) - end + function ENT:GetHelmetGlass_KAWA_NINJA_H2() + return self:GetNW2Bool("RealisticBike_HelmetGlass_KAWA_NINJA_H2") + end - function ENT:GetHelmetGlass_Yz_250() - return self:GetNW2Bool("RealisticBike_HelmetGlass_Yz_250") - end + -- Patches for RealisticBike YAMAHA Yz 250 + -- https://steamcommunity.com/sharedfiles/filedetails/?id=1735177715 + function ENT:SetHaveHelmet_Yz_250(bool) + self:SetNW2Bool("RealisticBike_HaveHelmet_Yz_250", bool) + end + + function ENT:GetHaveHelmet_Yz_250() + return self:GetNW2Bool("RealisticBike_HaveHelmet_Yz_250") + end + + function ENT:SetHelmetGlass_Yz_250(bool) + self:SetNW2Bool("RealisticBike_HelmetGlass_Yz_250", bool) + end + + function ENT:GetHelmetGlass_Yz_250() + return self:GetNW2Bool("RealisticBike_HelmetGlass_Yz_250") + end end local vehiclemeta = FindMetaTable "Vehicle" @@ -391,22 +391,22 @@ if not dvd or dvd.HasChangedVehicleMeta then return end -- * RealisticBike Kawasaki Ninja H2 (https://steamcommunity.com/sharedfiles/filedetails/?id=1745931343) -- * RealisticBike YAMAHA Yz 250 (https://steamcommunity.com/sharedfiles/filedetails/?id=1735177715) function vehiclemeta:GetDriver(...) - if self.DecentVehicle then - if Photon and istable(self.VehicleTable) - and self.VehicleTable.Photon - and IsValid(self.PhotonVehicleSpawner) - and self.PhotonVehicleSpawner:IsPlayer() then - return self.PhotonVehicleSpawner - elseif self.__IsSW_Motorbike -- For Sligwolf's Motorbike. - or self:GetModel() == "models/tdmcars/bus.mdl" -- For TDM Commercial Vehicles. - or self:GetVehicleClass() == "realistic_bike_ktm_690" -- For RealisticBike KTM Duke 690 - or self:GetVehicleClass() == "realistic_bike_kawasaki_ninja_h2" -- For RealisticBike Kawasaki Ninja H2 - or self:GetVehicleClass() == "realistic_bike_yamaha_yz_250" then -- For RealisticBike YAMAHA Yz 250 - return self.DecentVehicle - end - end + if self.DecentVehicle then + if Photon and istable(self.VehicleTable) + and self.VehicleTable.Photon + and IsValid(self.PhotonVehicleSpawner) + and self.PhotonVehicleSpawner:IsPlayer() then + return self.PhotonVehicleSpawner + elseif self.__IsSW_Motorbike -- For Sligwolf's Motorbike. + or self:GetModel() == "models/tdmcars/bus.mdl" -- For TDM Commercial Vehicles. + or self:GetVehicleClass() == "realistic_bike_ktm_690" -- For RealisticBike KTM Duke 690 + or self:GetVehicleClass() == "realistic_bike_kawasaki_ninja_h2" -- For RealisticBike Kawasaki Ninja H2 + or self:GetVehicleClass() == "realistic_bike_yamaha_yz_250" then -- For RealisticBike YAMAHA Yz 250 + return self.DecentVehicle + end + end - return GetDriver(self, ...) -- This usually returns npc_vehicledriver for Decent Vehicles. + return GetDriver(self, ...) -- This usually returns npc_vehicledriver for Decent Vehicles. end dvd.HasChangedVehicleMeta = true diff --git a/lua/entities/npc_decentvehicle/shared.lua b/lua/entities/npc_decentvehicle/shared.lua index a47cf0a..1790bba 100644 --- a/lua/entities/npc_decentvehicle/shared.lua +++ b/lua/entities/npc_decentvehicle/shared.lua @@ -14,57 +14,57 @@ ENT.Instructions = "" ENT.Spawnable = false list.Set("NPC", "npc_decentvehicle", { - Name = ENT.PrintName, - Class = "npc_decentvehicle", - Category = "GreatZenkakuMan's NPCs", + Name = ENT.PrintName, + Class = "npc_decentvehicle", + Category = "GreatZenkakuMan's NPCs", }) function ENT:SetDriverPosition() - local seat = self:GetNWEntity "Seat" - if not IsValid(seat) then return end - local pos = seat:LocalToWorld(self:GetNWVector "Pos") - self:SetPos(pos) - self:SetNetworkOrigin(pos) - self:SetAngles(seat:LocalToWorldAngles(self:GetNWAngle "Ang")) + local seat = self:GetNWEntity "Seat" + if not IsValid(seat) then return end + local pos = seat:LocalToWorld(self:GetNWVector "Pos") + self:SetPos(pos) + self:SetNetworkOrigin(pos) + self:SetAngles(seat:LocalToWorldAngles(self:GetNWAngle "Ang")) end function ENT:GetDrivingEntity() - local vehicle = self:GetNWEntity "Vehicle" - if not (IsValid(vehicle) and vehicle:IsVehicle()) then return vehicle end + local vehicle = self:GetNWEntity "Vehicle" + if not (IsValid(vehicle) and vehicle:IsVehicle()) then return vehicle end end function ENT:GetVehicleForward(v) - local vehicle = v or self:GetNWEntity "Vehicle" - if not (IsValid(vehicle) and vehicle:IsVehicle()) then return self:GetForward() end - if vehicle.IsScar then - return vehicle:GetForward() - elseif vehicle.IsSimfphyscar then - return vehicle:LocalToWorldAngles(vehicle.VehicleData.LocalAngForward or angle_zero):Forward() - else - return vehicle:GetForward() - end + local vehicle = v or self:GetNWEntity "Vehicle" + if not (IsValid(vehicle) and vehicle:IsVehicle()) then return self:GetForward() end + if vehicle.IsScar then + return vehicle:GetForward() + elseif vehicle.IsSimfphyscar then + return vehicle:LocalToWorldAngles(vehicle.VehicleData.LocalAngForward or angle_zero):Forward() + else + return vehicle:GetForward() + end end function ENT:GetVehicleRight(v) - local vehicle = v or self:GetNWEntity "Vehicle" - if not (IsValid(vehicle) and vehicle:IsVehicle()) then return self:GetRight() end - if vehicle.IsScar then - return vehicle:GetRight() - elseif vehicle.IsSimfphyscar then - return vehicle:LocalToWorldAngles(vehicle.VehicleData.LocalAngForward or angle_zero):Right() - else - return vehicle:GetRight() - end + local vehicle = v or self:GetNWEntity "Vehicle" + if not (IsValid(vehicle) and vehicle:IsVehicle()) then return self:GetRight() end + if vehicle.IsScar then + return vehicle:GetRight() + elseif vehicle.IsSimfphyscar then + return vehicle:LocalToWorldAngles(vehicle.VehicleData.LocalAngForward or angle_zero):Right() + else + return vehicle:GetRight() + end end function ENT:GetVehicleUp(v) - local vehicle = v or self:GetNWEntity "Vehicle" - if not (IsValid(vehicle) and vehicle:IsVehicle()) then return self:GetUp() end - if vehicle.IsScar then - return vehicle:GetUp() - elseif vehicle.IsSimfphyscar then - return vehicle:LocalToWorldAngles(vehicle.VehicleData.LocalAngForward or angle_zero):Up() - else - return vehicle:GetUp() - end + local vehicle = v or self:GetNWEntity "Vehicle" + if not (IsValid(vehicle) and vehicle:IsVehicle()) then return self:GetUp() end + if vehicle.IsScar then + return vehicle:GetUp() + elseif vehicle.IsSimfphyscar then + return vehicle:LocalToWorldAngles(vehicle.VehicleData.LocalAngForward or angle_zero):Up() + else + return vehicle:GetUp() + end end diff --git a/lua/entities/npc_dvpolice.lua b/lua/entities/npc_dvpolice.lua index 9566c42..19b636e 100644 --- a/lua/entities/npc_dvpolice.lua +++ b/lua/entities/npc_dvpolice.lua @@ -8,8 +8,8 @@ ENT.Base = "npc_decentvehicle" ENT.PrintName = dvd.Texts.npc_dvpolice ENT.DV_Police = true -- Adding your identifier will be good. ENT.Model = { - "models/player/police.mdl", - "models/player/police_fem.mdl", + "models/player/police.mdl", + "models/player/police_fem.mdl", } ENT.Preference = { -- Some preferences for the behavior of the base AI. DoTrace = true, -- Whether or not it does some traces @@ -30,129 +30,129 @@ ENT.Preference = { -- Some preferences for the behavior of the base AI. } -- list.Set("NPC", "npc_dvpolice", { --- Name = ENT.PrintName, --- Class = "npc_dvpolice", --- Category = "GreatZenkakuMan's NPCs", +-- Name = ENT.PrintName, +-- Class = "npc_dvpolice", +-- Category = "GreatZenkakuMan's NPCs", -- }) if CLIENT then return end local color_green = Color(0, 255, 0) local ChangeCode = dvd.CVars.Police.ChangeCode ---[[ +--[[ arguments: 1: Entity ent - entity to check 2: boolean turn(optional) - if true, then generate new waypoint and generate new route, else only generate new route ]] function ENT:DVPolice_GenerateWaypoint(ent, turn) - turn = turn or false - assert(IsEntity(ent), string.format("Entity expected, got %s.", tostring(ent))) - assert(isbool(turn), string.format("Bool expected, got %s.", tostring(turn))) - - local move_ok = self:GetMoveDirection(ent) - local is_opposite, foundwp, wpside, back, neighbor = self:GetOppositeLine() - local tg_nearest = dvd.GetNearestWaypoint(ent:GetPos()) - if move_ok or turn then -- if moving towards us - if tg_nearest == foundwp then - self.Waypoint = foundwp - elseif tg_nearest == neighbor then - self.Waypoint = neighbor - else - self.Waypoint = neighbor - end - - debugoverlay.Sphere(self.Waypoint.Target, 50, 1, color_green, true) - end - - if not table.HasValue(self.WaypointList,tg_nearest) then - table.insert(self.WaypointList, tg_nearest) - debugoverlay.Sphere(tg_nearest.Target, 30, 1, color_green, true) - end - - timer.Simple(.2, function() -- idk why, but first it need to wait before get route - if not self.PreferencesSetUpped then - self.Preference.StopAtTL = false -- don't stop at traffic light - self.Preference.GiveWay = false -- don't give way - self.Preference.StopEmergency = false -- don't stop after crash - self.Preference.WaitUntilNext = false -- don't stop at specefid waypoints - - table.insert(dvd.DVPolice_WantedTable, self.DVPolice_LastTarget) - self.PreferencesSetUpped = true - end - - if not self:GetELS() then - self.DVPolice_Code = 1 - self:SetELS(true) -- set ELS on - - if self.v:GetClass() == "prop_vehicle_jeep" - and VC and isfunction(VC.ELS_Lht_SetCode) then - VC.ELS_Lht_SetCode(self.v, nil, nil, 1) - end - end - - if not self:GetELSSound() then - self.DVPolice_Code = 1 - self:SetELSSound(true) -- and set ELS sound on - if self.v:GetClass() == "prop_vehicle_jeep" - and VC and isfunction(VC.ELS_Snd_SetCode) then - VC.ELS_Snd_SetCode(self.v, nil, nil, 1) - end - end - - hook.Run("Decent Police: Chasing", self, ent) - end) + turn = turn or false + assert(IsEntity(ent), string.format("Entity expected, got %s.", tostring(ent))) + assert(isbool(turn), string.format("Bool expected, got %s.", tostring(turn))) + + local move_ok = self:GetMoveDirection(ent) + local is_opposite, foundwp, wpside, back, neighbor = self:GetOppositeLine() + local tg_nearest = dvd.GetNearestWaypoint(ent:GetPos()) + if move_ok or turn then -- if moving towards us + if tg_nearest == foundwp then + self.Waypoint = foundwp + elseif tg_nearest == neighbor then + self.Waypoint = neighbor + else + self.Waypoint = neighbor + end + + debugoverlay.Sphere(self.Waypoint.Target, 50, 1, color_green, true) + end + + if not table.HasValue(self.WaypointList,tg_nearest) then + table.insert(self.WaypointList, tg_nearest) + debugoverlay.Sphere(tg_nearest.Target, 30, 1, color_green, true) + end + + timer.Simple(.2, function() -- idk why, but first it need to wait before get route + if not self.PreferencesSetUpped then + self.Preference.StopAtTL = false -- don't stop at traffic light + self.Preference.GiveWay = false -- don't give way + self.Preference.StopEmergency = false -- don't stop after crash + self.Preference.WaitUntilNext = false -- don't stop at specefid waypoints + + table.insert(dvd.DVPolice_WantedTable, self.DVPolice_LastTarget) + self.PreferencesSetUpped = true + end + + if not self:GetELS() then + self.DVPolice_Code = 1 + self:SetELS(true) -- set ELS on + + if self.v:GetClass() == "prop_vehicle_jeep" + and VC and isfunction(VC.ELS_Lht_SetCode) then + VC.ELS_Lht_SetCode(self.v, nil, nil, 1) + end + end + + if not self:GetELSSound() then + self.DVPolice_Code = 1 + self:SetELSSound(true) -- and set ELS sound on + if self.v:GetClass() == "prop_vehicle_jeep" + and VC and isfunction(VC.ELS_Snd_SetCode) then + VC.ELS_Snd_SetCode(self.v, nil, nil, 1) + end + end + + hook.Run("Decent Police: Chasing", self, ent) + end) end function ENT:GetCurrentMaxSpeed() - local limit = self.Waypoint.SpeedLimit - self.Waypoint.SpeedLimit = limit * 10 - local base = self.BaseClass.GetCurrentMaxSpeed(self) - self.Waypoint.SpeedLimit = limit - - return base + local limit = self.Waypoint.SpeedLimit + self.Waypoint.SpeedLimit = limit * 10 + local base = self.BaseClass.GetCurrentMaxSpeed(self) + self.Waypoint.SpeedLimit = limit + + return base end function ENT:TargetStopped() - if not IsValid(self.DVPolice_Target) then return end - local speed = math.Round(self.DVPolice_Target:GetVelocity():Length() * 0.09144, 0) - return speed < 0.5 + if not IsValid(self.DVPolice_Target) then return end + local speed = math.Round(self.DVPolice_Target:GetVelocity():Length() * 0.09144, 0) + return speed < 0.5 end function ENT:ShouldStop() - if IsValid(self.DVPolice_Target) and self.Trace.Entity == self.DVPolice_Target then -- if target in trace - local speed = math.Round(self.DVPolice_Target:GetVelocity():Length() * 0.09144, 0) - if self.DVPolice_Code and self.DVPolice_Code >= 2 and not self:TargetStopped() then -- if chase code 2 and target not stopped - -- aka, do PIT maneuver - return false - elseif self:TargetStopped() then - self:SetELSSound(false) - if not self.ChangedCode and VC - and isfunction(VC.ELS_Lht_SetCode) then - if dvd.DriveSide == dvd.DRIVESIDE_RIGHT then -- if drive side right - VC.ELS_Lht_SetCode(self.v, nil, nil, 10) - else - VC.ELS_Lht_SetCode(self.v, nil, nil, 12) - end - self.DVPolice_ChangedCode = true - end - - self.StopByTrace = 0 - timer.Simple(math.random(10, 20), function() - table.RemoveByValue(dvd.DVPolice_WantedTable, self.DVPolice_Target) - self.DVPolice_Target = nil - end) - - return true - end - end - - if self.StopHere then - if dvd.GetNearestWaypoint(self:GetPos()) == self.StopHere then - return true - end - end - - return self.BaseClass.ShouldStop(self) + if IsValid(self.DVPolice_Target) and self.Trace.Entity == self.DVPolice_Target then -- if target in trace + local speed = math.Round(self.DVPolice_Target:GetVelocity():Length() * 0.09144, 0) + if self.DVPolice_Code and self.DVPolice_Code >= 2 and not self:TargetStopped() then -- if chase code 2 and target not stopped + -- aka, do PIT maneuver + return false + elseif self:TargetStopped() then + self:SetELSSound(false) + if not self.ChangedCode and VC + and isfunction(VC.ELS_Lht_SetCode) then + if dvd.DriveSide == dvd.DRIVESIDE_RIGHT then -- if drive side right + VC.ELS_Lht_SetCode(self.v, nil, nil, 10) + else + VC.ELS_Lht_SetCode(self.v, nil, nil, 12) + end + self.DVPolice_ChangedCode = true + end + + self.StopByTrace = 0 + timer.Simple(math.random(10, 20), function() + table.RemoveByValue(dvd.DVPolice_WantedTable, self.DVPolice_Target) + self.DVPolice_Target = nil + end) + + return true + end + end + + if self.StopHere then + if dvd.GetNearestWaypoint(self:GetPos()) == self.StopHere then + return true + end + end + + return self.BaseClass.ShouldStop(self) end --[[ @@ -165,37 +165,37 @@ Vector back - position from what was 100% checked table neighbor - foundwp's neighbor that was used for checking too ]] function ENT:GetOppositeLine() - local is_opposite = false - - local wpside - local foundwp - - if dvd.DriveSide == dvd.DRIVESIDE_RIGHT then -- if drive side right - wpside = self:LocalToWorld(Vector(0, 250, 0), Angle(0, 0, 0)) - else - wpside = self:LocalToWorld(Vector(0, -300, 0), Angle(0, 0, 0)) - end - - foundwp = dvd.GetNearestWaypoint(wpside) - local back = self:LocalToWorld(Vector(-400, 0, 0), Angle(0, 0, 0)) - debugoverlay.Line(self.v:GetPos(), wpside, .05, Color(0, 0, 255), true) - debugoverlay.Line(self.v:GetPos(), back, .05, Color(0, 0, 255), true) - debugoverlay.Sphere(foundwp.Target, 64, .1, Color(0, 0, 255, 100), true) - if foundwp.Neighbors[1] then - debugoverlay.Sphere(dvd.Waypoints[foundwp.Neighbors[1]].Target, 54, .5, Color(255, 0, 0, 100), true) - - local neighbor = dvd.Waypoints[foundwp.Neighbors[1]] - is_opposite = neighbor.Target:Distance(back) < foundwp.Target:Distance(back) - return is_opposite, foundwp, wpside, back, neighbor - else - return nil - end + local is_opposite = false + + local wpside + local foundwp + + if dvd.DriveSide == dvd.DRIVESIDE_RIGHT then -- if drive side right + wpside = self:LocalToWorld(Vector(0, 250, 0), Angle(0, 0, 0)) + else + wpside = self:LocalToWorld(Vector(0, -300, 0), Angle(0, 0, 0)) + end + + foundwp = dvd.GetNearestWaypoint(wpside) + local back = self:LocalToWorld(Vector(-400, 0, 0), Angle(0, 0, 0)) + debugoverlay.Line(self.v:GetPos(), wpside, .05, Color(0, 0, 255), true) + debugoverlay.Line(self.v:GetPos(), back, .05, Color(0, 0, 255), true) + debugoverlay.Sphere(foundwp.Target, 64, .1, Color(0, 0, 255, 100), true) + if foundwp.Neighbors[1] then + debugoverlay.Sphere(dvd.Waypoints[foundwp.Neighbors[1]].Target, 54, .5, Color(255, 0, 0, 100), true) + + local neighbor = dvd.Waypoints[foundwp.Neighbors[1]] + is_opposite = neighbor.Target:Distance(back) < foundwp.Target:Distance(back) + return is_opposite, foundwp, wpside, back, neighbor + else + return nil + end end function ENT:CarCollide(data) - if data.Speed < 200 or not data.HitEntity:IsVehicle() then return end - local TimeToStopEmergency = GetConVar "decentvehicle_timetostopemergency" - self.Emergency = CurTime() + (self.EmergencyDuration or TimeToStopEmergency:GetFloat()) + if data.Speed < 200 or not data.HitEntity:IsVehicle() then return end + local TimeToStopEmergency = GetConVar "decentvehicle_timetostopemergency" + self.Emergency = CurTime() + (self.EmergencyDuration or TimeToStopEmergency:GetFloat()) end --[[ @@ -204,169 +204,169 @@ Determines move direction of given entity arguments: 1: Entity ent - entity to check -returns: +returns: 1: boolean - true - driving on it's lane, false - driving on the opposite lane, nil - no vehicle ]] function ENT:GetMoveDirection(ent) - assert(IsEntity(ent), string.format("Entity expected, got %s.", tostring(ent))) - assert(ent:IsVehicle(), string.format("Trying call 'GetMoveDirection' to not vehicle. Got: %s.", tostring(ent))) - assert(ent:GetClass() ~= "prop_vehicle_prisoner_pod", string.format("Trying call 'GetMoveDirection' to seat. Got: %s.", tostring(ent))) - local is_opposite, foundedwp, lookside, lookback, neighbor = self:GetOppositeLine() - local move_ok, attposf, attposr - if ent.IsSimfphyscar then - if not ent.CustomWheels then - attposf = ent:GetAttachment(ent:LookupAttachment "wheel_fl").Pos - attposr = ent:GetAttachment(ent:LookupAttachment "wheel_rl").Pos - else - local wheels = ent.Wheels - attposf = wheels[1]:GetPos() - attposr = wheels[3]:GetPos() - end - elseif ent.IsScar then - local wheels = ent.Wheels - attposf = wheels[1]:GetPos() - attposr = wheels[3]:GetPos() - elseif ent:GetClass() == "prop_vehicle_jeep" then - attposf = ent:GetAttachment(ent:LookupAttachment "wheel_fl").Pos - attposr = ent:GetAttachment(ent:LookupAttachment "wheel_rl").Pos - end - - if is_opposite then - for k, v in pairs(ents.FindInSphere(lookside, 175)) do - debugoverlay.Sphere(lookside, 175, .1, Color(200, 10, 255, 1), true) - if v ~= ent then continue end - move_ok = attposf:Distance(neighbor.Target) < attposr:Distance(neighbor.Target) - end - end - - return move_ok + assert(IsEntity(ent), string.format("Entity expected, got %s.", tostring(ent))) + assert(ent:IsVehicle(), string.format("Trying call 'GetMoveDirection' to not vehicle. Got: %s.", tostring(ent))) + assert(ent:GetClass() ~= "prop_vehicle_prisoner_pod", string.format("Trying call 'GetMoveDirection' to seat. Got: %s.", tostring(ent))) + local is_opposite, foundedwp, lookside, lookback, neighbor = self:GetOppositeLine() + local move_ok, attposf, attposr + if ent.IsSimfphyscar then + if not ent.CustomWheels then + attposf = ent:GetAttachment(ent:LookupAttachment "wheel_fl").Pos + attposr = ent:GetAttachment(ent:LookupAttachment "wheel_rl").Pos + else + local wheels = ent.Wheels + attposf = wheels[1]:GetPos() + attposr = wheels[3]:GetPos() + end + elseif ent.IsScar then + local wheels = ent.Wheels + attposf = wheels[1]:GetPos() + attposr = wheels[3]:GetPos() + elseif ent:GetClass() == "prop_vehicle_jeep" then + attposf = ent:GetAttachment(ent:LookupAttachment "wheel_fl").Pos + attposr = ent:GetAttachment(ent:LookupAttachment "wheel_rl").Pos + end + + if is_opposite then + for k, v in pairs(ents.FindInSphere(lookside, 175)) do + debugoverlay.Sphere(lookside, 175, .1, Color(200, 10, 255, 1), true) + if v ~= ent then continue end + move_ok = attposf:Distance(neighbor.Target) < attposr:Distance(neighbor.Target) + end + end + + return move_ok end function ENT:IsTargetInBack(ent) - if not ent then return end -- is located in back - return self:GetVehicleForward():Dot(ent:GetPos() - self.v:WorldSpaceCenter()) < 0 + if not ent then return end -- is located in back + return self:GetVehicleForward():Dot(ent:GetPos() - self.v:WorldSpaceCenter()) < 0 end function ENT:Think() - if self.DVPolice_Target and self:TargetStopped() and self.Trace.Entity == self.DVPolice_Target then - self.Waypoint = dvd.GetNearestWaypoint(self.DVPolice_Target:GetPos()) - end - - if not self.v.ELSCycleChanged then -- for VCMod - self.v.ELSCycleChanged = true - if self.v:GetClass() == "prop_vehicle_jeep" and VC - and isfunction(self.v.VC_setELSLightsCycle) - and isfunction(VC.ELS_Lht_SetCode) - and isfunction(VC.ELS_Snd_SetCode) then - VC.ELS_Lht_SetCode(self.v, nil, nil, 1) - VC.ELS_Snd_SetCode(self.v, nil, nil, 1) - self.DVPolice_Code = 1 - self:SetELS(false) - self:SetELSSound(false) - end - end - - if not IsValid(self.DVPolice_Target) then -- if we don't have target - if not self.Waypoint then - self.WaypointList = {} - self.NextWaypoint = nil - self:FindFirstWaypoint() - end - - if self:GetELS() then -- and ELS enabled - self.WaypointList = {} - self.NextWaypoint = nil - self:FindFirstWaypoint() - self:SetELS(false) -- then disable it - self:SetELSSound(false) -- and it - self.Preference.StopAtTL = true -- again be polite - self.Preference.GiveWay = true -- very polite - self.Preference.StopEmergency = true -- so damn polite stop after crash - self.Preference.WaitUntilNext = true -- you so.fuckin.precios.when you. stop at specefid waypoints - self.PreferencesSetUpped = false - if self.v:GetClass() == "prop_vehicle_jeep" and VC - and isfunction(self.v.VC_setELSLightsCycle) - and isfunction(VC.ELS_Lht_SetCode) - and isfunction(VC.ELS_Snd_SetCode) then - VC.ELS_Lht_SetCode(self.v, nil, nil, 1) - VC.ELS_Snd_SetCode(self.v, nil, nil, 1) - self.DVPolice_Code = 1 - self:SetELS(false) - self:SetELSSound(false) - self.v.ELSCycleChanged = true - end - - hook.Run("Decent Police: Calmed", self) - end - elseif not IsValid(self.DVPolice_Target) then -- "wh9t the g0in on wh3r3 is m9 t9rg3t" (if target not is valid) - self.DVPolice_Target = nil -- "ak th3n n3v3r mind" (forgot it) - self:FindFirstWaypoint() - hook.Run("Decent Police: Reset Target", self) - elseif self:GetPos():DistToSqr(self.DVPolice_Target:GetPos()) > 36000000 then -- If target too far - self.DVPolice_LastTarget = self.DVPolice_Target -- don't chase anymore, but remember this guy - hook.Run("Decent Police: Added wanted list", self, self.DVPolice_Target) - local route = dvd.GetRouteVector(self.v:GetPos(), self.DVPolice_Target:GetPos(), self.Group) - - if route then - self.WaypointList = route -- go to the last known pos - else - self:FindFirstWaypoint() - end - - if self.v:GetClass() == "prop_vehicle_jeep" - and VC and not self:TargetStopped() - and isfunction(VC.ELS_Lht_SetCode) - and isfunction(VC.ELS_Snd_SetCode) then - VC.ELS_Lht_SetCode(self.v, nil, nil, 1) -- change code - VC.ELS_Snd_SetCode(self.v, nil, nil, 1) -- change code - self.DVPolice_Code = 1 - end - - self.DVPolice_Target = nil -- and clean up target - else - local tg_speed = math.Round(self.DVPolice_Target:GetVelocity():Length() * 0.09144, 0) - if not self:TargetStopped() then - self:DVPolice_GenerateWaypoint(self.DVPolice_Target, self:IsTargetInBack(self.DVPolice_Target)) - end - - timer.Simple(ChangeCode:GetInt(), function() -- if chasing for 2 mins - if IsValid(self) and not self:TargetStopped() and - (self.DVPolice_Target == self.DVPolice_LastTarget - or not self.DVPolice_LastTarget and self.DVPolice_Target) then - if self.v:GetClass() == "prop_vehicle_jeep" and VC - and isfunction(VC.ELS_Lht_SetCode) - and isfunction(VC.ELS_Snd_SetCode) then - VC.ELS_Lht_SetCode(self.v, nil, nil, 2) -- change code - VC.ELS_Snd_SetCode(self.v, nil, nil, 2) -- change code - self.DVPolice_Code = 2 - end - end - end) - end - - for k, ent in pairs(ents.FindInSphere(self.v:GetPos(), 800)) do - if self.DVPolice_Target or self:TargetStopped() then continue end - if not ent:IsVehicle() then continue end - if ent:GetClass() == "prop_vehicle_prisoner_pod" then continue end - if ent == self.v then continue end - if self:IsTargetInBack(ent) then continue end -- don't look back - - hook.Run("Decent Police: Detected vehicle", self, ent) - debugoverlay.Line(self:GetPos(), ent:GetPos(), .1, Color(0, 0, 255)) - - for k, wanted in pairs(dvd.DVPolice_WantedTable) do -- bad idea - if ent ~= wanted then continue end - self.DVPolice_Target = ent - hook.Run("Decent Police: Detected wanted vehicle", self, ent) - self:DVPolice_GenerateWaypoint(ent, false) - end - - if math.Round(dvd.GetNearestWaypoint(self.v:GetPos()).SpeedLimit * 0.09144) + 20 < math.Round(ent:GetVelocity():Length() * 0.09144) then - self.DVPolice_Target = ent - self:DVPolice_GenerateWaypoint(ent, false) - end - end - - return self.BaseClass.Think(self) + if self.DVPolice_Target and self:TargetStopped() and self.Trace.Entity == self.DVPolice_Target then + self.Waypoint = dvd.GetNearestWaypoint(self.DVPolice_Target:GetPos()) + end + + if not self.v.ELSCycleChanged then -- for VCMod + self.v.ELSCycleChanged = true + if self.v:GetClass() == "prop_vehicle_jeep" and VC + and isfunction(self.v.VC_setELSLightsCycle) + and isfunction(VC.ELS_Lht_SetCode) + and isfunction(VC.ELS_Snd_SetCode) then + VC.ELS_Lht_SetCode(self.v, nil, nil, 1) + VC.ELS_Snd_SetCode(self.v, nil, nil, 1) + self.DVPolice_Code = 1 + self:SetELS(false) + self:SetELSSound(false) + end + end + + if not IsValid(self.DVPolice_Target) then -- if we don't have target + if not self.Waypoint then + self.WaypointList = {} + self.NextWaypoint = nil + self:FindFirstWaypoint() + end + + if self:GetELS() then -- and ELS enabled + self.WaypointList = {} + self.NextWaypoint = nil + self:FindFirstWaypoint() + self:SetELS(false) -- then disable it + self:SetELSSound(false) -- and it + self.Preference.StopAtTL = true -- again be polite + self.Preference.GiveWay = true -- very polite + self.Preference.StopEmergency = true -- so damn polite stop after crash + self.Preference.WaitUntilNext = true -- you so.fuckin.precios.when you. stop at specefid waypoints + self.PreferencesSetUpped = false + if self.v:GetClass() == "prop_vehicle_jeep" and VC + and isfunction(self.v.VC_setELSLightsCycle) + and isfunction(VC.ELS_Lht_SetCode) + and isfunction(VC.ELS_Snd_SetCode) then + VC.ELS_Lht_SetCode(self.v, nil, nil, 1) + VC.ELS_Snd_SetCode(self.v, nil, nil, 1) + self.DVPolice_Code = 1 + self:SetELS(false) + self:SetELSSound(false) + self.v.ELSCycleChanged = true + end + + hook.Run("Decent Police: Calmed", self) + end + elseif not IsValid(self.DVPolice_Target) then -- "wh9t the g0in on wh3r3 is m9 t9rg3t" (if target not is valid) + self.DVPolice_Target = nil -- "ak th3n n3v3r mind" (forgot it) + self:FindFirstWaypoint() + hook.Run("Decent Police: Reset Target", self) + elseif self:GetPos():DistToSqr(self.DVPolice_Target:GetPos()) > 36000000 then -- If target too far + self.DVPolice_LastTarget = self.DVPolice_Target -- don't chase anymore, but remember this guy + hook.Run("Decent Police: Added wanted list", self, self.DVPolice_Target) + local route = dvd.GetRouteVector(self.v:GetPos(), self.DVPolice_Target:GetPos(), self.Group) + + if route then + self.WaypointList = route -- go to the last known pos + else + self:FindFirstWaypoint() + end + + if self.v:GetClass() == "prop_vehicle_jeep" + and VC and not self:TargetStopped() + and isfunction(VC.ELS_Lht_SetCode) + and isfunction(VC.ELS_Snd_SetCode) then + VC.ELS_Lht_SetCode(self.v, nil, nil, 1) -- change code + VC.ELS_Snd_SetCode(self.v, nil, nil, 1) -- change code + self.DVPolice_Code = 1 + end + + self.DVPolice_Target = nil -- and clean up target + else + local tg_speed = math.Round(self.DVPolice_Target:GetVelocity():Length() * 0.09144, 0) + if not self:TargetStopped() then + self:DVPolice_GenerateWaypoint(self.DVPolice_Target, self:IsTargetInBack(self.DVPolice_Target)) + end + + timer.Simple(ChangeCode:GetInt(), function() -- if chasing for 2 mins + if IsValid(self) and not self:TargetStopped() and + (self.DVPolice_Target == self.DVPolice_LastTarget + or not self.DVPolice_LastTarget and self.DVPolice_Target) then + if self.v:GetClass() == "prop_vehicle_jeep" and VC + and isfunction(VC.ELS_Lht_SetCode) + and isfunction(VC.ELS_Snd_SetCode) then + VC.ELS_Lht_SetCode(self.v, nil, nil, 2) -- change code + VC.ELS_Snd_SetCode(self.v, nil, nil, 2) -- change code + self.DVPolice_Code = 2 + end + end + end) + end + + for k, ent in pairs(ents.FindInSphere(self.v:GetPos(), 800)) do + if self.DVPolice_Target or self:TargetStopped() then continue end + if not ent:IsVehicle() then continue end + if ent:GetClass() == "prop_vehicle_prisoner_pod" then continue end + if ent == self.v then continue end + if self:IsTargetInBack(ent) then continue end -- don't look back + + hook.Run("Decent Police: Detected vehicle", self, ent) + debugoverlay.Line(self:GetPos(), ent:GetPos(), .1, Color(0, 0, 255)) + + for k, wanted in pairs(dvd.DVPolice_WantedTable) do -- bad idea + if ent ~= wanted then continue end + self.DVPolice_Target = ent + hook.Run("Decent Police: Detected wanted vehicle", self, ent) + self:DVPolice_GenerateWaypoint(ent, false) + end + + if math.Round(dvd.GetNearestWaypoint(self.v:GetPos()).SpeedLimit * 0.09144) + 20 < math.Round(ent:GetVelocity():Length() * 0.09144) then + self.DVPolice_Target = ent + self:DVPolice_GenerateWaypoint(ent, false) + end + end + + return self.BaseClass.Think(self) end diff --git a/lua/entities/npc_dvtaxi.lua b/lua/entities/npc_dvtaxi.lua index bffc5ef..17de7dd 100644 --- a/lua/entities/npc_dvtaxi.lua +++ b/lua/entities/npc_dvtaxi.lua @@ -11,73 +11,73 @@ ENT.IsDVTaxiDriver = true ENT.WaitForCaller = false list.Set("NPC", "npc_dvtaxi", { - Name = ENT.PrintName, - Class = "npc_dvtaxi", - Category = "GreatZenkakuMan's NPCs", + Name = ENT.PrintName, + Class = "npc_dvtaxi", + Category = "GreatZenkakuMan's NPCs", }) if CLIENT then return end function ENT:ShouldStop() - if self.WaitForCaller then return true end - return self.BaseClass.ShouldStop(self) + if self.WaitForCaller then return true end + return self.BaseClass.ShouldStop(self) end function ENT:Think() - self.BaseClass.Think(self) - if isnumber(self.WaitForCaller) and CurTime() > self.WaitForCaller - or isnumber(self.ClearMemory) and CurTime() > self.ClearMemory then - if IsValid(self.Caller) and self.Caller:IsPlayer() then - net.Start "Decent Vehicle: The taxi driver says something localized" - net.WriteUInt(5, 4) -- The passenger got off the taxi - net.Send(self.Caller) - if engine.ActiveGamemode() == "darkrp" then - self.Caller:ChatPrint(dvd.Texts.Taxi.Fare:format(self.Fare)) - self.Caller:setDarkRPVar("money", math.max(self.Caller.DarkRPVars.money - self.Fare, 0)) - end - - local seats = self.v:GetChildren() - if self.v.IsScar then seats = self.v.Seats end - for i, s in ipairs(seats) do - if not (IsValid(s) and s:IsVehicle()) then continue end - if self.v.IsScar and not s.IsScarSeat then continue end - local p = s:GetDriver() - if IsValid(p) and p:IsPlayer() and self.Caller ~= p then - net.Start "Decent Vehicle: The taxi driver says something localized" - net.WriteUInt(1, 4) -- A new passenger got in the taxi - net.Send(p) - net.Start "Decent Vehicle: Open a taxi menu" - net.WriteEntity(self) - net.Send(p) - self.Caller = p - self.ClearMemory = nil - self.Coming = false - self.Transporting = false - self.WaitForCaller = true - return true - end - end - end - - self.Caller = nil - self.ClearMemory = nil - self.Coming = false - self.Transporting = false - self.WaitForCaller = nil - self.WaypointList = {} - end - - return true + self.BaseClass.Think(self) + if isnumber(self.WaitForCaller) and CurTime() > self.WaitForCaller + or isnumber(self.ClearMemory) and CurTime() > self.ClearMemory then + if IsValid(self.Caller) and self.Caller:IsPlayer() then + net.Start "Decent Vehicle: The taxi driver says something localized" + net.WriteUInt(5, 4) -- The passenger got off the taxi + net.Send(self.Caller) + if engine.ActiveGamemode() == "darkrp" then + self.Caller:ChatPrint(dvd.Texts.Taxi.Fare:format(self.Fare)) + self.Caller:setDarkRPVar("money", math.max(self.Caller.DarkRPVars.money - self.Fare, 0)) + end + + local seats = self.v:GetChildren() + if self.v.IsScar then seats = self.v.Seats end + for i, s in ipairs(seats) do + if not (IsValid(s) and s:IsVehicle()) then continue end + if self.v.IsScar and not s.IsScarSeat then continue end + local p = s:GetDriver() + if IsValid(p) and p:IsPlayer() and self.Caller ~= p then + net.Start "Decent Vehicle: The taxi driver says something localized" + net.WriteUInt(1, 4) -- A new passenger got in the taxi + net.Send(p) + net.Start "Decent Vehicle: Open a taxi menu" + net.WriteEntity(self) + net.Send(p) + self.Caller = p + self.ClearMemory = nil + self.Coming = false + self.Transporting = false + self.WaitForCaller = true + return true + end + end + end + + self.Caller = nil + self.ClearMemory = nil + self.Coming = false + self.Transporting = false + self.WaitForCaller = nil + self.WaypointList = {} + end + + return true end function ENT:Initialize() - self.BaseClass.Initialize(self) - if not IsValid(self.v) then return end - dvd.TaxiDrivers[self] = true - if CLIENT or not istable(self.v.VehicleTable) then return end - self:SetNWString("CarName", self.v.VehicleTable.Name) + self.BaseClass.Initialize(self) + if not IsValid(self.v) then return end + dvd.TaxiDrivers[self] = true + if CLIENT or not istable(self.v.VehicleTable) then return end + self:SetNWString("CarName", self.v.VehicleTable.Name) end function ENT:OnRemove() - self.BaseClass.OnRemove(self) - dvd.TaxiDrivers[self] = nil + self.BaseClass.OnRemove(self) + dvd.TaxiDrivers[self] = nil end diff --git a/lua/entities/npc_learningvehicle.lua b/lua/entities/npc_learningvehicle.lua index 3752448..088e930 100644 --- a/lua/entities/npc_learningvehicle.lua +++ b/lua/entities/npc_learningvehicle.lua @@ -8,22 +8,22 @@ ENT.PrintName = "Learning Vehicle (β)" ENT.IsLearningVehicle = true -- Adding your identifier will be good. ENT.Model = "models/player/gman_high.mdl" -- Your driver models here. -- ENT.Model = { -- It can be a table of paths. Decent Vehicle will select one of them. - -- "path/to/model1.mdl", - -- "path/to/model2.mdl", + -- "path/to/model1.mdl", + -- "path/to/model2.mdl", -- } ENT.Preference = { -- Some preferences for the behavior of the base AI. - GiveWay = true, - StopAtTL = true, - DoTrace = true, - LockVehicle = false, - LockVehicleDependsOnCVar = true, + GiveWay = true, + StopAtTL = true, + DoTrace = true, + LockVehicle = false, + LockVehicleDependsOnCVar = true, } -- Uncomment this when you add it to the NPC list -- list.Set("NPC", "npc_learningvehicle", { - -- Name = ENT.PrintName, - -- Class = "npc_learningvehicle", - -- Category = "GreatZenkakuMan's NPCs", + -- Name = ENT.PrintName, + -- Class = "npc_learningvehicle", + -- Category = "GreatZenkakuMan's NPCs", -- }) if CLIENT then return end @@ -34,5 +34,5 @@ end -- Override the base functions here function ENT:DriveToWaypoint() - do return self.BaseClass.DriveToWaypoint(self) end + do return self.BaseClass.DriveToWaypoint(self) end end diff --git a/lua/weapons/gmod_tool/stools/dv_route.lua b/lua/weapons/gmod_tool/stools/dv_route.lua index a81515b..00cdd5e 100644 --- a/lua/weapons/gmod_tool/stools/dv_route.lua +++ b/lua/weapons/gmod_tool/stools/dv_route.lua @@ -11,10 +11,10 @@ TOOL.IsDecentVehicleTool = true TOOL.Category = texts.Category TOOL.Name = texts.Name TOOL.Information = { - {name = "info", stage = 0}, - {name = "left", stage = 0}, - {name = "left_1", stage = 1}, - {name = "right"}, + {name = "info", stage = 0}, + {name = "left", stage = 0}, + {name = "left_1", stage = 1}, + {name = "right"}, } TOOL.WaypointID = -1 @@ -31,312 +31,312 @@ TOOL.ClientConVar["updateradius"] = 100 TOOL.ClientConVar["wait"] = 0 if CLIENT then - language.Add("tool.dv_route.name", texts.PrintName) - language.Add("tool.dv_route.desc", texts.Description) - language.Add("tool.dv_route.0", texts.Instructions) - language.Add("tool.dv_route.left", texts.Left[1]) - language.Add("tool.dv_route.left_1", texts.Left[2]) - language.Add("tool.dv_route.right", texts.Right[1]) + language.Add("tool.dv_route.name", texts.PrintName) + language.Add("tool.dv_route.desc", texts.Description) + language.Add("tool.dv_route.0", texts.Instructions) + language.Add("tool.dv_route.left", texts.Left[1]) + language.Add("tool.dv_route.left_1", texts.Left[2]) + language.Add("tool.dv_route.right", texts.Right[1]) end function TOOL:LeftClick(trace) - if CLIENT then return true end - local bidirectional = self:GetClientNumber "bidirectional" > 0 - local fuel = self:GetClientNumber "fuel" > 0 - local group = self:GetClientNumber "group" - local shouldblink = self:GetClientNumber "shouldblink" > 0 - local speed = self:GetClientNumber "speed" - local wait = self:GetClientNumber "wait" - local pos = trace.HitPos - local waypoint, waypointID = dvd.GetNearestWaypoint(pos, dvd.WaypointSize) - if IsValid(trace.Entity) then - if trace.Entity.IsDVTrafficLight then - self.TrafficLight = trace.Entity - self.WaypointID = -1 - self:SetStage(1) - return true - elseif trace.Entity.DecentVehicle then - trace.Entity.DecentVehicle.Group = group - return true - end - end - - if not waypoint then - local oldpointID = self.WaypointID - local newpoint = dvd.AddWaypoint(pos) - self.WaypointID = #dvd.Waypoints - dvd.AddTrafficLight(self.WaypointID, self.TrafficLight) - newpoint.Owner = self:GetOwner() - newpoint.Time = CurTime() - newpoint.FuelStation = fuel - newpoint.UseTurnLights = shouldblink - newpoint.WaitUntilNext = wait - newpoint.SpeedLimit = speed * dvd.KmphToHUps - newpoint.Group = group - if dvd.Waypoints[oldpointID] then - dvd.AddNeighbor(oldpointID, self.WaypointID) - if bidirectional then - dvd.AddNeighbor(self.WaypointID, oldpointID) - end - end - - undo.Create "Decent Vehicle Waypoint" - undo.SetCustomUndoText(dvd.Texts.UndoText) - undo.AddFunction(dvd.UndoWaypoint) - undo.SetPlayer(self:GetOwner()) - undo.Finish() - elseif self:GetStage() == 0 or not (dvd.Waypoints[self.WaypointID] or IsValid(self.TrafficLight)) then - self.WaypointID = waypointID - self.TrafficLight = nil - self:SetStage(1) - return true - elseif self.WaypointID ~= waypointID then - if self.TrafficLight then - dvd.AddTrafficLight(waypointID, self.TrafficLight) - end - - if self.WaypointID > -1 then - if table.HasValue(dvd.Waypoints[self.WaypointID].Neighbors, waypointID) then - dvd.RemoveNeighbor(self.WaypointID, waypointID) - if bidirectional then - dvd.RemoveNeighbor(waypointID, self.WaypointID) - end - else - dvd.AddNeighbor(self.WaypointID, waypointID) - if bidirectional then - dvd.AddNeighbor(waypointID, self.WaypointID) - end - end - end - - self.WaypointID = -1 - self.TrafficLight = nil - elseif self.WaypointID > -1 then - dvd.RemoveWaypoint(self.WaypointID) - self.WaypointID = -1 - self.TrafficLight = nil - local removed = false - for id, undolist in pairs(undo.GetTable()) do - for i, undotable in pairs(undolist) do - if undotable.Name ~= "Decent Vehicle Waypoint" then continue end - if undotable.Owner ~= self:GetOwner() then continue end - undolist[i] = nil - removed = true - break - end - - if removed then break end - end - end - - self:SetStage(0) - return true + if CLIENT then return true end + local bidirectional = self:GetClientNumber "bidirectional" > 0 + local fuel = self:GetClientNumber "fuel" > 0 + local group = self:GetClientNumber "group" + local shouldblink = self:GetClientNumber "shouldblink" > 0 + local speed = self:GetClientNumber "speed" + local wait = self:GetClientNumber "wait" + local pos = trace.HitPos + local waypoint, waypointID = dvd.GetNearestWaypoint(pos, dvd.WaypointSize) + if IsValid(trace.Entity) then + if trace.Entity.IsDVTrafficLight then + self.TrafficLight = trace.Entity + self.WaypointID = -1 + self:SetStage(1) + return true + elseif trace.Entity.DecentVehicle then + trace.Entity.DecentVehicle.Group = group + return true + end + end + + if not waypoint then + local oldpointID = self.WaypointID + local newpoint = dvd.AddWaypoint(pos) + self.WaypointID = #dvd.Waypoints + dvd.AddTrafficLight(self.WaypointID, self.TrafficLight) + newpoint.Owner = self:GetOwner() + newpoint.Time = CurTime() + newpoint.FuelStation = fuel + newpoint.UseTurnLights = shouldblink + newpoint.WaitUntilNext = wait + newpoint.SpeedLimit = speed * dvd.KmphToHUps + newpoint.Group = group + if dvd.Waypoints[oldpointID] then + dvd.AddNeighbor(oldpointID, self.WaypointID) + if bidirectional then + dvd.AddNeighbor(self.WaypointID, oldpointID) + end + end + + undo.Create "Decent Vehicle Waypoint" + undo.SetCustomUndoText(dvd.Texts.UndoText) + undo.AddFunction(dvd.UndoWaypoint) + undo.SetPlayer(self:GetOwner()) + undo.Finish() + elseif self:GetStage() == 0 or not (dvd.Waypoints[self.WaypointID] or IsValid(self.TrafficLight)) then + self.WaypointID = waypointID + self.TrafficLight = nil + self:SetStage(1) + return true + elseif self.WaypointID ~= waypointID then + if self.TrafficLight then + dvd.AddTrafficLight(waypointID, self.TrafficLight) + end + + if self.WaypointID > -1 then + if table.HasValue(dvd.Waypoints[self.WaypointID].Neighbors, waypointID) then + dvd.RemoveNeighbor(self.WaypointID, waypointID) + if bidirectional then + dvd.RemoveNeighbor(waypointID, self.WaypointID) + end + else + dvd.AddNeighbor(self.WaypointID, waypointID) + if bidirectional then + dvd.AddNeighbor(waypointID, self.WaypointID) + end + end + end + + self.WaypointID = -1 + self.TrafficLight = nil + elseif self.WaypointID > -1 then + dvd.RemoveWaypoint(self.WaypointID) + self.WaypointID = -1 + self.TrafficLight = nil + local removed = false + for id, undolist in pairs(undo.GetTable()) do + for i, undotable in pairs(undolist) do + if undotable.Name ~= "Decent Vehicle Waypoint" then continue end + if undotable.Owner ~= self:GetOwner() then continue end + undolist[i] = nil + removed = true + break + end + + if removed then break end + end + end + + self:SetStage(0) + return true end function TOOL:RightClick(trace) - local fuel = self:GetClientNumber "fuel" > 0 - local group = self:GetClientNumber "group" - local shouldblink = self:GetClientNumber "shouldblink" > 0 - local speed = self:GetClientNumber "speed" - local wait = self:GetClientNumber "wait" - local pos = trace.HitPos - local waypoints = {} - if self:GetOwner():KeyDown(IN_USE) then - local RadiusSqr = self:GetClientNumber "updateradius"^2 - for i, w in ipairs(dvd.Waypoints) do - if pos:DistToSqr(w.Target) > RadiusSqr then continue end - table.insert(waypoints, i) - end - else - waypoints = {select(2, dvd.GetNearestWaypoint(pos, dvd.WaypointSize))} - end - - if #waypoints == 0 then return end - for _, i in ipairs(waypoints) do - local w = dvd.Waypoints[i] - if not w then continue end - w.FuelStation = fuel - w.UseTurnLights = shouldblink - w.WaitUntilNext = wait - w.SpeedLimit = speed * dvd.KmphToHUps - w.Group = group - - if SERVER and player.GetCount() > 0 then - net.Start "Decent Vehicle: Send waypoint info" - net.WriteUInt(i, 24) - net.WriteUInt(w.Group, 16) - net.WriteFloat(w.SpeedLimit) - net.WriteFloat(w.WaitUntilNext) - net.WriteBool(w.UseTurnLights) - net.WriteBool(w.FuelStation) - net.Broadcast() - end - end - - self:SetStage(0) - return true + local fuel = self:GetClientNumber "fuel" > 0 + local group = self:GetClientNumber "group" + local shouldblink = self:GetClientNumber "shouldblink" > 0 + local speed = self:GetClientNumber "speed" + local wait = self:GetClientNumber "wait" + local pos = trace.HitPos + local waypoints = {} + if self:GetOwner():KeyDown(IN_USE) then + local RadiusSqr = self:GetClientNumber "updateradius"^2 + for i, w in ipairs(dvd.Waypoints) do + if pos:DistToSqr(w.Target) > RadiusSqr then continue end + table.insert(waypoints, i) + end + else + waypoints = {select(2, dvd.GetNearestWaypoint(pos, dvd.WaypointSize))} + end + + if #waypoints == 0 then return end + for _, i in ipairs(waypoints) do + local w = dvd.Waypoints[i] + if not w then continue end + w.FuelStation = fuel + w.UseTurnLights = shouldblink + w.WaitUntilNext = wait + w.SpeedLimit = speed * dvd.KmphToHUps + w.Group = group + + if SERVER and player.GetCount() > 0 then + net.Start "Decent Vehicle: Send waypoint info" + net.WriteUInt(i, 24) + net.WriteUInt(w.Group, 16) + net.WriteFloat(w.SpeedLimit) + net.WriteFloat(w.WaitUntilNext) + net.WriteBool(w.UseTurnLights) + net.WriteBool(w.FuelStation) + net.Broadcast() + end + end + + self:SetStage(0) + return true end local ConVarsDefault = TOOL:BuildConVarList() local ConVarsList = table.GetKeys(ConVarsDefault) function TOOL.BuildCPanel(CPanel) - local ControlPresets = vgui.Create("ControlPresets", CPanel) - ControlPresets:SetPreset "decentvehicle" - ControlPresets:AddOption("#preset.default", ConVarsDefault) - for k, v in pairs(ConVarsList) do - ControlPresets:AddConVar(v) - end - - CPanel:AddItem(ControlPresets) - if dvd.Texts.Version then - local label = CPanel:Help(dvd.Texts.Version) - label:SetTextColor(CPanel:GetSkin().Colours.Tree.Hover) - end - - CPanel:Help(texts.DescriptionInMenu) - CPanel:CheckBox(texts.ShowUpdates, "dv_route_showupdates"):SetToolTip(texts.ShowUpdatesHelp) - CPanel:CheckBox(texts.DrawWaypoints, "dv_route_showpoints") - CPanel:CheckBox(texts.AlwaysDrawWaypoints, "dv_route_showalways") - CPanel:CheckBox(texts.Bidirectional, "dv_route_bidirectional"):SetToolTip(texts.BidirectionalHelp) - CPanel:CheckBox(texts.UseTurnLights, "dv_route_shouldblink"):SetToolTip(texts.UseTurnLightsHelp) - CPanel:CheckBox(texts.FuelStation, "dv_route_fuel"):SetToolTip(texts.FuelStationHelp) - CPanel:NumSlider(texts.UpdateRadius, "dv_route_updateradius", 100, 400, 0):SetToolTip(texts.UpdateRadiusHelp) - CPanel:NumSlider(texts.DrawDistance, "dv_route_drawdistance", 2000, 10000, 0):SetToolTip(texts.DrawDistanceHelp) - CPanel:NumSlider(texts.WaypointGroup, "dv_route_group", 0, 20, 0):SetToolTip(texts.WaypointGroupHelp) - CPanel:NumSlider(texts.WaitTime, "dv_route_wait", 0, 100, 2):SetToolTip(texts.WaitTimeHelp) - CPanel:NumSlider(texts.MaxSpeed, "dv_route_speed", 5, 500, 0) - - if LocalPlayer():IsAdmin() then - CPanel:Help "" - local label = CPanel:Help(texts.ServerSettings) - label:SetTextColor(CPanel:GetSkin().Colours.Tree.Hover) - for printname, cvarname in SortedPairs { - AutoLoad = "decentvehicle_autoload", - DriveSide = "decentvehicle_driveside", - ForceHeadlights = "decentvehicle_forceheadlights", - LockVehicle = "decentvehicle_gotorefuel", - ShouldGoToRefuel = "decentvehicle_lock", - StopInfrontofPerson = "decentvehicle_stop_infrontof_person", - } do - local c = vgui.Create("DCheckBoxLabel", CPanel) - local cvar = GetConVar(cvarname) - c:SetText(texts[printname]) - c:SetTextColor(c:GetSkin().Colours.Label.Dark) - if cvar then - hook.Add("Decent Vehicle: Sync CVar", printname, function() - c:SetChecked(cvar:GetBool()) - end) - end - - if texts[printname .. "Help"] then c:SetTooltip(texts[printname .. "Help"]) end - function c:OnChange(checked) - net.Start "Decent Vehicle: Change serverside value" - net.WriteString(cvarname) - net.WriteString(checked and "1" or "0") - net.SendToServer() - end - - CPanel:AddItem(c) - end - - for printname, cvartable in SortedPairs { - DetectionRange = { - name = "decentvehicle_detectionrange", - min = 1, max = 64, decimals = 0, - }, - DetectionRangeELS = { - name = "decentvehicle_elsrange", - min = 0, max = 1000, decimals = 0, - }, - } do - local n = vgui.Create("DNumSlider", CPanel) - local cvar = GetConVar(cvartable.name) - n:SetText(texts[printname]) - n:SetMinMax(cvartable.min, cvartable.max) - n:SetDecimals(cvartable.decimals) - n:SizeToContents() - n.Label:SetTextColor(n.Label:GetSkin().Colours.Label.Dark) - if cvar then - hook.Add("Decent Vehicle: Sync CVar", printname, function() - n:SetValue(cvar:GetFloat()) - end) - end - - if texts[printname .. "Help"] then n:SetTooltip(texts[printname .. "Help"]) end - function n:OnValueChanged(value) - net.Start "Decent Vehicle: Change serverside value" - net.WriteString(cvartable.name) - net.WriteString(tostring(value)) - net.SendToServer() - end - - CPanel:AddItem(n) - end - - local cvarlightlevelname = "decentvehicle_turnonlights" - local cvarlightlevel = GetConVar(cvarlightlevelname) - local comboboxlabel = vgui.Create("DLabel", CPanel) - local combobox = vgui.Create("DComboBox", CPanel) - local comboboxvalues = { - [0] = texts.LightLevel.None, - [1] = texts.LightLevel.Running, - [2] = texts.LightLevel.Headlights, - [3] = texts.LightLevel.All, - } - comboboxlabel:SetText(texts.LightLevel.Title) - comboboxlabel:SetTextColor(comboboxlabel:GetSkin().Colours.Label.Dark) - combobox:SetSortItems(false) - combobox:Dock(FILL) - for i, printname in SortedPairs(comboboxvalues) do - combobox:AddChoice(printname, i) - end - - if cvarlightlevel and comboboxvalues[cvarlightlevel:GetInt()] then - hook.Add("Decent Vehicle: Sync CVar", texts.LightLevel.Title, function() - combobox:SetValue(comboboxvalues[cvarlightlevel:GetInt()]) - end) - end - - function combobox:OnSelect(index, value, data) - net.Start "Decent Vehicle: Change serverside value" - net.WriteString(cvarlightlevelname) - net.WriteString(tostring(index)) - net.SendToServer() - end - - CPanel:AddItem(comboboxlabel, combobox) - CPanel:Button(texts.Save, "dv_route_save") - CPanel:Button(texts.Restore, "dv_route_load") - CPanel:Button(texts.Delete, "dv_route_delete") - CPanel:Button(texts.Generate, "dv_route_generate") - hook.Run "Decent Vehicle: Sync CVar" - end - - CPanel:InvalidateLayout() + local ControlPresets = vgui.Create("ControlPresets", CPanel) + ControlPresets:SetPreset "decentvehicle" + ControlPresets:AddOption("#preset.default", ConVarsDefault) + for k, v in pairs(ConVarsList) do + ControlPresets:AddConVar(v) + end + + CPanel:AddItem(ControlPresets) + if dvd.Texts.Version then + local label = CPanel:Help(dvd.Texts.Version) + label:SetTextColor(CPanel:GetSkin().Colours.Tree.Hover) + end + + CPanel:Help(texts.DescriptionInMenu) + CPanel:CheckBox(texts.ShowUpdates, "dv_route_showupdates"):SetToolTip(texts.ShowUpdatesHelp) + CPanel:CheckBox(texts.DrawWaypoints, "dv_route_showpoints") + CPanel:CheckBox(texts.AlwaysDrawWaypoints, "dv_route_showalways") + CPanel:CheckBox(texts.Bidirectional, "dv_route_bidirectional"):SetToolTip(texts.BidirectionalHelp) + CPanel:CheckBox(texts.UseTurnLights, "dv_route_shouldblink"):SetToolTip(texts.UseTurnLightsHelp) + CPanel:CheckBox(texts.FuelStation, "dv_route_fuel"):SetToolTip(texts.FuelStationHelp) + CPanel:NumSlider(texts.UpdateRadius, "dv_route_updateradius", 100, 400, 0):SetToolTip(texts.UpdateRadiusHelp) + CPanel:NumSlider(texts.DrawDistance, "dv_route_drawdistance", 2000, 10000, 0):SetToolTip(texts.DrawDistanceHelp) + CPanel:NumSlider(texts.WaypointGroup, "dv_route_group", 0, 20, 0):SetToolTip(texts.WaypointGroupHelp) + CPanel:NumSlider(texts.WaitTime, "dv_route_wait", 0, 100, 2):SetToolTip(texts.WaitTimeHelp) + CPanel:NumSlider(texts.MaxSpeed, "dv_route_speed", 5, 500, 0) + + if LocalPlayer():IsAdmin() then + CPanel:Help "" + local label = CPanel:Help(texts.ServerSettings) + label:SetTextColor(CPanel:GetSkin().Colours.Tree.Hover) + for printname, cvarname in SortedPairs { + AutoLoad = "decentvehicle_autoload", + DriveSide = "decentvehicle_driveside", + ForceHeadlights = "decentvehicle_forceheadlights", + LockVehicle = "decentvehicle_gotorefuel", + ShouldGoToRefuel = "decentvehicle_lock", + StopInfrontofPerson = "decentvehicle_stop_infrontof_person", + } do + local c = vgui.Create("DCheckBoxLabel", CPanel) + local cvar = GetConVar(cvarname) + c:SetText(texts[printname]) + c:SetTextColor(c:GetSkin().Colours.Label.Dark) + if cvar then + hook.Add("Decent Vehicle: Sync CVar", printname, function() + c:SetChecked(cvar:GetBool()) + end) + end + + if texts[printname .. "Help"] then c:SetTooltip(texts[printname .. "Help"]) end + function c:OnChange(checked) + net.Start "Decent Vehicle: Change serverside value" + net.WriteString(cvarname) + net.WriteString(checked and "1" or "0") + net.SendToServer() + end + + CPanel:AddItem(c) + end + + for printname, cvartable in SortedPairs { + DetectionRange = { + name = "decentvehicle_detectionrange", + min = 1, max = 64, decimals = 0, + }, + DetectionRangeELS = { + name = "decentvehicle_elsrange", + min = 0, max = 1000, decimals = 0, + }, + } do + local n = vgui.Create("DNumSlider", CPanel) + local cvar = GetConVar(cvartable.name) + n:SetText(texts[printname]) + n:SetMinMax(cvartable.min, cvartable.max) + n:SetDecimals(cvartable.decimals) + n:SizeToContents() + n.Label:SetTextColor(n.Label:GetSkin().Colours.Label.Dark) + if cvar then + hook.Add("Decent Vehicle: Sync CVar", printname, function() + n:SetValue(cvar:GetFloat()) + end) + end + + if texts[printname .. "Help"] then n:SetTooltip(texts[printname .. "Help"]) end + function n:OnValueChanged(value) + net.Start "Decent Vehicle: Change serverside value" + net.WriteString(cvartable.name) + net.WriteString(tostring(value)) + net.SendToServer() + end + + CPanel:AddItem(n) + end + + local cvarlightlevelname = "decentvehicle_turnonlights" + local cvarlightlevel = GetConVar(cvarlightlevelname) + local comboboxlabel = vgui.Create("DLabel", CPanel) + local combobox = vgui.Create("DComboBox", CPanel) + local comboboxvalues = { + [0] = texts.LightLevel.None, + [1] = texts.LightLevel.Running, + [2] = texts.LightLevel.Headlights, + [3] = texts.LightLevel.All, + } + comboboxlabel:SetText(texts.LightLevel.Title) + comboboxlabel:SetTextColor(comboboxlabel:GetSkin().Colours.Label.Dark) + combobox:SetSortItems(false) + combobox:Dock(FILL) + for i, printname in SortedPairs(comboboxvalues) do + combobox:AddChoice(printname, i) + end + + if cvarlightlevel and comboboxvalues[cvarlightlevel:GetInt()] then + hook.Add("Decent Vehicle: Sync CVar", texts.LightLevel.Title, function() + combobox:SetValue(comboboxvalues[cvarlightlevel:GetInt()]) + end) + end + + function combobox:OnSelect(index, value, data) + net.Start "Decent Vehicle: Change serverside value" + net.WriteString(cvarlightlevelname) + net.WriteString(tostring(index)) + net.SendToServer() + end + + CPanel:AddItem(comboboxlabel, combobox) + CPanel:Button(texts.Save, "dv_route_save") + CPanel:Button(texts.Restore, "dv_route_load") + CPanel:Button(texts.Delete, "dv_route_delete") + CPanel:Button(texts.Generate, "dv_route_generate") + hook.Run "Decent Vehicle: Sync CVar" + end + + CPanel:InvalidateLayout() end if SERVER then return end function TOOL:DrawHUD() - if self:GetClientNumber "showpoints" == 0 then return end - local pos = LocalPlayer():GetEyeTrace().HitPos - local waypoint, waypointID = dvd.GetNearestWaypoint(pos, dvd.WaypointSize) - if not waypoint then return end - net.Start "Decent Vehicle: Send waypoint info" - net.WriteUInt(waypointID, 24) - net.SendToServer() - - if not waypoint.SpeedLimit then return end - local textpos = pos:ToScreen() - for _, text in ipairs { - texts.ShowInfo.ID .. tostring(waypointID), - texts.ShowInfo.Group .. tostring(waypoint.Group), - texts.ShowInfo.SpeedLimit .. tostring(math.Round(waypoint.SpeedLimit / dvd.KmphToHUps, 2)), - texts.ShowInfo.WaitUntilNext .. tostring(math.Round(waypoint.WaitUntilNext, 2)), - texts.ShowInfo.UseTurnLights .. (waypoint.UseTurnLights and "Yes" or "No"), - texts.ShowInfo.FuelStation .. (waypoint.FuelStation and "Yes" or "No"), - } do - textpos.y = textpos.y + select(2, draw.SimpleTextOutlined( - text, "CloseCaption_Normal", textpos.x, textpos.y, color_white, - TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP, 2, color_black)) - end + if self:GetClientNumber "showpoints" == 0 then return end + local pos = LocalPlayer():GetEyeTrace().HitPos + local waypoint, waypointID = dvd.GetNearestWaypoint(pos, dvd.WaypointSize) + if not waypoint then return end + net.Start "Decent Vehicle: Send waypoint info" + net.WriteUInt(waypointID, 24) + net.SendToServer() + + if not waypoint.SpeedLimit then return end + local textpos = pos:ToScreen() + for _, text in ipairs { + texts.ShowInfo.ID .. tostring(waypointID), + texts.ShowInfo.Group .. tostring(waypoint.Group), + texts.ShowInfo.SpeedLimit .. tostring(math.Round(waypoint.SpeedLimit / dvd.KmphToHUps, 2)), + texts.ShowInfo.WaitUntilNext .. tostring(math.Round(waypoint.WaitUntilNext, 2)), + texts.ShowInfo.UseTurnLights .. (waypoint.UseTurnLights and "Yes" or "No"), + texts.ShowInfo.FuelStation .. (waypoint.FuelStation and "Yes" or "No"), + } do + textpos.y = textpos.y + select(2, draw.SimpleTextOutlined( + text, "CloseCaption_Normal", textpos.x, textpos.y, color_white, + TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP, 2, color_black)) + end end diff --git a/lua/wire/stools/dv_wiremanager.lua b/lua/wire/stools/dv_wiremanager.lua index 55d3883..76946f6 100644 --- a/lua/wire/stools/dv_wiremanager.lua +++ b/lua/wire/stools/dv_wiremanager.lua @@ -3,15 +3,15 @@ WireToolSetup.open( "dv_wiremanager", "Waypoint Manager", "gmod_wire_dvmanager", local dvd = DecentVehicleDestination if CLIENT then - language.Add( "Tool.wire_dv_wiremanager.name", dvd.Texts.WireSupport.ToolName) - language.Add( "Tool.wire_dv_wiremanager.desc", dvd.Texts.WireSupport.ToolDesc) + language.Add( "Tool.wire_dv_wiremanager.name", dvd.Texts.WireSupport.ToolName) + language.Add( "Tool.wire_dv_wiremanager.desc", dvd.Texts.WireSupport.ToolDesc) end WireToolSetup.BaseLang() WireToolSetup.SetupMax( 100 ) WireToolSetup.SetupLinking(true, "waypoint") TOOL.ClientConVar = { - model = "models/props_c17/lampShade001a.mdl", + model = "models/props_c17/lampShade001a.mdl", } if SERVER then function TOOL:GetConVars() end end @@ -68,5 +68,5 @@ function TOOL:Reload(trace) end function TOOL.BuildCPanel(panel) - WireDermaExts.ModelSelect(panel, "wire_dv_wiremanager_model", list.Get( "[DV] WireManager Model List" ), 4, true) + WireDermaExts.ModelSelect(panel, "wire_dv_wiremanager_model", list.Get( "[DV] WireManager Model List" ), 4, true) end diff --git a/materials/decentvehicle/ent_dvtaxi_station/screen.vmt b/materials/decentvehicle/ent_dvtaxi_station/screen.vmt index f5d6fb4..0b31432 100644 --- a/materials/decentvehicle/ent_dvtaxi_station/screen.vmt +++ b/materials/decentvehicle/ent_dvtaxi_station/screen.vmt @@ -1,25 +1,25 @@ "VertexLitGeneric" { - "$basetexture" "decentvehicle/ent_dvtaxi_station/screen" - "$bumpmap" "decentvehicle/ent_dvtaxi_station/normal" - "$nodecal" "1" - "$phong" "1" - "$phongexponent" "27" - "$phongboost" "1.3" - "$envmap" "env_cubemap" - "$envmapfresnel" "3" - "$phongfresnelranges" "[ 0 0 0]" - "$envmaptint" "[0 0 0]" - "$phongfix" "{0 0 0}" - "$colorfix" "{255 255 255}" - "Proxies" - { - "Equals" - { - srcVar1 $colorfix - resultVar $color - } - } + "$basetexture" "decentvehicle/ent_dvtaxi_station/screen" + "$bumpmap" "decentvehicle/ent_dvtaxi_station/normal" + "$nodecal" "1" + "$phong" "1" + "$phongexponent" "27" + "$phongboost" "1.3" + "$envmap" "env_cubemap" + "$envmapfresnel" "3" + "$phongfresnelranges" "[ 0 0 0]" + "$envmaptint" "[0 0 0]" + "$phongfix" "{0 0 0}" + "$colorfix" "{255 255 255}" + "Proxies" + { + "Equals" + { + srcVar1 $colorfix + resultVar $color + } + } } diff --git a/materials/decentvehicle/ent_dvtaxi_station/skin.vmt b/materials/decentvehicle/ent_dvtaxi_station/skin.vmt index 86a76c2..9fa4a76 100644 --- a/materials/decentvehicle/ent_dvtaxi_station/skin.vmt +++ b/materials/decentvehicle/ent_dvtaxi_station/skin.vmt @@ -1,25 +1,25 @@ "VertexLitGeneric" { - "$basetexture" "decentvehicle/ent_dvtaxi_station/skin" - "$bumpmap" "decentvehicle/ent_dvtaxi_station/normal" - "$nodecal" "1" - "$phong" "1" - "$phongexponent" "27" - "$phongboost" "1.3" - "$envmap" "env_cubemap" - "$envmapfresnel" "3" - "$phongfresnelranges" "[ 0 0 0]" - "$envmaptint" "[0 0 0]" - "$phongfix" "{0 0 0}" - "$colorfix" "{255 255 255}" - "Proxies" - { - "Equals" - { - srcVar1 $colorfix - resultVar $color - } - } + "$basetexture" "decentvehicle/ent_dvtaxi_station/skin" + "$bumpmap" "decentvehicle/ent_dvtaxi_station/normal" + "$nodecal" "1" + "$phong" "1" + "$phongexponent" "27" + "$phongboost" "1.3" + "$envmap" "env_cubemap" + "$envmapfresnel" "3" + "$phongfresnelranges" "[ 0 0 0]" + "$envmaptint" "[0 0 0]" + "$phongfix" "{0 0 0}" + "$colorfix" "{255 255 255}" + "Proxies" + { + "Equals" + { + srcVar1 $colorfix + resultVar $color + } + } } diff --git a/materials/decentvehicle/trafficlight/body.vmt b/materials/decentvehicle/trafficlight/body.vmt index db12f08..221cdc7 100644 --- a/materials/decentvehicle/trafficlight/body.vmt +++ b/materials/decentvehicle/trafficlight/body.vmt @@ -5,26 +5,26 @@ "VertexLitGeneric" { - "$basetexture" "decentvehicle/trafficlight/body" - "$bumpmap" "decentvehicle/trafficlight/normal" - "$nodecal" "1" - "$phong" "1" - "$phongexponent" "27" - "$phongboost" "1.3" - "$envmap" "env_cubemap" - "$envmapfresnel" "3" - "$phongfresnelranges" "[ 0 0 0]" - "$envmaptint" "[0 0 0]" - "$phongfix" "{0 0 0}" - "$colorfix" "{255 255 255}" - "Proxies" - { - "Equals" - { - srcVar1 $colorfix - resultVar $color - } - } + "$basetexture" "decentvehicle/trafficlight/body" + "$bumpmap" "decentvehicle/trafficlight/normal" + "$nodecal" "1" + "$phong" "1" + "$phongexponent" "27" + "$phongboost" "1.3" + "$envmap" "env_cubemap" + "$envmapfresnel" "3" + "$phongfresnelranges" "[ 0 0 0]" + "$envmaptint" "[0 0 0]" + "$phongfix" "{0 0 0}" + "$colorfix" "{255 255 255}" + "Proxies" + { + "Equals" + { + srcVar1 $colorfix + resultVar $color + } + } } diff --git a/materials/decentvehicle/trafficlight/lg.vmt b/materials/decentvehicle/trafficlight/lg.vmt index 6375c3e..eb31dab 100644 --- a/materials/decentvehicle/trafficlight/lg.vmt +++ b/materials/decentvehicle/trafficlight/lg.vmt @@ -5,24 +5,24 @@ "UnlitGeneric" { - "$basetexture" "decentvehicle/trafficlight/lg" - "$nodecal" "1" - "$phong" "1" - "$phongboost" "0.1" - "$phongfresnelranges" "[1 1 1]" - "$phongexponent" 150 - "$envmap" "env_cubemap" - "$envmaptint" "[0.1 0.1 0.1]" - "$envmapfresnel" "1.65" - "$halflambert" 1 - "$colorfix" "{255 255 255}" - "$selfillum" 1 - "Proxies" - { - "Equals" - { - srcVar1 $colorfix - resultVar $color - } - } + "$basetexture" "decentvehicle/trafficlight/lg" + "$nodecal" "1" + "$phong" "1" + "$phongboost" "0.1" + "$phongfresnelranges" "[1 1 1]" + "$phongexponent" 150 + "$envmap" "env_cubemap" + "$envmaptint" "[0.1 0.1 0.1]" + "$envmapfresnel" "1.65" + "$halflambert" 1 + "$colorfix" "{255 255 255}" + "$selfillum" 1 + "Proxies" + { + "Equals" + { + srcVar1 $colorfix + resultVar $color + } + } } \ No newline at end of file diff --git a/materials/decentvehicle/trafficlight/lightg.vmt b/materials/decentvehicle/trafficlight/lightg.vmt index 7af9565..7820677 100644 --- a/materials/decentvehicle/trafficlight/lightg.vmt +++ b/materials/decentvehicle/trafficlight/lightg.vmt @@ -5,32 +5,32 @@ "VertexLitGeneric" { - "$basetexture" "decentvehicle/trafficlight/light" - "$bumpmap" "decentvehicle/trafficlight/normal" - "$nodecal" "1" - "$phong" "1" - "$phongexponent" "27" - "$phongboost" "1.3" - "$envmap" "env_cubemap" - "$envmapfresnel" "1.65" - "$phongfresnelranges" "[.4 .7 .74]" - "$envmaptint" "[0.4 0.4 0.4]" - "$phongfix" "{20 20 20}" + "$basetexture" "decentvehicle/trafficlight/light" + "$bumpmap" "decentvehicle/trafficlight/normal" + "$nodecal" "1" + "$phong" "1" + "$phongexponent" "27" + "$phongboost" "1.3" + "$envmap" "env_cubemap" + "$envmapfresnel" "1.65" + "$phongfresnelranges" "[.4 .7 .74]" + "$envmaptint" "[0.4 0.4 0.4]" + "$phongfix" "{20 20 20}" - Proxies - { - Equals - { - srcVar1 $color - resultVar $phongtint - } - Add - { - srcVar1 $phongfix - srcVar2 $phongtint - resultVar $phongtint - } - } + Proxies + { + Equals + { + srcVar1 $color + resultVar $phongtint + } + Add + { + srcVar1 $phongfix + srcVar2 $phongtint + resultVar $phongtint + } + } } diff --git a/materials/decentvehicle/trafficlight/lightr.vmt b/materials/decentvehicle/trafficlight/lightr.vmt index e2dad3b..48d8313 100644 --- a/materials/decentvehicle/trafficlight/lightr.vmt +++ b/materials/decentvehicle/trafficlight/lightr.vmt @@ -5,32 +5,32 @@ "VertexLitGeneric" { - "$basetexture" "decentvehicle/trafficlight/light" - "$bumpmap" "decentvehicle/trafficlight/normal" - "$nodecal" "1" - "$phong" "1" - "$phongexponent" "27" - "$phongboost" "1.3" - "$envmap" "env_cubemap" - "$envmapfresnel" "1.65" - "$phongfresnelranges" "[.4 .7 .74]" - "$envmaptint" "[0.4 0.4 0.4]" - "$phongfix" "{20 20 20}" - - Proxies - { - Equals - { - srcVar1 $color - resultVar $phongtint - } - Add - { - srcVar1 $phongfix - srcVar2 $phongtint - resultVar $phongtint - } - } + "$basetexture" "decentvehicle/trafficlight/light" + "$bumpmap" "decentvehicle/trafficlight/normal" + "$nodecal" "1" + "$phong" "1" + "$phongexponent" "27" + "$phongboost" "1.3" + "$envmap" "env_cubemap" + "$envmapfresnel" "1.65" + "$phongfresnelranges" "[.4 .7 .74]" + "$envmaptint" "[0.4 0.4 0.4]" + "$phongfix" "{20 20 20}" + + Proxies + { + Equals + { + srcVar1 $color + resultVar $phongtint + } + Add + { + srcVar1 $phongfix + srcVar2 $phongtint + resultVar $phongtint + } + } } diff --git a/materials/decentvehicle/trafficlight/lighty.vmt b/materials/decentvehicle/trafficlight/lighty.vmt index 7af9565..7820677 100644 --- a/materials/decentvehicle/trafficlight/lighty.vmt +++ b/materials/decentvehicle/trafficlight/lighty.vmt @@ -5,32 +5,32 @@ "VertexLitGeneric" { - "$basetexture" "decentvehicle/trafficlight/light" - "$bumpmap" "decentvehicle/trafficlight/normal" - "$nodecal" "1" - "$phong" "1" - "$phongexponent" "27" - "$phongboost" "1.3" - "$envmap" "env_cubemap" - "$envmapfresnel" "1.65" - "$phongfresnelranges" "[.4 .7 .74]" - "$envmaptint" "[0.4 0.4 0.4]" - "$phongfix" "{20 20 20}" + "$basetexture" "decentvehicle/trafficlight/light" + "$bumpmap" "decentvehicle/trafficlight/normal" + "$nodecal" "1" + "$phong" "1" + "$phongexponent" "27" + "$phongboost" "1.3" + "$envmap" "env_cubemap" + "$envmapfresnel" "1.65" + "$phongfresnelranges" "[.4 .7 .74]" + "$envmaptint" "[0.4 0.4 0.4]" + "$phongfix" "{20 20 20}" - Proxies - { - Equals - { - srcVar1 $color - resultVar $phongtint - } - Add - { - srcVar1 $phongfix - srcVar2 $phongtint - resultVar $phongtint - } - } + Proxies + { + Equals + { + srcVar1 $color + resultVar $phongtint + } + Add + { + srcVar1 $phongfix + srcVar2 $phongtint + resultVar $phongtint + } + } } diff --git a/materials/decentvehicle/trafficlight/lr.vmt b/materials/decentvehicle/trafficlight/lr.vmt index 2cec482..2e7c837 100644 --- a/materials/decentvehicle/trafficlight/lr.vmt +++ b/materials/decentvehicle/trafficlight/lr.vmt @@ -5,24 +5,24 @@ "UnlitGeneric" { - "$basetexture" "decentvehicle/trafficlight/lr" - "$nodecal" "1" - "$phong" "1" - "$phongboost" "0.1" - "$phongfresnelranges" "[1 1 1]" - "$phongexponent" 150 - "$envmap" "env_cubemap" - "$envmaptint" "[0.1 0.1 0.1]" - "$envmapfresnel" "1.65" - "$halflambert" 1 - "$colorfix" "{255 255 255}" - "$selfillum" 1 - "Proxies" - { - "Equals" - { - srcVar1 $colorfix - resultVar $color - } - } + "$basetexture" "decentvehicle/trafficlight/lr" + "$nodecal" "1" + "$phong" "1" + "$phongboost" "0.1" + "$phongfresnelranges" "[1 1 1]" + "$phongexponent" 150 + "$envmap" "env_cubemap" + "$envmaptint" "[0.1 0.1 0.1]" + "$envmapfresnel" "1.65" + "$halflambert" 1 + "$colorfix" "{255 255 255}" + "$selfillum" 1 + "Proxies" + { + "Equals" + { + srcVar1 $colorfix + resultVar $color + } + } } \ No newline at end of file diff --git a/materials/decentvehicle/trafficlight/ly.vmt b/materials/decentvehicle/trafficlight/ly.vmt index 5a1a839..2ca78ce 100644 --- a/materials/decentvehicle/trafficlight/ly.vmt +++ b/materials/decentvehicle/trafficlight/ly.vmt @@ -5,24 +5,24 @@ "UnlitGeneric" { - "$basetexture" "decentvehicle/trafficlight/ly" - "$nodecal" "1" - "$phong" "1" - "$phongboost" "0.1" - "$phongfresnelranges" "[1 1 1]" - "$phongexponent" 150 - "$envmap" "env_cubemap" - "$envmaptint" "[0.1 0.1 0.1]" - "$envmapfresnel" "1.65" - "$halflambert" 1 - "$colorfix" "{255 255 255}" - "$selfillum" 1 - "Proxies" - { - "Equals" - { - srcVar1 $colorfix - resultVar $color - } - } + "$basetexture" "decentvehicle/trafficlight/ly" + "$nodecal" "1" + "$phong" "1" + "$phongboost" "0.1" + "$phongfresnelranges" "[1 1 1]" + "$phongexponent" 150 + "$envmap" "env_cubemap" + "$envmaptint" "[0.1 0.1 0.1]" + "$envmapfresnel" "1.65" + "$halflambert" 1 + "$colorfix" "{255 255 255}" + "$selfillum" 1 + "Proxies" + { + "Equals" + { + srcVar1 $colorfix + resultVar $color + } + } } \ No newline at end of file diff --git a/materials/vgui/entities/ent_dv_traffic_light.vmt b/materials/vgui/entities/ent_dv_traffic_light.vmt index aa1b41f..9a6d7c0 100644 --- a/materials/vgui/entities/ent_dv_traffic_light.vmt +++ b/materials/vgui/entities/ent_dv_traffic_light.vmt @@ -5,8 +5,8 @@ "UnlitGeneric" { - "$basetexture" "vgui/entities/ent_dv_traffic_light" - "$nolod" 1 - "$vertexalpha" 1 - "$vertexcolor" 1 + "$basetexture" "vgui/entities/ent_dv_traffic_light" + "$nolod" "1" + "$vertexalpha" "1" + "$vertexcolor" "1" } diff --git a/materials/vgui/entities/ent_dvtaxi_station.vmt b/materials/vgui/entities/ent_dvtaxi_station.vmt index 0baeace..a0490cb 100644 --- a/materials/vgui/entities/ent_dvtaxi_station.vmt +++ b/materials/vgui/entities/ent_dvtaxi_station.vmt @@ -5,8 +5,8 @@ "UnlitGeneric" { - "$basetexture" "vgui/entities/ent_dvtaxi_station" - "$nolod" 1 - "$vertexalpha" 1 - "$vertexcolor" 1 + "$basetexture" "vgui/entities/ent_dvtaxi_station" + "$nolod" "1" + "$vertexalpha" "1" + "$vertexcolor" "1" } diff --git a/materials/vgui/entities/npc_decentvehicle.vmt b/materials/vgui/entities/npc_decentvehicle.vmt index 1cdf95e..ef79a00 100644 --- a/materials/vgui/entities/npc_decentvehicle.vmt +++ b/materials/vgui/entities/npc_decentvehicle.vmt @@ -5,8 +5,8 @@ "UnlitGeneric" { - "$basetexture" "vgui/entities/npc_decentvehicle" - "$nolod" 1 - "$vertexalpha" 1 - "$vertexcolor" 1 + "$basetexture" "vgui/entities/npc_decentvehicle" + "$nolod" "1" + "$vertexalpha" "1" + "$vertexcolor" "1" } diff --git a/materials/vgui/entities/npc_dvpolice.vmt b/materials/vgui/entities/npc_dvpolice.vmt index 0906b39..26a3d57 100644 --- a/materials/vgui/entities/npc_dvpolice.vmt +++ b/materials/vgui/entities/npc_dvpolice.vmt @@ -5,8 +5,8 @@ "UnlitGeneric" { - "$basetexture" "vgui/entities/npc_dvpolice" - "$nolod" 1 - "$vertexalpha" 1 - "$vertexcolor" 1 + "$basetexture" "vgui/entities/npc_dvpolice" + "$nolod" "1" + "$vertexalpha" "1" + "$vertexcolor" "1" } diff --git a/materials/vgui/entities/npc_dvtaxi.vmt b/materials/vgui/entities/npc_dvtaxi.vmt index a321f94..5902aa3 100644 --- a/materials/vgui/entities/npc_dvtaxi.vmt +++ b/materials/vgui/entities/npc_dvtaxi.vmt @@ -5,8 +5,8 @@ "UnlitGeneric" { - "$basetexture" "vgui/entities/npc_dvtaxi" - "$nolod" 1 - "$vertexalpha" 1 - "$vertexcolor" 1 + "$basetexture" "vgui/entities/npc_dvtaxi" + "$nolod" "1" + "$vertexalpha" "1" + "$vertexcolor" "1" } diff --git a/materials/vgui/entities/npc_learningvehicle.vmt b/materials/vgui/entities/npc_learningvehicle.vmt index 1000a19..6d83f8c 100644 --- a/materials/vgui/entities/npc_learningvehicle.vmt +++ b/materials/vgui/entities/npc_learningvehicle.vmt @@ -5,8 +5,8 @@ "UnlitGeneric" { - "$basetexture" "vgui/entities/npc_learningvehicle" - "$nolod" 1 - "$vertexalpha" 1 - "$vertexcolor" 1 + "$basetexture" "vgui/entities/npc_learningvehicle" + "$nolod" "1" + "$vertexalpha" "1" + "$vertexcolor" "1" }