Skip to content

Commit

Permalink
New overlays, Turret mechanics
Browse files Browse the repository at this point in the history
Added new overlays to gearboxes/engines
- When looking at any gearbox or engine, the entire link chain will have links rendered, as well as inputs/outputs for each one, as well as connections to any wheels
Useful for figuring it of something was linked wrong, or a link broke

Updated overlay for turrets
- Using some much nicer looking quads to display various aspects of the turret, including home angle, current angle, and arc limits
- When you look at a turret with just the physgun, an orange arrow will point in the home direction, to aid with placing the turret correctly.

New mechanics for turrets
- Complexity, if multiple of the same turret type get stacked on each other above a certain relative size, there will be greatly reduced speeds for everything in the chain
- Max mass, when the mass loaded on a turret goes over this, the efficiency of the turret's power source steadily reaches 0 as the mass approaches 3 times the limit. It is possible to power through the efficiency loss with a more powerful motor, but only so far. This is reflected in the turret simulation panel in the menu.
- Max speed slider: New option in the menu to allow someone to set a more realistic limit on the speed of a turret. If it is 0, it will default to the turret's normal max speed. Otherwise, the lowest speed will be used between the turret's normal max speed and this setting.
- Removed the clientside model rendering, in favor of using the existing rendermatrix. This should cut down on needless checks on the client when the turret is being rendered, and will just render the turret's model rotated as needed.

Increased armor on turrets
- Just broadly increased the armor so they are easier to keep alive without covering them up

Sound replacer addition
- Allowed sound replacement for turret motors

Replaced more usages of self with a local entity table where applicable (and likely missed or skipped some)

Also, fixed a small type in the howitzer definition file
  • Loading branch information
LiddulBOFH committed May 25, 2024
1 parent 4829332 commit 2c3a4b2
Show file tree
Hide file tree
Showing 11 changed files with 762 additions and 139 deletions.
43 changes: 34 additions & 9 deletions lua/acf/core/utilities/util_cl.lua
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,7 @@ end

do -- Default turret menus
local Turrets = ACF.Classes.Turrets
local TurretMassText = "Drive Mass : %s kg, %s kg max capacity"
local MassText = "Mass : %s kg"

do -- Turret ring
Expand All @@ -483,6 +484,7 @@ do -- Default turret menus
TurretClass = Data.ID,
Teeth = TurretClass.GetTeethCount(Data,Data.Size.Base),
TotalMass = 0,
MaxMass = 0,
RingSize = Data.Size.Base,
RingHeight = TurretClass.GetRingHeight({Type = "Turret-H",Ratio = Data.Size.Ratio},Data.Size.Base),
LocalCoM = Vector(),
Expand All @@ -491,13 +493,17 @@ do -- Default turret menus

local RingSize = Menu:AddSlider("Ring Diameter", Data.Size.Min, Data.Size.Max, 2)

local RingStats = Menu:AddLabel(TurretText:format(0,0))
local MassLbl = Menu:AddLabel(MassText:format(0))
local MaxSpeed = Menu:AddSlider("Max Speed (deg/s)", 0, 120, 2)

Menu:AddLabel("If the Max Speed slider is lower than the calculated max speed of the turret, this will be the new limit. If 0, it will default to the actual max speed.")

Menu:AddLabel("If the total arc is less than 360, then it will use the limits set here.\nIf it is 360, then it will have free rotation.")
local RingStats = Menu:AddLabel(TurretText:format(0,0))
local MassLbl = Menu:AddLabel(MassText:format(0,0))

local ArcSettings = Menu:AddCollapsible("Arc Settings")

ArcSettings:AddLabel("If the total arc is less than 360, then it will use the limits set here.\nIf it is 360, then it will have free rotation.")

local MinDeg = ArcSettings:AddSlider("Minimum Degrees", -180, 0, 1)
local MaxDeg = ArcSettings:AddSlider("Maximum Degrees", 0, 180, 1)

Expand Down Expand Up @@ -617,7 +623,8 @@ do -- Default turret menus
Teeth = TurretData.Teeth,
Tilt = 1,
TurretClass = TurretData.TurretClass,
TotalMass = 0
TotalMass = 0,
MaxMass = TurretData.MaxMass,
}

local Points = {}
Expand Down Expand Up @@ -645,19 +652,31 @@ do -- Default turret menus

local Teeth = TurretClass.GetTeethCount(Data,N)
RingStats:SetText(TurretText:format(Teeth))
MassLbl:SetText(MassText:format(TurretClass.GetMass(Data,N)))
local MaxMass = TurretClass.GetMaxMass(Data,N)
MassLbl:SetText(TurretMassText:format(TurretClass.GetMass(Data,N), MaxMass))

TurretData.Teeth = Teeth
TurretData.RingSize = N
TurretData.RingHeight = TurretClass.GetRingHeight({Type = Data.ID,Ratio = Data.Size.Ratio},N)
TurretData.MaxMass = MaxMass

EstDist:SetMinMax(0,math.max(N * 2,24))
MaxSpeed:SetValue(0)

HandCrankLbl:UpdateSim()

return N
end)

MaxSpeed:SetClientData("MaxSpeed", "OnValueChanged")
MaxSpeed:DefineSetter(function(Panel, _, _, Value)
local N = Value

Panel:SetValue(N)

return N
end)

EstMass.OnValueChanged = function(_, Value)
TurretData.TotalMass = Value

Expand All @@ -673,6 +692,7 @@ do -- Default turret menus
RingSize:SetValue(Data.Size.Base)
EstMass:SetValue(0)
EstDist:SetValue(0)
MaxSpeed:SetValue(0)

TurretData.Ready = true
HandCrankLbl:UpdateSim()
Expand Down Expand Up @@ -711,7 +731,7 @@ do -- Default turret menus
Menu:AddLabel("Determines the number of teeth of the gear on the motor.")
local TeethAmt = Menu:AddSlider("Gear Teeth (" .. Data.Teeth.Min .. "-" .. Data.Teeth.Max .. ")", Data.Teeth.Min, Data.Teeth.Max, 0)

local MassLbl = Menu:AddLabel(MassText:format(0))
local MassLbl = Menu:AddLabel(TurretMassText:format(0,0))
local TorqLbl = Menu:AddLabel(TorqText:format(0))

-- Simulation
Expand All @@ -727,6 +747,8 @@ do -- Default turret menus

local EstDist = TurretSim:AddSlider("Mass Center Dist.", 0, 2, 2)

local MaxMassLbl = TurretSim:AddLabel("Max mass: 0kg")

local Graph = Menu:AddGraph()
local GraphSize = Menu:GetParent():GetParent():GetWide()
Graph:SetSize(GraphSize, GraphSize / 2)
Expand All @@ -746,7 +768,8 @@ do -- Default turret menus
Teeth = TurretData.TurretTeeth,
Tilt = 1,
TurretClass = TurretData.Type,
TotalMass = 0
TotalMass = 0,
MaxMass = TurretData.MaxMass,
}

local SimMotorData = {
Expand Down Expand Up @@ -781,7 +804,7 @@ do -- Default turret menus
HandcrankInfo.UpdateSim = function(Panel)
if TurretData.Ready == false then return end

local Info = TurretClass.CalcSpeed({Tilt = 1, TotalMass = TurretData.Mass, RingSize = TurretData.Size, Teeth = TurretData.TurretTeeth, TurretClass = TurretData.Type, LocalCoM = Vector(TurretData.Distance,0,TurretData.Distance), RingHeight = TurretData.RingHeight},
local Info = TurretClass.CalcSpeed({Tilt = 1, TotalMass = TurretData.Mass, MaxMass = TurretData.MaxMass, RingSize = TurretData.Size, Teeth = TurretData.TurretTeeth, TurretClass = TurretData.Type, LocalCoM = Vector(TurretData.Distance,0,TurretData.Distance), RingHeight = TurretData.RingHeight},
TurretClass.HandGear)

Panel:SetText(HandcrankText:format(math.Round(Info.MaxSlewRate, 2), math.Round(Info.SlewAccel, 4)))
Expand All @@ -794,7 +817,7 @@ do -- Default turret menus
MotorInfo.UpdateSim = function(Panel)
if TurretData.Ready == false then return end

local Info = TurretClass.CalcSpeed({Tilt = 1, TotalMass = TurretData.Mass, RingSize = TurretData.Size, Teeth = TurretData.TurretTeeth, TurretClass = TurretData.Type, LocalCoM = Vector(TurretData.Distance,0,TurretData.Distance), RingHeight = TurretData.RingHeight},
local Info = TurretClass.CalcSpeed({Tilt = 1, TotalMass = TurretData.Mass, MaxMass = TurretData.MaxMass, RingSize = TurretData.Size, Teeth = TurretData.TurretTeeth, TurretClass = TurretData.Type, LocalCoM = Vector(TurretData.Distance,0,TurretData.Distance), RingHeight = TurretData.RingHeight},
{Teeth = TurretData.MotorTeeth, Speed = Data.Speed, Torque = TurretData.Torque, Efficiency = Data.Efficiency, Accel = Data.Accel})

Panel:SetText(MotorText:format(math.Round(Info.MaxSlewRate, 2), math.Round(Info.SlewAccel, 4)))
Expand Down Expand Up @@ -841,8 +864,10 @@ do -- Default turret menus
TurretData.Size = Value
TurretData.RingHeight = TurretClass.GetRingHeight({Type = TurretData.Turret, Ratio = TurretData.Turret.Size.Ratio},Value)
TurretData.TurretTeeth = TurretClass.GetTeethCount(TurretData.Turret,Value)
TurretData.MaxMass = TurretClass.GetMaxMass(TurretData.Turret,Value)

EstDist:SetMinMax(0,math.max(Value * 2,24))
MaxMassLbl:SetText("Max mass: " .. math.Round(TurretData.MaxMass,1) .. "kg")

MotorInfo:UpdateSim()
HandcrankInfo:UpdateSim()
Expand Down
29 changes: 24 additions & 5 deletions lua/acf/entities/turrets/turrets.lua
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ do -- Turret drives
GetMass = function(Data, Size)
return math.Round(math.max(Data.Mass * (Size / Data.Size.Base),5) ^ 1.5, 1)
end,
GetMaxMass = function(Data, Size)
local SizePerc = (Size - Data.Size.Min) / (Data.Size.Max - Data.Size.Min)
return math.Round(((Data.MassLimit.Min * (1 - SizePerc)) + (Data.MassLimit.Max * SizePerc)) ^ 2, 1)
end,
GetTeethCount = function(Data, Size)
local SizePerc = (Size - Data.Size.Min) / (Data.Size.Max - Data.Size.Min)
return math.Round((Data.Teeth.Min * (1 - SizePerc)) + (Data.Teeth.Max * SizePerc))
Expand Down Expand Up @@ -85,6 +89,11 @@ do -- Turret drives
local Diameter = (TurretData.RingSize * InchToMm) -- Used for some of the formulas from the referenced page, needs to be in mm
local CoMDistance = (TurretData.LocalCoM * Vector(1,1,0)):Length() * (InchToMm / 1000) -- (Lateral) Distance of center of mass from center of axis, in meters for calculation
local OffBaseDistance = math.max(CoMDistance - math.max(CoMDistance - (Diameter / 2),0),0)
local OverweightMod = 1

if TurretData.TotalMass > TurretData.MaxMass then
OverweightMod = 1 - (((TurretData.TotalMass - TurretData.MaxMass) / TurretData.MaxMass) / 2)
end

-- Slewing ring friction moment caused by load (kNm)
-- 1kg weight (mass * gravity) is about 9.81N
Expand Down Expand Up @@ -112,7 +121,7 @@ do -- Turret drives
-- 9.55 is 1 rad/s to RPM
-- Required power to rotate at full speed
-- With this we can lower maximum attainable speed
local ReqConstantPower = (Mz * TopSpeed) / (9.55 * PowerData.Efficiency)
local ReqConstantPower = (Mz * TopSpeed) / (9.55 * PowerData.Efficiency * OverweightMod)

if (math.max(1,ReqConstantPower) / math.max(MaxPower,1)) > 1 then return {SlewAccel = 0, MaxSlewRate = 0} end -- Too heavy to rotate, so we'll just stop here

Expand Down Expand Up @@ -157,8 +166,13 @@ do -- Turret drives
},

Armor = {
Min = 15,
Max = 175
Min = 50,
Max = 300
},

MassLimit = {
Min = 12,
Max = 960
},

SetupInputs = function(_,List)
Expand Down Expand Up @@ -224,8 +238,13 @@ do -- Turret drives
},

Armor = {
Min = 5,
Max = 305
Min = 50,
Max = 300
},

MassLimit = {
Min = 16,
Max = 256
},

SetupInputs = function(_,List)
Expand Down
2 changes: 1 addition & 1 deletion lua/acf/entities/weapons/howitzer.lua
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ local Weapons = ACF.Classes.Weapons

Weapons.Register("HW", {
Name = "Howitzer",
Description = "Analog of cannons, except it's intended to fire explosive and chemical rounds where its bigger round size a exceels at.",
Description = "Analog of cannons, except it's intended to fire explosive and chemical rounds where the bigger round size excels.",
Sound = "acf_base/weapons/howitzer_new2.mp3",
Model = "models/howitzer/howitzer_105mm.mdl",
MuzzleFlash = "howie_muzzleflash_noscale",
Expand Down
114 changes: 114 additions & 0 deletions lua/entities/acf_engine/cl_init.lua
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
local ACF = ACF
local Clock = ACF.Utilities.Clock
local Queued = {}

include("shared.lua")

language.Add("Cleanup_acf_engine", "ACF Engines")
Expand All @@ -7,3 +11,113 @@ language.Add("SBoxLimit__acf_engine", "You've reached the ACF Engines limit!")
function ENT:Update()
self.HitBoxes = ACF.GetHitboxes(self:GetModel())
end

do -- NET SURFER 2.0
net.Receive("ACF_InvalidateEngineInfo",function()
local Engine = net.ReadEntity()

if not IsValid(Engine) then return end

Engine.HasData = false
end)

net.Receive("ACF_RequestEngineInfo",function()
local Engine = net.ReadEntity()
local Data = util.JSONToTable(net.ReadString())
local Outputs = util.JSONToTable(net.ReadString())

local OutEnts = {}

for _,E in ipairs(Outputs) do
local Ent = Entity(E)
local Pos = Ent:WorldToLocal(Ent:GetAttachment(Ent:LookupAttachment("input")).Pos)

OutEnts[#OutEnts + 1] = {Ent = Ent, Pos = Pos}
end

Engine.Outputs = OutEnts

Engine.Driveshaft = Data.Driveshaft

Engine.HasData = true
Engine.Age = Clock.CurTime + 5

Queued[Engine] = nil
end)

function ENT:RequestEngineInfo()
if Queued[self] then return end

Queued[self] = true

timer.Simple(5, function() Queued[self] = nil end)

net.Start("ACF_RequestEngineInfo")
net.WriteEntity(self)
net.SendToServer()
end
end

do -- Overlay
-- Rendered is used to prevent re-rendering as part of the extended link rendering

local red = Color(255,0,0)
local orange = Color(255,127,0)
function ENT:DrawLinks(Rendered)
if Rendered[self] then return end
local SelfTbl = self:GetTable()

Rendered[self] = true

if not SelfTbl.HasData then
self:RequestEngineInfo()
return
elseif Clock.CurTime > SelfTbl.Age then
self:RequestEngineInfo()
end

-- draw links to gearboxes
local Perc = (Clock.CurTime / 2) % 1

local OutPos = self:LocalToWorld(SelfTbl.Driveshaft)
for _,T in ipairs(SelfTbl.Outputs) do
local E = T.Ent

if IsValid(E) then

local Pos = E:LocalToWorld(T.Pos)
--render.DrawLine(OutPos, Pos, color_white, true)
render.DrawBeam(OutPos, Pos, 2, 0, 0, color_black)
render.DrawBeam(OutPos, Pos, 1.5, 0, 0, color_white)
local SpherePos = LerpVector(Perc, OutPos, Pos)
render.DrawSphere(SpherePos, 2, 4, 3, orange)

if E.DrawLinks then
E:DrawLinks(Rendered,false)
end
end
end

render.DrawSphere(OutPos, 2, 4, 3, red)
end

function ENT:DrawOverlay()
local SelfTbl = self:GetTable()

if not SelfTbl.HasData then
self:RequestEngineInfo()
return
elseif Clock.CurTime > SelfTbl.Age then
self:RequestEngineInfo()
end

render.SetColorMaterial()

self:DrawLinks({self = true}, true)

local OutTextPos = self:LocalToWorld(SelfTbl.Driveshaft):ToScreen()
cam.Start2D()
draw.SimpleTextOutlined("Output","ACF_Title",OutTextPos.x,OutTextPos.y,color_white,TEXT_ALIGN_CENTER,TEXT_ALIGN_CENTER,1,color_black)
cam.End2D()
end
end
38 changes: 38 additions & 0 deletions lua/entities/acf_engine/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ do
Engine:UpdateOverlay()
Target:UpdateOverlay()

Engine:InvalidateClientInfo()

return true, "Engine linked successfully!"
end)

Expand All @@ -98,6 +100,8 @@ do
Engine:UpdateOverlay()
Target:UpdateOverlay()

Engine:InvalidateClientInfo()

return true, "Engine unlinked successfully!"
end)
end
Expand Down Expand Up @@ -900,4 +904,38 @@ function ENT:OnRemove()
TimerRemove("ACF Engine Clock " .. self:EntIndex())

WireLib.Remove(self)
end

do -- NET SURFER 2.0
util.AddNetworkString("ACF_RequestEngineInfo")
util.AddNetworkString("ACF_InvalidateEngineInfo")

function ENT:InvalidateClientInfo()
net.Start("ACF_InvalidateEngineInfo")
net.WriteEntity(self)
net.Broadcast()
end

net.Receive("ACF_RequestEngineInfo",function(_,Ply)
local Entity = net.ReadEntity()

if IsValid(Entity) then
local Outputs = {}
local Data = {
Driveshaft = Entity.Out
}

if next(Entity.Gearboxes) then
for E in pairs(Entity.Gearboxes) do
Outputs[#Outputs + 1] = E:EntIndex()
end
end

net.Start("ACF_RequestEngineInfo")
net.WriteEntity(Entity)
net.WriteString(util.TableToJSON(Data))
net.WriteString(util.TableToJSON(Outputs))
net.Send(Ply)
end
end)
end
Loading

0 comments on commit 2c3a4b2

Please sign in to comment.