Skip to content

Commit

Permalink
Added graph panel, self-unlink for turret entities
Browse files Browse the repository at this point in the history
New generic graph panel
Has various settings and various ways to plot on it (visible in acf_panel.lua)
Added to ammo menu, turret menu, and engine menu
Engine menu:
- Shows RPM range with torque (Nm) and power (HP)

Turret menu:
- Shows turret slew rates for hand crank (and if on the motor menu, motors too) for an estimated mass

Ammo menu:
- Dependent on the ammo type chose
 - AP and equivalent types: shows penetration values up to 1km distance
 - HE: shows explosion radius
 - HEAT and equivalent types: shows penetration values by standoff distance
 - Smoke: shows smoke cloud size over time

Added auto-unlink for turret components, motors will automatically unlink if they are too far from the turret ring's/trunnion's radius, gyroscopes will unlink from the turret if they are over ACF.LinkDistance, and ballistic computers will unlink if they are also over ACF.LinkDistance from the linked gun

Closes #238
  • Loading branch information
LiddulBOFH committed Feb 13, 2024
1 parent 6e6cd27 commit afda4b8
Show file tree
Hide file tree
Showing 8 changed files with 567 additions and 20 deletions.
2 changes: 1 addition & 1 deletion lua/acf/contraption/contraption_sv.lua
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,7 @@ do -- ASSUMING DIRECT CONTROL
local Ent = self:GetEntity()

-- Required due for AD2 support, if this isn't present then entities will never get set to their required weight on dupe paste
if Ent.IsACFEntity then Contraption.SetMass(self, Ent.ACF.Mass) return end
if Ent.IsACFEntity then Contraption.SetMass(Ent, Ent.ACF.Mass) return end

if Ent.ACF_OnMassChange then
Ent:ACF_OnMassChange(self:GetMass(), Mass)
Expand Down
7 changes: 4 additions & 3 deletions lua/acf/core/validation_sv.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

-- Local Vars -----------------------------------
local ACF = ACF
local Contraption = ACF.Contraption
local StringFind = string.find
local TimerSimple = timer.Simple
local Baddies = ACF.GlobalFilter
Expand Down Expand Up @@ -146,7 +145,8 @@ function ACF.UpdateThickness(Entity, PhysObj, Area, Ductility)
local Mass = Area * (1 + Ductility) ^ 0.5 * Thickness * 0.00078

if Mass ~= Entity.ACF.Mass then
Contraption.SetMass(Entity,Mass)
Entity.ACF.Mass = Mass
PhysObj:SetMass(Mass)
end

return Thickness
Expand All @@ -162,7 +162,8 @@ function ACF.UpdateThickness(Entity, PhysObj, Area, Ductility)
local Armor = ACF.CalcArmor(Area, Ductility, Mass)

if Mass ~= Entity.ACF.Mass then
Contraption.SetMass(Entity,Mass)
Entity.ACF.Mass = Mass
PhysObj:SetMass(Mass)

duplicator.StoreEntityModifier(Entity, "mass", { Mass = Mass })
end
Expand Down
121 changes: 105 additions & 16 deletions lua/acf/entities/turrets/turret_menu_cl.lua
Original file line number Diff line number Diff line change
Expand Up @@ -143,12 +143,47 @@ do -- Turret ring
Menu:AddLabel("Approximation of speed of the turret, with a handcrank.")
local HandCrankLbl = Menu:AddLabel(HandCrankText:format(0,0))

local Graph = Menu:AddGraph()
local GraphSize = Menu:GetParent():GetParent():GetWide()
Graph:SetSize(GraphSize, GraphSize / 2)
Graph:SetXLabel("Estimated Mass (kg)")
Graph:SetYLabel("Degrees/sec")
Graph:SetXRange(0,100000)
Graph:SetXSpacing(10000)
Graph:SetYSpacing(5)

HandCrankLbl.UpdateSim = function(Panel)
if TurretData.Ready == false then return end

local Info = TurretClass.CalcSpeed(TurretData,TurretClass.HandGear)

Panel:SetText(HandCrankText:format(math.Round(Info.MaxSlewRate,2),math.Round(Info.SlewAccel,4)))

local SimTurretData = {
LocalCoM = TurretData.LocalCoM,
RingSize = TurretData.RingSize,
RingHeight = TurretData.RingHeight,
Teeth = TurretData.Teeth,
Tilt = 1,
TurretClass = TurretData.TurretClass,
TotalMass = 0
}

local Points = {}

for I = 1, 101 do
local Mass = 1000 * (I - 1)
SimTurretData.TotalMass = Mass

Points[I] = {x = Mass, y = TurretClass.CalcSpeed(SimTurretData, TurretClass.HandGear).MaxSlewRate}
end

Graph:SetYRange(0, Points[1].y * 1.1)

Graph:Clear()
Graph:PlotTable("Slew Rate", Points, Color(65,65,200))

Graph:PlotPoint("Estimate", TurretData.TotalMass, Info.MaxSlewRate, Color(65,65,200))
end

RingSize:SetClientData("RingSize", "OnValueChanged")
Expand Down Expand Up @@ -179,7 +214,7 @@ do -- Turret ring
end

EstDist.OnValueChanged = function(_, Value)
TurretData.LocalCoM = Vector(Value,0,0)
TurretData.LocalCoM = Vector(Value,0,Value)

HandCrankLbl:UpdateSim()
end
Expand All @@ -194,7 +229,17 @@ do -- Turret ring
end

do -- Turret Motors
local TurretData = {Ready = false, Mass = 0, TurretType = "Turret-H", TurretTeeth = 0, MotorTeeth = 0, Torque = 0, Distance = 0}
local TurretData = {
Ready = false,
Mass = 0,
TurretType = "Turret-H",
TurretTeeth = 0,
MotorTeeth = 0,
Torque = 0,
Distance = 0,
HandSim = 0,
MotorSim = 0
}

local TorqText = "%GNm Torque"
local HandcrankText = "--HANDCRANK--\nMax Speed: %G deg/s\nAccel: %G deg/s^2"
Expand Down Expand Up @@ -234,28 +279,80 @@ do -- Turret Motors

local EstDist = TurretSim:AddSlider("Center of mass distance (gmu)", 0, 2, 2)

local Graph = Menu:AddGraph()
local GraphSize = Menu:GetParent():GetParent():GetWide()
Graph:SetSize(GraphSize, GraphSize / 2)
Graph:SetXLabel("Estimated Mass (kg)")
Graph:SetYLabel("Degrees/sec")
Graph:SetXRange(0,100000)
Graph:SetXSpacing(10000)
Graph:SetYSpacing(5)

Graph.Replot = function(self)
self:Clear()

local SimTurretData = {
LocalCoM = Vector(TurretData.Distance,0,TurretData.Distance),
RingSize = TurretData.Size,
RingHeight = TurretData.RingHeight,
Teeth = TurretData.TurretTeeth,
Tilt = 1,
TurretClass = TurretData.Type,
TotalMass = 0
}

local SimMotorData = {
Teeth = TurretData.MotorTeeth,
Speed = Data.Speed,
Torque = TurretData.Torque,
Efficiency = Data.Efficiency,
Accel = Data.Accel
}

local HandCrankPoints = {}
local MotorPoints = {}

for I = 1, 101 do
local Mass = 1000 * (I - 1)
SimTurretData.TotalMass = Mass

HandCrankPoints[I] = {x = Mass, y = TurretClass.CalcSpeed(SimTurretData, TurretClass.HandGear).MaxSlewRate}
MotorPoints[I] = {x = Mass, y = TurretClass.CalcSpeed(SimTurretData, SimMotorData).MaxSlewRate}
end

self:SetYRange(0, math.max(MotorPoints[1].y, HandCrankPoints[1].y) * 1.1)

self:PlotTable("Hand Rate", HandCrankPoints, Color(65,65,200))
self:PlotPoint("Hand Estimate", TurretData.Mass, TurretData.HandSim, Color(65,65,200))

self:PlotTable("Motor Rate", MotorPoints, Color(200,65,65))
self:PlotPoint("Motor Estimate", TurretData.Mass, TurretData.MotorSim, Color(200,65,65))
end

local HandcrankInfo = TurretSim:AddLabel(HandcrankText:format(0,0))
HandcrankInfo.UpdateSim = function(Panel)
if TurretData.Ready == false then return end

--local Info = TurretClass.CalcInfo({Mass = TurretData.Mass, Size = TurretData.Size, Teeth = TurretData.TurretTeeth, TurretClass = TurretData.Type, Distance = TurretData.Distance},TurretClass.HandGear)
local Info = TurretClass.CalcSpeed({Tilt = 1, TotalMass = TurretData.Mass, RingSize = TurretData.Size, Teeth = TurretData.TurretTeeth, TurretClass = TurretData.Type, LocalCoM = Vector(TurretData.Distance,0,0), RingHeight = TurretData.RingHeight},
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},
TurretClass.HandGear)

Panel:SetText(HandcrankText:format(math.Round(Info.MaxSlewRate,2),math.Round(Info.SlewAccel,4)))

TurretData.HandSim = Info.MaxSlewRate
Graph:Replot()
end

local MotorInfo = TurretSim:AddLabel(MotorText:format(0,0))
MotorInfo.UpdateSim = function(Panel)
if TurretData.Ready == false then return end

--local Info = TurretClass.CalcInfo({Mass = TurretData.Mass, Size = TurretData.Size, Teeth = TurretData.TurretTeeth, TurretClass = TurretData.Type, Distance = TurretData.Distance},
--{Teeth = TurretData.MotorTeeth, Speed = Data.Speed, Torque = TurretData.Torque, Efficiency = Data.Efficiency})

local Info = TurretClass.CalcSpeed({Tilt = 1, TotalMass = TurretData.Mass, RingSize = TurretData.Size, Teeth = TurretData.TurretTeeth, TurretClass = TurretData.Type, LocalCoM = Vector(TurretData.Distance,0,0), RingHeight = TurretData.RingHeight},
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},
{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)))

TurretData.MotorSim = Info.MaxSlewRate
Graph:Replot()
end

-- Updating functions
Expand Down Expand Up @@ -339,14 +436,6 @@ do -- Turret Motors
end

ACF.LoadSortedList(TurretType, Turrets.GetItemEntries("1-Turret"), "ID")

-- Calculator for turret speed
--[[
Should include data from the motor
Should output top speed, acceleration of turret
]]

end
end

Expand Down
113 changes: 113 additions & 0 deletions lua/acf/menu/items_cl/ammo_menu.lua
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,118 @@ local function AddInformation(Base, Settings, ToolData)
hook.Run("ACF_AddAmmoInformation", Base, ToolData, Ammo, BulletData)
end

local function AddGraph(Base, ToolData)
local Graph = Base:AddGraph()
Base.Graph = Graph
local MenuSizeX = Base:GetParent():GetParent():GetWide() -- Parent of the parent of this item should be the menu panel
Graph:SetSize(MenuSizeX, MenuSizeX * 0.5)

Graph:SetXRange(0,1000)
Graph:SetXLabel("Distance (m)")
Graph:SetYLabel("Pen (mm)")

Graph:SetXSpacing(100)
Graph:SetYSpacing(50)
Graph:SetFidelity(16)

Graph:TrackClientData("Projectile")
Graph:TrackClientData("Propellant")
Graph:TrackClientData("FillerRatio")
Graph:TrackClientData("LinerAngle")
Graph:TrackClientData("StandoffRatio")
Graph:TrackClientData("SmokeWPRatio")

Graph:DefineSetter(function(Panel)
Panel:Clear()

Panel:SetXLabel("Distance (m)")
Panel:SetFidelity(8)

Graph:SetXSpacing(100)
Graph:SetYSpacing(50)

local Ammo = AmmoTypes.Get(ToolData.AmmoType)

if ToolData.AmmoType == "HEAT" or ToolData.AmmoType == "HEATFS" then
local PassiveStandoffPen = Ammo:GetPenetration(BulletData, BulletData.Standoff)
local BreakupDistPen = Ammo:GetPenetration(BulletData, BulletData.BreakupDist)

Panel:SetYRange(0,math.max(BreakupDistPen, PassiveStandoffPen) * 1.5)
Panel:SetXRange(0,BulletData.BreakupDist * 1000 * 2.5) -- HEAT/HEATFS doesn't care how long the shell has been flying for penetration, just the instant it detonates
--Panel:SetXRange(0,60000)

Panel:SetXLabel("Standoff (mm)")

--Panel:PlotLimitLine("Passive", false, BulletData.Standoff * 1000, Color(65,65,200))
--Panel:PlotLimitLine("Breakup", false, BulletData.BreakupDist * 1000, Color(200,65,65))

Panel:PlotPoint("Passive", BulletData.Standoff * 1000, PassiveStandoffPen, Color(65,65,200))
Panel:PlotPoint("Breakup", BulletData.BreakupDist * 1000, BreakupDistPen, Color(200,65,65))

Panel:PlotFunction("mm Pen", Color(255,65,65), function(X)
return Ammo:GetPenetration(BulletData, X / 1000)
end)
elseif ToolData.AmmoType == "HE" then
Panel:SetYLabel("Blast Radius")
Panel:SetXLabel("")

Panel:SetYSpacing(10)

Panel:SetXRange(0,10)
Panel:SetYRange(0,BulletData.BlastRadius * 2)

Panel:PlotLimitLine("Blast Radius", true, BulletData.BlastRadius, Color(200,65,65))

Panel:PlotFunction("Blast Radius", Color(200,65,65), function(_)
return BulletData.BlastRadius
end)
elseif ToolData.AmmoType == "SM" then
Panel:SetYLabel("Smoke Radius (m)")
Panel:SetXLabel("Time (s)")

Panel:SetYSpacing(10)
Panel:SetXSpacing(5)

local WPTime = BulletData.WPLife or 0
local SFTime = BulletData.SMLife or 0

local MinWP = BulletData.WPRadiusMin or 0
local MaxWP = BulletData.WPRadiusMax or 0

local MinSF = BulletData.SMRadiusMin or 0
local MaxSF = BulletData.SMRadiusMax or 0

Panel:SetXRange(0,math.max(WPTime,SFTime) * 1.1)
Panel:SetYRange(0,math.max(MaxWP,MaxSF) * 1.1)

if WPTime > 0 then
Panel:PlotLimitFunction("WP Filler", 0, WPTime, Color(65,65,200), function(X)
return Lerp(X / WPTime, MinWP, MaxWP)
end)

Panel:PlotPoint("WP Max Radius", WPTime, MaxWP, Color(65,65,200))
end

if SFTime > 0 then
Panel:PlotLimitFunction("Smoke Filler", 0, SFTime, Color(200,65,65), function(X)
return Lerp(X / SFTime, MinSF, MaxSF)
end)

Panel:PlotPoint("SM Max Radius", SFTime, MaxSF, Color(200,65,65))
end
else
Panel:SetYRange(0,math.ceil(BulletData.MaxPen or 0) * 1.1)

Panel:PlotPoint("300m", 300, Ammo:GetRangedPenetration(BulletData, 300), Color(65,65,200))
Panel:PlotPoint("800m", 800, Ammo:GetRangedPenetration(BulletData, 800), Color(65,65,200))

Panel:PlotFunction("Pen", Color(255,65,65), function(X)
return Ammo:GetRangedPenetration(BulletData, X)
end)
end
end)
end

function ACF.GetCurrentAmmoData()
return BulletData
end
Expand All @@ -210,6 +322,7 @@ function ACF.UpdateAmmoMenu(Menu, Settings)
AddPreview(Base, Settings, ToolData)
AddControls(Base, Settings, ToolData)
AddInformation(Base, Settings, ToolData)
AddGraph(Base, ToolData)
end

Menu:EndTemporal(Base)
Expand Down
28 changes: 28 additions & 0 deletions lua/acf/menu/items_cl/engines.lua
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,16 @@ local function CreateMenu(Menu)
local EnginePreview = EngineBase:AddModelPreview(nil, true)
local EngineStats = EngineBase:AddLabel()

local PowerGraph = Menu:AddGraph()
local PGWidth = Menu:GetWide()
PowerGraph:SetSize(PGWidth,PGWidth / 2)

PowerGraph:SetXLabel("RPM")
PowerGraph:SetYLabel("x100")
PowerGraph:SetXSpacing(1000)
PowerGraph:SetYSpacing(100)
PowerGraph:SetFidelity(24)

Menu:AddTitle("Fuel Tank Settings")
local FuelType = Menu:AddComboBox()
local FuelClass = Menu:AddComboBox()
Expand Down Expand Up @@ -164,6 +174,24 @@ local function CreateMenu(Menu)

UpdateEngineStats(EngineStats, Data)

PowerGraph:SetXRange(0,Data.RPM.Limit)
PowerGraph:SetYRange(0,math.max(math.ceil(Data.PeakPower * 1.34), Data.Torque) * 1.1)
PowerGraph:SetFidelity(10)

PowerGraph:Clear()
PowerGraph:PlotPoint("Peak HP", Data.PeakPowerRPM, math.Round(Data.PeakPower * 1.34), Color(255,65,65))
PowerGraph:PlotPoint("Peak Nm", Data.PeakTqRPM, math.Round(Data.Torque), Color(65,65,255))

PowerGraph:PlotLimitFunction("Tq", Data.RPM.Idle, Data.RPM.Limit, Color(65,65,255), function(X)
return ACF.GetTorque(Data.TorqueCurve, math.Remap(X, Data.RPM.Idle, Data.RPM.Limit, 0, 1)) * Data.Torque
end)

PowerGraph:PlotLimitFunction("HP", Data.RPM.Idle, Data.RPM.Limit, Color(255,65,65), function(X)
return (ACF.GetTorque(Data.TorqueCurve, math.Remap(X, Data.RPM.Idle, Data.RPM.Limit, 0, 1)) * Data.Torque * X) * 1.34 / 9548.8
end)

PowerGraph:PlotLimitLine("Idle RPM", false, Data.RPM.Idle, Color(127,0,0))

ACF.LoadSortedList(FuelType, Data.Fuel, "ID")
end

Expand Down
Loading

0 comments on commit afda4b8

Please sign in to comment.