From d9b9e984f50d1417fe52d5f72bde819e6cf5b67d Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Wed, 12 Feb 2020 23:57:56 -0300 Subject: [PATCH 001/279] Added initial files for the new menu tool - Added ACF_Panel derma object. - Added ACF.AddOption and ACF.AddOptionItem functions to help populate the menu easily. - Added basic menu tool, has no functionality for the moment. --- lua/acf/client/cl_menu.lua | 173 +++++++++++++++++++++ lua/vgui/acf_panel.lua | 149 ++++++++++++++++++ lua/weapons/gmod_tool/stools/acf_menu2.lua | 55 +++++++ 3 files changed, 377 insertions(+) create mode 100644 lua/acf/client/cl_menu.lua create mode 100644 lua/vgui/acf_panel.lua create mode 100644 lua/weapons/gmod_tool/stools/acf_menu2.lua diff --git a/lua/acf/client/cl_menu.lua b/lua/acf/client/cl_menu.lua new file mode 100644 index 000000000..51df2486b --- /dev/null +++ b/lua/acf/client/cl_menu.lua @@ -0,0 +1,173 @@ +local Options = {} +local Lookup = {} +local Count = 0 + +do -- Menu population functions + local function DefaultAction(Panel) + Panel:AddTitle("There's nothing here.") + Panel:AddParagraph("This option is either a work in progress or something isn't working as intended.") + end + + function ACF.AddOption(Name, Icon) + if not Name then return end + + if not Lookup[Name] then + Count = Count + 1 + + Options[Count] = { + Name = Name, + Icon = "icon16/" .. (Icon or "plugin") .. ".png", + Lookup = {}, + List = {}, + Count = 0, + } + + Lookup[Name] = Options[Count] + else + local Option = Lookup[Name] + + Option.Icon = "icon16/" .. (Icon or "plugin") .. ".png" + end + end + + function ACF.AddOptionItem(Option, Name, Icon, Action) + if not Option then return end + if not Name then return end + if not Lookup[Option] then return end + + local Items = Lookup[Option] + local Item = Items.Lookup[Name] + + if not Item then + Items.Count = Items.Count + 1 + + Items.List[Items.Count] = { + Icon = "icon16/" .. (Icon or "plugin") .. ".png", + Action = Action or DefaultAction, + Name = Name, + } + + Items.Lookup[Name] = Items.List[Items.Count] + else + Item.Icon = "icon16/" .. (Icon or "plugin") .. ".png" + Item.Action = Action or DefaultAction + Item.Name = Name + end + end + + -- Small workaround to give the correct order to the items + ACF.AddOption("About the Addon", "information") + ACF.AddOptionItem("About the Addon", "Guidelines", "book_open") + ACF.AddOptionItem("About the Addon", "Updates", "newspaper") + ACF.AddOptionItem("About the Addon", "Contact Us", "feed") + + ACF.AddOption("Entities", "brick") + ACF.AddOptionItem("Entities", "Weapons", "gun") + ACF.AddOptionItem("Entities", "Missiles", "wand") + ACF.AddOptionItem("Entities", "Mobility", "car") + ACF.AddOptionItem("Entities", "Sensors", "transmit") + ACF.AddOptionItem("Entities", "Components", "cog") +end + +do -- ACF Menu context panel + local function PopulateTree(Tree) + local First + + Tree.BaseHeight = Count + 0.5 + + for _, Option in ipairs(Options) do + local Parent = Tree:AddNode(Option.Name, Option.Icon) + local SetExpanded = Parent.SetExpanded + + Parent.Action = Option.Action + Parent.Master = true + Parent.Count = Option.Count + Parent.SetExpanded = function(Panel, Bool) + if not Panel.AllowExpand then return end + + SetExpanded(Panel, Bool) + + Panel.AllowExpand = nil + end + + for _, Data in ipairs(Option.List) do + local Child = Parent:AddNode(Data.Name, Data.Icon) + + Child.Action = Data.Action + Child.Parent = Parent + + if not Parent.Selected then + Parent.Selected = Child + + if not First then + Tree:SetSelectedItem(Child) + First = true + end + end + end + end + end + + local function UpdateTree(Tree, Old, New) + local OldParent = Old and Old.Parent or Old + local NewParent = New.Parent or New + + if OldParent == NewParent then return end + + if OldParent then + OldParent.AllowExpand = true + OldParent:SetExpanded(false) + end + + NewParent.AllowExpand = true + NewParent:SetExpanded(true) + + Tree:SetHeight(Tree:GetLineHeight() * (Tree.BaseHeight + NewParent.Count)) + end + + function ACF.BuildContextPanel(Panel) + local Menu = ACF.Menu + + if not IsValid(Menu) then + ACF.Menu = vgui.Create("ACF_Panel", Panel) + + Menu = ACF.Menu + Menu.Panel = Panel + + Panel:AddItem(Menu) + else + Menu:Clear() + end + + local Reload = Menu:AddButton("Reload Menu") + Reload.DoClickInternal = function() + ACF.BuildContextPanel(Panel) + end + + Menu:AddTitle("Available Options") + + local Tree = Menu:AddPanel("DTree") + Tree.OnNodeSelected = function(_, Node) + if Tree.Selected == Node then return end + + if Node.Master then + Tree:SetSelectedItem(Node.Selected) + return + end + + UpdateTree(Tree, Tree.Selected, Node) + + Node.Parent.Selected = Node + Tree.Selected = Node + + Menu:ClearTemporal() + Menu:StartTemporal() + + Node.Action(Menu) + + Menu:EndTemporal() + end + + PopulateTree(Tree) + end +end diff --git a/lua/vgui/acf_panel.lua b/lua/vgui/acf_panel.lua new file mode 100644 index 000000000..8405144a3 --- /dev/null +++ b/lua/vgui/acf_panel.lua @@ -0,0 +1,149 @@ +local PANEL = {} + +DEFINE_BASECLASS("Panel") + +function PANEL:Init() + self.Items = {} + self.TempItems = {} +end + +function PANEL:Clear() + if not next(self.Items) then return end + + for K in pairs(self.Items) do + if IsValid(K) then + K:Remove() + end + + self.Items[K] = nil + end +end + +function PANEL:ClearTemporal(Panel) + local Target = IsValid(Panel) and Panel or self + + if not Target.TempItems then return end + + for K in pairs(Target.TempItems) do + if IsValid(K) then + K:Remove() + end + + Target.TempItems[K] = nil + end +end + +local TemporalPanels = {} + +function PANEL:StartTemporal(Panel) + local Target = IsValid(Panel) and Panel or self + + if not Target.TempItems then + Target.TempItems = {} + end + + TemporalPanels[Target] = true +end + +function PANEL:EndTemporal(Panel) + local Target = IsValid(Panel) and Panel or self + + TemporalPanels[Target] = nil +end + +function PANEL:AddPanel(Name) + if not Name then return end + + local Panel = vgui.Create(Name, self) + + if not IsValid(Panel) then return end + + Panel:Dock(TOP) + Panel:DockMargin(0, 0, 0, 10) + Panel:InvalidateLayout() + + self:InvalidateLayout() + self.Items[Panel] = true + + if next(TemporalPanels) then + for K in pairs(TemporalPanels) do + K.TempItems[Panel] = true + end + end + + return Panel +end + +function PANEL:AddButton(Text, Command, ...) + local Panel = self:AddPanel("DButton") + Panel:SetText(Text or "Button") + Panel:SetFont("ACF_Control") + + if Command then + Panel:SetConsoleCommand(Command, ...) + end + + return Panel +end + +function PANEL:AddTitle(Text) + local Panel = self:AddPanel("DLabel") + Panel:SetAutoStretchVertical(true) + Panel:SetText(Text or "Text") + Panel:SetFont("ACF_Title") + Panel:SetWrap(true) + Panel:SetDark(true) + + return Panel +end + +function PANEL:AddSubtitle(Text) + local Panel = self:AddTitle(Text) + Panel:SetFont("ACF_Subtitle") + + return Panel +end + +function PANEL:AddParagraph(Text) + local Panel = self:AddTitle(Text) + Panel:SetFont("ACF_Paragraph") + + return Panel +end + +function PANEL:AddHelp(Text) + local TextColor = self:GetSkin().Colours.Tree.Hover + local Panel = self:AddParagraph(Text) + Panel:DockMargin(32, 0, 32, 10) + Panel:SetTextColor(TextColor) + Panel:InvalidateLayout() + + return Panel +end + +function PANEL:AddComboBox() + local Panel = self:AddPanel("DComboBox") + Panel:SetFont("ACF_Control") + Panel:SetSortItems(false) + Panel:SetDark(true) + Panel:SetWrap(true) + + return Panel +end + +function PANEL:AddSlider(Title) + local Panel = self:AddPanel("DNumSlider") + Panel:SetText(Title or "") + Panel:SetDark(true) + + return Panel +end + +function PANEL:PerformLayout() + self:SizeToChildren(true, true) +end + +function PANEL:GenerateExample() +end + +derma.DefineControl("ACF_Panel", "", PANEL, "Panel") \ No newline at end of file diff --git a/lua/weapons/gmod_tool/stools/acf_menu2.lua b/lua/weapons/gmod_tool/stools/acf_menu2.lua new file mode 100644 index 000000000..a56876d18 --- /dev/null +++ b/lua/weapons/gmod_tool/stools/acf_menu2.lua @@ -0,0 +1,55 @@ +TOOL.Name = "ACF Menu Test" +TOOL.Category = "Construction" + +cleanup.Register("acfmenu") + +if CLIENT then + local DrawBoxes = CreateConVar("acf_drawboxes", 0, FCVAR_ARCHIVE, "Whether or not to draw hitboxes on ACF entities", 0, 1) + + language.Add("Tool.acf_menu2.name", "Armored Combat Framework") + language.Add("Tool.acf_menu2.desc", "Testing the new menu tool") + + function TOOL:DrawHUD() + if not DrawBoxes:GetBool() then return end + + local Ent = LocalPlayer():GetEyeTrace().Entity + + if not IsValid(Ent) then return end + if not Ent.HitBoxes then return end + + cam.Start3D() + render.SetColorMaterial() + + for _, Tab in pairs(Ent.HitBoxes) do + local BoxColor = Tab.Sensitive and Color(214, 160, 190, 50) or Color(160, 190, 215, 50) + + render.DrawBox(Ent:LocalToWorld(Tab.Pos), Ent:LocalToWorldAngles(Tab.Angle), Tab.Scale * -0.5, Tab.Scale * 0.5, BoxColor) + end + + cam.End3D() + end + + function TOOL:LeftClick(Trace) + return not Trace.HitSky + end + + function TOOL:RightClick(Trace) + return not Trace.HitSky + end + + TOOL.BuildCPanel = ACF.BuildContextPanel + + concommand.Add("acf_reload_menu", function() + if not IsValid(ACF.Menu) then return end + + ACF.BuildContextPanel(ACF.Menu.Panel) + end) +else + function TOOL:LeftClick(Trace) + return not Trace.HitSky + end + + function TOOL:RightClick(Trace) + return not Trace.HitSky + end +end From a981a5ca0d18aad9bf6cb3014cc6ef58df6b78a5 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sat, 15 Feb 2020 22:38:57 -0300 Subject: [PATCH 002/279] Added new weapon and weapon class registration functions - Added ACF.RegisterWeaponClass and ACF.RegisterWeapon functions to replace ACF_defineGunClass and ACF_defineGun respectively. - Weapon classes will be stored on the ACF.Classes.Weapons global table. --- lua/acf/base/sh_classes.lua | 63 ++++++++++++++++ lua/acf/shared/guns/autocannon.lua | 77 ++++++++++++++++++- lua/acf/shared/guns/autoloader.lua | 77 ++++++++++++++++++- lua/acf/shared/guns/cannon.lua | 94 +++++++++++++++++++++++- lua/acf/shared/guns/grenadelauncher.lua | 26 +++++++ lua/acf/shared/guns/heavymachinegun.lua | 82 ++++++++++++++++++++- lua/acf/shared/guns/howitzer.lua | 78 +++++++++++++++++++- lua/acf/shared/guns/machinegun.lua | 61 ++++++++++++++- lua/acf/shared/guns/mortar.lua | 79 +++++++++++++++++++- lua/acf/shared/guns/rotaryautocannon.lua | 90 +++++++++++++++++++++++ lua/acf/shared/guns/semiauto.lua | 93 ++++++++++++++++++++++- lua/acf/shared/guns/shortcannon.lua | 93 +++++++++++++++++++++++ lua/acf/shared/guns/smokelauncher.lua | 42 ++++++++++- 13 files changed, 946 insertions(+), 9 deletions(-) create mode 100644 lua/acf/base/sh_classes.lua diff --git a/lua/acf/base/sh_classes.lua b/lua/acf/base/sh_classes.lua new file mode 100644 index 000000000..c3ef37840 --- /dev/null +++ b/lua/acf/base/sh_classes.lua @@ -0,0 +1,63 @@ +do -- Weapon class registration functions + ACF.Classes.Weapons = ACF.Classes.Weapons or {} + + local Weapons = ACF.Classes.Weapons + + function ACF.RegisterWeaponClass(ID, Data) + if not ID then return end + if not Data then return end + + local Class = Weapons[ID] + + if not Class then + Class = { + ID = ID, + Lookup = {}, + Items = {}, + Count = 0, + } + + Weapons[ID] = Class + end + + for K, V in pairs(Data) do + Class[K] = V + end + + if Class.MuzzleFlash then + PrecacheParticleSystem(Class.MuzzleFlash) + end + end + + function ACF.RegisterWeapon(ID, ClassID, Data) + if not ID then return end + if not ClassID then return end + if not Data then return end + if not Weapons[ClassID] then return end + + local Class = Weapons[ClassID] + local Weapon = Class.Lookup[ID] + + if not Weapon then + Weapon = { + ID = ID, + Class = Class, + ClassID = ClassID, + EntClass = "acf_gun", + Type = "Weapons", + } + + Class.Count = Class.Count + 1 + Class.Items[Class.Count] = Weapon + Class.Lookup[ID] = Weapon + end + + for K, V in pairs(Data) do + Weapon[K] = V + end + + if Weapon.MuzzleFlash then + PrecacheParticleSystem(Weapon.MuzzleFlash) + end + end +end \ No newline at end of file diff --git a/lua/acf/shared/guns/autocannon.lua b/lua/acf/shared/guns/autocannon.lua index fbf44e913..ffb4cc0df 100644 --- a/lua/acf/shared/guns/autocannon.lua +++ b/lua/acf/shared/guns/autocannon.lua @@ -78,4 +78,79 @@ ACF_defineGun("50mmAC", { maxlength = 52, propweight = 1.2 } -}) \ No newline at end of file +}) + +ACF.RegisterWeaponClass("AC", { + Name = "Autocannon", + Description = "Autocannons have a rather high weight and bulk for the ammo they fire, but they can fire it extremely fast.", + MuzzleFlash = "auto_muzzleflash_noscale", + ROFMod = 0.85, + Spread = 0.12, + Sound = "weapons/ACF_Gun/ac_fire4.mp3", + soundDistance = " ", + soundNormal = " ", +}) + +ACF.RegisterWeapon("20mmAC", "AC", { + Name = "20mm Autocannon", + Description = "The 20mm autocannon is the smallest of the family; having a good rate of fire but a tiny shell.", + Model = "models/autocannon/autocannon_20mm.mdl", + Caliber = 20, + Mass = 225, + Year = 1930, + ROFMod = 0.7, + MagSize = 100, + MagReload = 3, + Round = { + MaxLength = 32, + PropMass = 0.13, + } +}) + +ACF.RegisterWeapon("30mmAC", "AC", { + Name = "30mm Autocannon", + Description = "The 30mm autocannon can fire shells with sufficient space for a small payload, and has modest anti-armor capability", + Model = "models/autocannon/autocannon_30mm.mdl", + Caliber = 30, + Mass = 960, + Year = 1935, + ROFMod = 0.5, + MagSize = 75, + MagReload = 3, + Round = { + MaxLength = 39, + PropMass = 0.350, + } +}) + +ACF.RegisterWeapon("40mmAC", "AC", { + Name = "40mm Autocannon", + Description = "The 40mm autocannon can fire shells with sufficient space for a useful payload, and can get decent penetration with proper rounds.", + Model = "models/autocannon/autocannon_40mm.mdl", + Caliber = 40, + Mass = 1500, + Year = 1940, + ROFMod = 0.48, + MagSize = 30, + MagReload = 3, + Round = { + MaxLength = 45, + PropMass = 0.9, + } +}) + +ACF.RegisterWeapon("50mmAC", "AC", { + Name = "50mm Autocannon", + Description = "The 50mm autocannon fires shells comparable with the 50mm Cannon, making it capable of destroying light armour quite quickly.", + Model = "models/autocannon/autocannon_50mm.mdl", + Caliber = 50, + Mass = 2130, + Year = 1965, + ROFMod = 0.4, + MagSize = 20, + MagReload = 3, + Round = { + MaxLength = 52, + PropMass = 1.2 + } +}) diff --git a/lua/acf/shared/guns/autoloader.lua b/lua/acf/shared/guns/autoloader.lua index 636e4b2ce..5fbd36caf 100644 --- a/lua/acf/shared/guns/autoloader.lua +++ b/lua/acf/shared/guns/autoloader.lua @@ -97,4 +97,79 @@ ACF_defineGun("170mmAL", { } } ) ]] --- \ No newline at end of file +-- + +ACF.RegisterWeaponClass("AL", { + Name = "Autoloader", + Description = "A cannon with attached autoloading mechanism. While it allows for several quick shots, the mechanism adds considerable bulk, weight, and magazine reload time.", + MuzzleFlash = "cannon_muzzleflash_noscale", + ROFMod = 0.64, + Spread = 0.08, + Sound = "weapons/ACF_Gun/autoloader.mp3", + soundDistance = "Cannon.Fire", + soundNormal = " ", +}) + +ACF.RegisterWeapon("75mmAL", "AL", { + Name = "75mm Autoloading Cannon", + Description = "A quick-firing 75mm gun, pops off a number of rounds in relatively short order.", + Model = "models/tankgun/tankgun_al_75mm.mdl", + Caliber = 75, + Mass = 1892, + Year = 1946, + ROFMod = 1, + MagSize = 8, + MagReload = 15, + Round = { + MaxLength = 78, + PropMass = 3.8, + } +}) + +ACF.RegisterWeapon("100mmAL", "AL", { + Name = "100mm Autoloading Cannon", + Description = "The 100mm is good for rapidly hitting medium armor, then running like your ass is on fire to reload.", + Model = "models/tankgun/tankgun_al_100mm.mdl", + Caliber = 100, + Mass = 3325, + Year = 1956, + ROFMod = 0.85, + MagSize = 6, + MagReload = 21, + Round = { + MaxLength = 93, + PropMass = 9.5, + } +}) + +ACF.RegisterWeapon("120mmAL", "AL", { + Name = "120mm Autoloading Cannon", + Description = "The 120mm autoloader can do serious damage before reloading, but the reload time is killer.", + Model = "models/tankgun/tankgun_al_120mm.mdl", + Caliber = 120, + Mass = 6050, + Year = 1956, + ROFMod = 0.757, + MagSize = 5, + MagReload = 27, + Round = { + MaxLength = 110, + PropMass = 18, + } +}) + +ACF.RegisterWeapon("140mmAL", "AL", { + Name = "140mm Autoloading Cannon", + Description = "The 140mm can shred a medium tank's armor with one magazine, and even function as shoot & scoot artillery, with its useful HE payload.", + Model = "models/tankgun/tankgun_al_140mm.mdl", + Caliber = 140, + Mass = 8830, + Year = 1970, + ROFMod = 0.743, + MagSize = 5, + MagReload = 35, + Round = { + MaxLength = 127, + PropMass = 28, + } +}) diff --git a/lua/acf/shared/guns/cannon.lua b/lua/acf/shared/guns/cannon.lua index 474d9936d..702005560 100644 --- a/lua/acf/shared/guns/cannon.lua +++ b/lua/acf/shared/guns/cannon.lua @@ -113,4 +113,96 @@ ACF_defineGun("170mmC", { } } ) ]] --- \ No newline at end of file +-- + +ACF.RegisterWeaponClass("C", { + Name = "Cannon", + Description = "High velocity guns that can fire very powerful ammunition, but are rather slow to reload.", + MuzzleFlash = "cannon_muzzleflash_noscale", + ROFMod = 2, + Spread = 0.08, + Sound = "weapons/ACF_Gun/cannon_new.mp3", + soundDistance = "Cannon.Fire", + soundNormal = " ", +}) + +ACF.RegisterWeapon("37mmC", "C", { + Name = "37mm Cannon", + Description = "A light and fairly weak cannon with good accuracy.", + Model = "models/tankgun/tankgun_37mm.mdl", + Caliber = 37, + Mass = 350, + Year = 1919, + ROFMod = 1.4, + Sound = "weapons/ACF_Gun/ac_fire4.mp3", + Round = { + MaxLength = 48, + PropMass = 1.125, + } +}) + +ACF.RegisterWeapon("50mmC", "C", { + Name = "50mm Cannon", + Description = "The 50mm is surprisingly fast-firing, with good effectiveness against light armor, but a pea-shooter compared to its bigger cousins", + Model = "models/tankgun/tankgun_50mm.mdl", + Caliber = 50, + Mass = 665, + Year = 1935, + Sound = "weapons/ACF_Gun/ac_fire4.mp3", + Round = { + MaxLength = 63, + PropMass = 2.1, + } +}) + +ACF.RegisterWeapon("75mmC", "C", { + Name = "75mm Cannon", + Description = "The 75mm is still rather respectable in rate of fire, but has only modest payload. Often found on the Eastern Front, and on cold war light tanks.", + Model = "models/tankgun/tankgun_75mm.mdl", + Caliber = 75, + Mass = 1420, + Year = 1942, + Round = { + MaxLength = 78, + PropMass = 3.8, + } +}) + +ACF.RegisterWeapon("100mmC", "C", { + Name = "100mm Cannon", + Description = "The 100mm was a benchmark for the early cold war period, and has great muzzle velocity and hitting power, while still boasting a respectable, if small, payload.", + Model = "models/tankgun/tankgun_100mm.mdl", + Caliber = 100, + Mass = 2750, + Year = 1944, + Round = { + MaxLength = 93, + PropMass = 9.5, + } +}) + +ACF.RegisterWeapon("120mmC", "C", { + Name = "120mm Cannon", + Description = "Often found in MBTs, the 120mm shreds lighter armor with utter impunity, and is formidable against even the big boys.", + Model = "models/tankgun/tankgun_120mm.mdl", + Caliber = 120, + Mass = 5200, + Year = 1955, + Round = { + MaxLength = 110, + PropMass = 18, + } +}) + +ACF.RegisterWeapon("140mmC", "C", { + Name = "140mm Cannon", + Description = "The 140mm fires a massive shell with enormous penetrative capability, but has a glacial reload speed and a very hefty weight.", + Model = "models/tankgun/tankgun_140mm.mdl", + Caliber = 140, + Mass = 8180, + Year = 1990, + Round = { + MaxLength = 127, + PropMass = 28, + } +}) \ No newline at end of file diff --git a/lua/acf/shared/guns/grenadelauncher.lua b/lua/acf/shared/guns/grenadelauncher.lua index 193219150..4fa1e394e 100644 --- a/lua/acf/shared/guns/grenadelauncher.lua +++ b/lua/acf/shared/guns/grenadelauncher.lua @@ -26,3 +26,29 @@ ACF_defineGun("40mmGL", { --id propweight = 0.01 } } ) + +ACF.RegisterWeaponClass("GL", { + Name = "Grenade Launcher", + Description = "Grenade Launchers can fire shells with relatively large payloads at a fast rate, but with very limited velocities and poor accuracy.", + MuzzleFlash = "gl_muzzleflash_noscale", + ROFMod = 1, + Spread = 0.32, + Sound = "weapons/acf_gun/grenadelauncher.mp3", + soundDistance = " ", + soundNormal = " ", +}) + +ACF.RegisterWeapon("40mmGL", "GL", { + Name = "40mm Grenade Launcher", + Description = "The 40mm chews up infantry but is about as useful as tits on a nun for fighting armor. Often found on 4x4s rolling through the third world.", + Model = "models/launcher/40mmgl.mdl", + Caliber = 40, + Mass = 55, + Year = 1970, + MagSize = 6, + MagReload = 7.5, + Round = { + MaxLength = 7.5, + PropMass = 0.01, + } +}) diff --git a/lua/acf/shared/guns/heavymachinegun.lua b/lua/acf/shared/guns/heavymachinegun.lua index 7da7edc3d..45e35f63b 100644 --- a/lua/acf/shared/guns/heavymachinegun.lua +++ b/lua/acf/shared/guns/heavymachinegun.lua @@ -82,4 +82,84 @@ ACF_defineGun("40mmHMG", { maxlength = 42, propweight = 0.9 } -}) \ No newline at end of file +}) + +ACF.RegisterWeaponClass("HMG", { + Name = "Heavy Machinegun", + Description = "Designed as autocannons for aircraft, HMGs are rapid firing, lightweight, and compact but sacrifice accuracy, magazine size, and reload times.", + MuzzleFlash = "mg_muzzleflash_noscale", + ROFMod = 0.14, + Spread = 0.4, + Sound = "weapons/ACF_Gun/mg_fire3.mp3", + soundDistance = " ", + soundNormal = " ", + LongBarrel = { + Index = 2, + Submodel = 4, + NewPos = "muzzle2", + } +}) + +ACF.RegisterWeapon("13mmHMG", "HMG", { + Name = "13mm Heavy Machinegun", + Description = "The lightest of the HMGs, the 13mm has a rapid fire rate but suffers from poor payload size. Often used to strafe ground troops or annoy low-flying aircraft.", + Model = "models/machinegun/machinegun_20mm.mdl", + Caliber = 13, + Mass = 90, + Year = 1935, + ROFMod = 3.3, + MagSize = 35, + MagReload = 6, + Round = { + MaxLength = 22, + PropMass = 0.09, + } +}) + +ACF.RegisterWeapon("20mmHMG", "HMG", { + Name = "20mm Heavy Machinegun", + Description = "The 20mm has a rapid fire rate but suffers from poor payload size. Often used to strafe ground troops or annoy low-flying aircraft.", + Model = "models/machinegun/machinegun_20mm_compact.mdl", + Caliber = 20, + Mass = 160, + Year = 1935, + ROFMod = 1.9, + MagSize = 30, + MagReload = 6, + Round = { + MaxLength = 30, + PropMass = 0.12, + } +}) + +ACF.RegisterWeapon("30mmHMG", "HMG", { + Name = "30mm Heavy Machinegun", + Description = "30mm shell chucker, light and compact. Your average cold war dogfight go-to.", + Model = "models/machinegun/machinegun_30mm_compact.mdl", + Caliber = 30, + Mass = 480, + Year = 1941, + ROFMod = 1.1, + MagSize = 25, + MagReload = 6, + Round = { + MaxLength = 37, + PropMass = 0.35, + } +}) + +ACF.RegisterWeapon("40mmHMG", "HMG", { + Name = "40mm Heavy Machinegun", + Description = "The heaviest of the heavy machineguns. Massively powerful with a killer reload and hefty ammunition requirements, it can pop even relatively heavy targets with ease.", + Model = "models/machinegun/machinegun_40mm_compact.mdl", + Caliber = 40, + Mass = 780, + Year = 1955, + ROFMod = 0.95, + MagSize = 20, + MagReload = 8, + Round = { + MaxLength = 42, + PropMass = 0.9, + } +}) diff --git a/lua/acf/shared/guns/howitzer.lua b/lua/acf/shared/guns/howitzer.lua index c0878768c..7b806083b 100644 --- a/lua/acf/shared/guns/howitzer.lua +++ b/lua/acf/shared/guns/howitzer.lua @@ -110,4 +110,80 @@ ACF_defineGun("290mmHW", { } } ) ]] --- \ No newline at end of file +-- + +ACF.RegisterWeaponClass("HW", { + Name = "Howitzer", + Description = "Howitzers are limited to rather mediocre muzzle velocities, but can fire extremely heavy projectiles with large useful payload capacities.", + MuzzleFlash = "howie_muzzleflash_noscale", + ROFMod = 1.8, + Spread = 0.12, + Sound = "weapons/ACF_Gun/howitzer_new2.mp3", + soundDistance = "Howitzer.Fire", + soundNormal = " ", +}) + +ACF.RegisterWeapon("75mmHW", "HW", { + Name = "75mm Howitzer", + Description = "Often found being towed by large smelly animals, the 75mm has a high rate of fire, and is surprisingly lethal against light armor. Great for a sustained barrage against someone you really don't like.", + Model = "models/howitzer/howitzer_75mm.mdl", + Caliber = 75, + Mass = 530, + Year = 1900, + Round = { + MaxLength = 60, + PropMass = 1.8, + } +}) + +ACF.RegisterWeapon("105mmHW", "HW", { + Name = "105mm Howitzer", + Description = "The 105 lobs a big shell far, and its HEAT rounds can be extremely effective against even heavier armor.", + Model = "models/howitzer/howitzer_105mm.mdl", + Caliber = 105, + Mass = 1480, + Year = 1900, + Round = { + MaxLength = 86, + PropMass = 3.75, + } +}) + +ACF.RegisterWeapon("122mmHW", "HW", { + Name = "122mm Howitzer", + Description = "The 122mm bridges the gap between the 105 and the 155, providing a lethal round with a big splash radius.", + Model = "models/howitzer/howitzer_122mm.mdl", + Caliber = 122, + Mass = 3420, + Year = 1900, + Round = { + MaxLength = 106, + PropMass = 7, + } +}) + +ACF.RegisterWeapon("155mmHW", "HW", { + Name = "155mm Howitzer", + Description = "The 155 is a classic heavy artillery round, with good reason. A versatile weapon, it's found on most modern SPGs.", + Model = "models/howitzer/howitzer_155mm.mdl", + Caliber = 155, + Mass = 5340, + Year = 1900, + Round = { + MaxLength = 124, + PropMass = 13.5, + } +}) + +ACF.RegisterWeapon("203mmHW", "HW", { + Name = "203mm Howitzer", + Description = "An 8-inch deck gun, found on siege artillery and cruisers.", + Model = "models/howitzer/howitzer_203mm.mdl", + Caliber = 203, + Mass = 10280, + Year = 1900, + Round = { + MaxLength = 162.4, + PropMass = 28.5, + } +}) diff --git a/lua/acf/shared/guns/machinegun.lua b/lua/acf/shared/guns/machinegun.lua index 2e1997121..e48e23c31 100644 --- a/lua/acf/shared/guns/machinegun.lua +++ b/lua/acf/shared/guns/machinegun.lua @@ -80,4 +80,63 @@ ACF_defineGun("14.5mmMG", { --maxlength = 22, --propweight = 0.09 --} ---} ) \ No newline at end of file +--} ) + +ACF.RegisterWeaponClass("MG", { + Name = "Machinegun", + Description = "Machineguns are light guns that fire equally light bullets at a fast rate.", + MuzzleFlash = "mg_muzzleflash_noscale", + ROFMod = 0.9, + Spread = 0.24, + Sound = "weapons/ACF_Gun/mg_fire4.mp3", + soundNormal = "weapons/ACF_Gun/mg_fire4.mp3", + soundDistance = "", +}) + +ACF.RegisterWeapon("7.62mmMG", "MG", { + Name = "7.62mm Machinegun", + Description = "The 7.62mm is effective against infantry, but its usefulness against armor is laughable at best.", + Model = "models/machinegun/machinegun_762mm.mdl", + Caliber = 7.62, + Mass = 15, + Year = 1930, + ROFMod = 1.59, + MagSize = 250, + MagReload = 6, + Round = { + MaxLength = 13, + PropMass = 0.04, + } +}) + +ACF.RegisterWeapon("12.7mmMG", "MG", { + Name = "12.7mm Machinegun", + Description = "The 12.7mm MG is still light, finding its way into a lot of mountings, including on top of tanks.", + Model = "models/machinegun/machinegun_127mm.mdl", + Caliber = 12.7, + Mass = 30, + Year = 1910, + ROFMod = 1, + MagSize = 150, + MagReload = 6, + Round = { + MaxLength = 15.8, + PropMass = 0.03, + } +}) + +ACF.RegisterWeapon("14.5mmMG", "MG", { + Name = "14.5mm Machinegun", + Description = "The 14.5mm MG trades its smaller stablemates' rate of fire for more armor penetration and damage.", + Model = "models/machinegun/machinegun_145mm.mdl", + Caliber = 14.5, + Mass = 45, + Year = 1932, + ROFMod = 1, + MagSize = 90, + MagReload = 5, + Round = { + MaxLength = 19.5, + PropMass = 0.04, + } +}) diff --git a/lua/acf/shared/guns/mortar.lua b/lua/acf/shared/guns/mortar.lua index 32ac776aa..066ca3cd5 100644 --- a/lua/acf/shared/guns/mortar.lua +++ b/lua/acf/shared/guns/mortar.lua @@ -97,4 +97,81 @@ ACF_defineGun("280mmM", { } } ) ]] --- \ No newline at end of file +-- + +ACF.RegisterWeaponClass("MO", { + Name = "Mortar", + Description = "Mortars are able to fire shells with usefull payloads from a light weight gun, at the price of limited velocities.", + MuzzleFlash = "mortar_muzzleflash_noscale", + ROFMod = 2.5, + Spread = 0.64, + Sound = "weapons/ACF_Gun/mortar_new.mp3", + soundDistance = "Mortar.Fire", + soundNormal = " ", +}) + +ACF.RegisterWeapon("60mmM", "MO", { + Name = "60mm Mortar", + Description = "The 60mm is a common light infantry support weapon, with a high rate of fire but a puny payload.", + Model = "models/mortar/mortar_60mm.mdl", + Caliber = 60, + Mass = 60, + Year = 1930, + ROFMod = 1.25, + Round = { + MaxLength = 20, + PropMass = 0.037, + } +}) + +ACF.RegisterWeapon("80mmM", "MO", { + Name = "80mm Mortar", + Description = "The 80mm is a common infantry support weapon, with a good bit more boom than its little cousin.", + Model = "models/mortar/mortar_80mm.mdl", + Caliber = 80, + Mass = 120, + Year = 1930, + Round = { + MaxLength = 28, + PropMass = 0.055, + } +}) + +ACF.RegisterWeapon("120mmM", "MO", { + Name = "120mm Mortar", + Description = "The versatile 120 is sometimes vehicle-mounted to provide quick boomsplat to support the infantry. Carries more boom in its boomsplat, has good HEAT performance, and is more accurate in high-angle firing.", + Model = "models/mortar/mortar_120mm.mdl", + Caliber = 120, + Mass = 640, + Year = 1935, + Round = { + MaxLength = 45, + PropMass = 0.175, + } +}) + +ACF.RegisterWeapon("150mmM", "MO", { + Name = "150mm Mortar", + Description = "The perfect balance between the 120mm and the 200mm. Can prove a worthy main gun weapon, as well as a mighty good mortar emplacement", + Model = "models/mortar/mortar_150mm.mdl", + Caliber = 150, + Mass = 1255, + Year = 1945, + Round = { + MaxLength = 58, + PropMass = 0.235, + } +}) + +ACF.RegisterWeapon("200mmM", "MO", { + Name = "200mm Mortar", + Description = "The 200mm is a beast, often used against fortifications. Though enormously powerful, feel free to take a nap while it reloads", + Model = "models/mortar/mortar_200mm.mdl", + Caliber = 200, + Mass = 2850, + Year = 1940, + Round = { + MaxLength = 80, + PropMass = 0.330, + } +}) diff --git a/lua/acf/shared/guns/rotaryautocannon.lua b/lua/acf/shared/guns/rotaryautocannon.lua index 570158163..7c2f1c623 100644 --- a/lua/acf/shared/guns/rotaryautocannon.lua +++ b/lua/acf/shared/guns/rotaryautocannon.lua @@ -97,3 +97,93 @@ ACF_defineGun("30mmHRAC", { } } ) +ACF.RegisterWeaponClass("RAC", { + Name = "Rotary Autocannon", + Description = "Rotary Autocannons sacrifice weight, bulk and accuracy over classic autocannons to get the highest rate of fire possible.", + MuzzleFlash = "mg_muzzleflash_noscale", + ROFMod = 0.07, + Spread = 0.4, + Sound = "weapons/acf_gun/mg_fire3.mp3", + soundDistance = " ", + soundNormal = " ", +}) + +ACF.RegisterWeapon("14.5mmRAC", "RAC", { + Name = "14.5mm Rotary Autocannon", + Description = "A lightweight rotary autocannon, used primarily against infantry and light vehicles. It has a lower firerate than its larger brethren, but a significantly quicker cooldown period as well.", + Model = "models/rotarycannon/kw/14_5mmrac.mdl", + Caliber = 14.5, + Mass = 240, + Year = 1962, + ROFMod = 5.4, + MagSize = 60, + MagReload = 6, + Round = { + MaxLength = 25, + PropMass = 0.06, + } +}) + +ACF.RegisterWeapon("20mmRAC", "RAC", { + Name = "20mm Rotary Autocannon", + Description = "The 20mm is able to chew up light armor with decent penetration or put up a big flak screen. Typically mounted on ground attack aircraft, SPAAGs and the ocassional APC. Suffers from a moderate cooldown period between bursts to avoid overheating the barrels.", + Model = "models/rotarycannon/kw/20mmrac.mdl", + Caliber = 20, + Mass = 760, + Year = 1965, + ROFMod = 2.1, + MagSize = 40, + MagReload = 7, + Round = { + MaxLength = 30, + PropMass = 0.12, + } +}) + +ACF.RegisterWeapon("30mmRAC", "RAC", { + Name = "30mm Rotary Autocannon", + Description = "The 30mm is the bane of ground-attack aircraft, able to tear up light armor without giving one single fuck. Also seen in the skies above dead T-72s. Has a moderate cooldown period between bursts to avoid overheating the barrels.", + Model = "models/rotarycannon/kw/30mmrac.mdl", + Caliber = 30, + Mass = 1500, + Year = 1975, + ROFMod = 1, + MagSize = 40, + MagReload = 8, + Round = { + MaxLength = 40, + PropMass = 0.350, + } +}) + +ACF.RegisterWeapon("20mmHRAC", "RAC", { + Name = "20mm Heavy Rotary Autocannon", + Description = "A reinforced, heavy-duty 20mm rotary autocannon, able to fire heavier rounds with a larger magazine. Phalanx.", + Model = "models/rotarycannon/kw/20mmrac.mdl", + Caliber = 20, + Mass = 1200, + Year = 1981, + ROFMod = 2.5, + MagSize = 60, + MagReload = 4, + Round = { + MaxLength = 36, + PropMass = 0.12, + } +}) + +ACF.RegisterWeapon("30mmHRAC", "RAC", { + Name = "30mm Heavy Rotary Autocannon", + Description = "A reinforced, heavy duty 30mm rotary autocannon, able to fire heavier rounds with a larger magazine. Keeper of goals.", + Model = "models/rotarycannon/kw/30mmrac.mdl", + Caliber = 30, + Mass = 2850, + Year = 1985, + ROFMod = 1.2, + MagSize = 50, + MagReload = 6, + Round = { + MaxLength = 45, + PropMass = 0.350, + } +}) \ No newline at end of file diff --git a/lua/acf/shared/guns/semiauto.lua b/lua/acf/shared/guns/semiauto.lua index 2e2baa0ac..248b2a85e 100644 --- a/lua/acf/shared/guns/semiauto.lua +++ b/lua/acf/shared/guns/semiauto.lua @@ -95,4 +95,95 @@ ACF_defineGun("76mmSA", { maxlength = 70, propweight = 4.75 } -}) \ No newline at end of file +}) + +ACF.RegisterWeaponClass("SA", { + Name = "Semiautomatic Cannon", + Description = "Semiautomatic cannons offer better payloads than autocannons and less weight at the cost of rate of fire.", + MuzzleFlash = "semi_muzzleflash_noscale", + ROFMod = 0.36, + Spread = 0.1, + Sound = "weapons/acf_gun/sa_fire1.mp3", + soundDistance = " ", + soundNormal = " ", +}) + +ACF.RegisterWeapon("25mmSA", "SA", { + Name = "25mm Semiautomatic Cannon", + Description = "The 25mm semiauto can quickly put five rounds downrange, being lethal, yet light.", + Model = "models/autocannon/semiautocannon_25mm.mdl", + Caliber = 25, + Mass = 200, + Year = 1935, + ROFMod = 0.7, + MagSize = 5, + MagReload = 2, + Round = { + MaxLength = 39, + PropMass = 0.5, + } +}) + +ACF.RegisterWeapon("37mmSA", "SA", { + Name = "37mm Semiautomatic Cannon", + Description = "The 37mm is surprisingly powerful, its five-round clips boasting a respectable payload and a high muzzle velocity.", + Model = "models/autocannon/semiautocannon_37mm.mdl", + Caliber = 37, + Mass = 540, + Year = 1940, + ROFMod = 0.7, + MagSize = 5, + MagReload = 3.5, + Round = { + MaxLength = 42, + PropMass = 1.125, + } +}) + +ACF.RegisterWeapon("45mmSA", "SA", { + Name = "45mm Semiautomatic Cannon", + Description = "The 45mm can easily shred light armor, with a respectable rate of fire, but its armor penetration pales in comparison to regular cannons.", + Model = "models/autocannon/semiautocannon_45mm.mdl", + Caliber = 45, + Mass = 870, + Year = 1965, + ROFMod = 0.72, + MagSize = 5, + MagReload = 4, + Round = { + MaxLength = 52, + PropMass = 1.8, + } +}) + +ACF.RegisterWeapon("57mmSA", "SA", { + Name = "57mm Semiautomatic Cannon", + Description = "The 57mm is a respectable light armament, offering considerable penetration and moderate fire rate.", + Model = "models/autocannon/semiautocannon_57mm.mdl", + Caliber = 57, + Mass = 1560, + Year = 1965, + ROFMod = 0.8, + MagSize = 5, + MagReload = 4.5, + Round = { + MaxLength = 62, + PropMass = 2, + } +}) + +ACF.RegisterWeapon("76mmSA", "SA", { + Name = "76mm Semiautomatic Cannon", + Description = "The 76mm semiauto is a fearsome weapon, able to put five 76mm rounds downrange in 8 seconds.", + Model = "models/autocannon/semiautocannon_76mm.mdl", + Caliber = 76.2, + Mass = 2990, + Year = 1984, + ROFMod = 0.85, + MagSize = 5, + MagReload = 5, + Round = { + MaxLength = 70, + PropMass = 4.75, + } +}) diff --git a/lua/acf/shared/guns/shortcannon.lua b/lua/acf/shared/guns/shortcannon.lua index 62aabbc24..1b6fb9603 100644 --- a/lua/acf/shared/guns/shortcannon.lua +++ b/lua/acf/shared/guns/shortcannon.lua @@ -98,3 +98,96 @@ ACF_defineGun("140mmSC", { propweight = 12.8 } } ) + +ACF.RegisterWeaponClass("SC", { + Name = "Short-Barrel Cannon", + Description = "Short cannons trade muzzle velocity and accuracy for lighter weight and smaller size, with more penetration than howitzers and lighter than cannons.", + MuzzleFlash = "cannon_muzzleflash_noscale", + ROFMod = 1.7, + Spread = 0.2, + Sound = "weapons/ACF_Gun/cannon_new.mp3", + soundDistance = "Cannon.Fire", + soundNormal = " ", +}) + +ACF.RegisterWeapon("37mmSC", "SC", { + Name = "37mm Short Cannon", + Description = "Quick-firing and light, but penetration is laughable. You're better off throwing rocks.", + Model = "models/tankgun/tankgun_short_37mm.mdl", + Caliber = 37, + Mass = 200, + ROFMod = 1.4, + Year = 1915, + Sound = "weapons/ACF_Gun/ac_fire4.mp3", + Round = { + MaxLength = 45, + PropMass = 0.29, + } +}) + +ACF.RegisterWeapon("50mmSC", "SC", { + Name = "50mm Short Cannon", + Description = "The 50mm is a quick-firing pea-shooter, good for scouts, and common on old interwar tanks.", + Model = "models/tankgun/tankgun_short_50mm.mdl", + Caliber = 50, + Mass = 330, + ROFMod = 1.4, + Year = 1915, + Sound = "weapons/ACF_Gun/ac_fire4.mp3", + Round = { + MaxLength = 63, + PropMass = 0.6, + } +}) + +ACF.RegisterWeapon("75mmSC", "SC", { + Name = "75mm Short Cannon", + Description = "The 75mm is common WW2 medium tank armament, and still useful in many other applications.", + Model = "models/tankgun/tankgun_short_75mm.mdl", + Caliber = 75, + Mass = 750, + Year = 1936, + Round = { + MaxLength = 76, + PropMass = 2, + } +}) + +ACF.RegisterWeapon("100mmSC", "SC", { + Name = "100mm Short Cannon", + Description = "The 100mm is an effective infantry-support or antitank weapon, with a lot of uses and surprising lethality.", + Model = "models/tankgun/tankgun_short_100mm.mdl", + Caliber = 100, + Mass = 1750, + Year = 1940, + Round = { + MaxLength = 93, + PropMass = 4.5, + } +}) + +ACF.RegisterWeapon("120mmSC", "SC", { + Name = "120mm Short Cannon", + Description = "The 120mm is a formidable yet lightweight weapon, with excellent performance against larger vehicles.", + Model = "models/tankgun/tankgun_short_120mm.mdl", + Caliber = 120, + Mass = 3800, + Year = 1944, + Round = { + MaxLength = 110, + PropMass = 8.5, + } +}) + +ACF.RegisterWeapon("140mmSC", "SC", { + Name = "140mm Short Cannon", + Description = "A specialized weapon, developed from dark magic and anti-heavy tank hatred. Deal with it.", + Model = "models/tankgun/tankgun_short_140mm.mdl", + Caliber = 140, + Mass = 6040, + Year = 1999, + Round = { + MaxLength = 127, + PropMass = 12.8, + } +}) diff --git a/lua/acf/shared/guns/smokelauncher.lua b/lua/acf/shared/guns/smokelauncher.lua index 0a34deeb5..92a2e327b 100644 --- a/lua/acf/shared/guns/smokelauncher.lua +++ b/lua/acf/shared/guns/smokelauncher.lua @@ -45,4 +45,44 @@ ACF_defineGun("40mmCL", { maxlength = 12, propweight = 0.001 } -}) \ No newline at end of file +}) + +ACF.RegisterWeaponClass("SL", { + Name = "Smoke Launcher", + Description = "Smoke launcher to block an attacker's line of sight.", + MuzzleFlash = "gl_muzzleflash_noscale", + ROFMod = 45, + Spread = 0.32, + Sound = "weapons/acf_gun/smoke_launch.mp3", + soundDistance = "Mortar.Fire", + soundNormal = " ", +}) + +ACF.RegisterWeapon("40mmSL", "SL", { + Name = "40mm Smoke Launcher", + Description = "", + Model = "models/launcher/40mmsl.mdl", + Caliber = 40, + Mass = 1, + Year = 1941, + Round = { + MaxLength = 17.5, + PropMass = 0.000075, + } +}) + +ACF.RegisterWeapon("40mmCL", "SL", { + Name = "40mm Countermeasure Launcher", + Description = "A revolver-style launcher capable of firing off several smoke or flare rounds.", + Model = "models/launcher/40mmgl.mdl", + Caliber = 40, + Mass = 20, + ROFMod = 0.015, + Year = 1950, + MagSize = 6, + MagReload = 40, + Round = { + MaxLength = 12, + PropMass = 0.001, + } +}) From 94820229e984347adc112ac8232af86c299f6522 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sat, 15 Feb 2020 22:43:16 -0300 Subject: [PATCH 003/279] Added tool data functions - Clientside: Added ACF.WriteValue and ACF.Read[Bool/Number/String] functions to secure tool information and replace tool convars. - Clientside: Added PANEL:SetDataVariable and PANEL:ClearDataVariable to allow panels to control tool data variables. - Serverside: Added ACF.Read[Bool/Number/String] functions to retrieve tool data variables from the players on the server. --- lua/acf/base/util/cl_util.lua | 248 +++++++++++++++++++++++++--------- lua/acf/base/util/sv_util.lua | 141 +++++++++++++------ 2 files changed, 285 insertions(+), 104 deletions(-) diff --git a/lua/acf/base/util/cl_util.lua b/lua/acf/base/util/cl_util.lua index acd023173..cd73fe391 100644 --- a/lua/acf/base/util/cl_util.lua +++ b/lua/acf/base/util/cl_util.lua @@ -1,71 +1,195 @@ - -local Types = { - Normal = { - Prefix = "", - Color = Color(80, 255, 80) - }, - Info = { - Prefix = " - Info", - Color = Color(0, 233, 255) - }, - Warning = { - Prefix = " - Warning", - Color = Color(255, 160, 0) - }, - Error = { - Prefix = " - Error", - Color = Color(255, 80, 80) +do -- Clientside chat messages + local Types = { + Normal = { + Prefix = "", + Color = Color(80, 255, 80) + }, + Info = { + Prefix = " - Info", + Color = Color(0, 233, 255) + }, + Warning = { + Prefix = " - Warning", + Color = Color(255, 160, 0) + }, + Error = { + Prefix = " - Error", + Color = Color(255, 80, 80) + } } -} -function ACF.AddMessageType(Name, Prefix, TitleColor) - if not Name then return end + function ACF.AddMessageType(Name, Prefix, TitleColor) + if not Name then return end - Types[Name] = { - Prefix = Prefix and (" - " .. Prefix) or "", - Color = TitleColor or Color(80, 255, 80), - } + Types[Name] = { + Prefix = Prefix and (" - " .. Prefix) or "", + Color = TitleColor or Color(80, 255, 80), + } + end + + local function PrintToChat(Type, ...) + if not ... then return end + + local Data = Types[Type] or Types.Normal + local Prefix = "[ACF" .. Data.Prefix .. "] " + local Message = istable(...) and ... or { ... } + + chat.AddText(Data.Color, Prefix, color_white, unpack(Message)) + end + + ACF.PrintToChat = PrintToChat + + net.Receive("ACF_ChatMessage", function() + local Type = net.ReadString() + local Message = net.ReadTable() + + PrintToChat(Type, Message) + end) end -local function PrintToChat(Type, ...) - if not ... then return end +do -- Custom fonts + surface.CreateFont("ACF_Title", { + font = "Roboto", + size = 22, + weight = 850, + }) + + surface.CreateFont("ACF_Subtitle", { + font = "Roboto", + size = 18, + weight = 850, + }) - local Data = Types[Type] or Types.Normal - local Prefix = "[ACF" .. Data.Prefix .. "] " - local Message = istable(...) and ... or { ... } + surface.CreateFont("ACF_Paragraph", { + font = "Roboto", + size = 14, + weight = 650, + }) - chat.AddText(Data.Color, Prefix, color_white, unpack(Message)) + surface.CreateFont("ACF_Control", { + font = "Roboto", + size = 14, + weight = 550, + }) end -ACF.PrintToChat = PrintToChat - -net.Receive("ACF_ChatMessage", function() - local Type = net.ReadString() - local Message = net.ReadTable() - - PrintToChat(Type, Message) -end) - -surface.CreateFont("ACF_Title", { - font = "Roboto", - size = 23, - weight = 1000, -}) - -surface.CreateFont("ACF_Subtitle", { - font = "Roboto", - size = 18, - weight = 1000, -}) - -surface.CreateFont("ACF_Paragraph", { - font = "Roboto", - size = 14, - weight = 750, -}) - -surface.CreateFont("ACF_Control", { - font = "Roboto", - size = 14, - weight = 550, -}) +do -- Tool data functions + local ToolData = {} + + do -- Read functions + function ACF.ReadBool(Key) + if not Key then return false end + + return tobool(ToolData[Key]) + end + + function ACF.ReadNumber(Key) + if not Key then return 0 end + + return tonumber(ToolData[Key]) + end + + function ACF.ReadString(Key) + if not Key then return "" end + + return tostring(ToolData[Key]) + end + end + + do -- Write function + local KeyPattern = "^[%w]+" + local ValuePattern = "[%w]*[%.]?[%w]+$" + + local function IsValidKey(Key) + if not Key then return false end + + return Key:match(KeyPattern) and true or false + end + + local function IsValidValue(Value) + if not Value then return false end + + return tostring(Value):match(ValuePattern) and true or false + end + + local function UpdateKeyValue(Key, Value) + if ToolData[Key] == Value then return end + + ToolData[Key] = Value + + net.Start("ACF_ToolData") + net.WriteString(Key .. ":" .. Value) + net.SendToServer() + + hook.Run("OnToolDataUpdate", Key, Value) + + print("Sent", LocalPlayer(), Key, Value) + end + + function ACF.WriteValue(Key, Value) + if not IsValidKey(Key) then return end + if not IsValidValue(Value) then return end + + UpdateKeyValue(Key, Value) + end + end + + do -- Panel functions + local PANEL = FindMetaTable("Panel") + local Panels = {} + + local function AddFunctions(Panel) + Panel.LegacySetValue = Panel.SetValue + Panel.LegacyRemove = Panel.Remove + + Panels[Panel] = true + + function Panel:SetValue(Value, ...) + ACF.WriteValue(self.DataVar, Value) + + self:LegacySetValue(Value, ...) + end + + function Panel:Remove(...) + Panels[Panel] = nil + + self:LegacyRemove(...) + end + end + + function PANEL:SetDataVariable(Key) + if not Key then return end + if not self.SetValue then return end + + self.DataVar = Key + + if not ToolData[Key] then + ACF.WriteValue(Key, self:GetValue()) + end + + if not self.LegacySetValue then + AddFunctions(self) + end + end + + function PANEL:ClearDataVariable() + if not self.LegacySetValue then return end + + Panels[self] = nil + + self.SetValue = self.LegacySetValue + self.Remove = self.LegacyRemove + self.LegacySetValue = nil + self.LegacyRemove = nil + self.DataVar = nil + end + + hook.Add("OnToolDataUpdate", "ACF Update Panel Values", function(Key, Value) + for Panel in pairs(Panels) do + if Panel.DataVar == Key then + Panel:LegacySetValue(Value) + end + end + end) + end +end \ No newline at end of file diff --git a/lua/acf/base/util/sv_util.lua b/lua/acf/base/util/sv_util.lua index 6a5950b31..fb1230b9f 100644 --- a/lua/acf/base/util/sv_util.lua +++ b/lua/acf/base/util/sv_util.lua @@ -1,58 +1,115 @@ -util.AddNetworkString("ACF_ChatMessage") +do -- Serverside console log messages + local Types = { + Normal = { + Prefix = "", + Color = Color(80, 255, 80) + }, + Info = { + Prefix = " - Info", + Color = Color(0, 233, 255) + }, + Warning = { + Prefix = " - Warning", + Color = Color(255, 160, 0) + }, + Error = { + Prefix = " - Error", + Color = Color(255, 80, 80) + } + } + + function ACF.AddLogType(Name, Prefix, TitleColor) + if not Name then return end + + Types[Name] = { + Prefix = Prefix and (" - " .. Prefix) or "", + Color = TitleColor or Color(80, 255, 80), + } + end + + function ACF.PrintLog(Type, ...) + if not ... then return end -function ACF.SendMessage(Player, Type, ...) - if not ... then return end + local Data = Types[Type] or Types.Normal + local Prefix = "[ACF" .. Data.Prefix .. "] " + local Message = istable(...) and ... or { ... } - local Message = istable(...) and ... or { ... } + Message[#Message + 1] = "\n" - net.Start("ACF_ChatMessage") - net.WriteString(Type or "Normal") - net.WriteTable(Message) - if IsValid(Player) then - net.Send(Player) - else - net.Broadcast() + MsgC(Data.Color, Prefix, color_white, unpack(Message)) end end -local Types = { - Normal = { - Prefix = "", - Color = Color(80, 255, 80) - }, - Info = { - Prefix = " - Info", - Color = Color(0, 233, 255) - }, - Warning = { - Prefix = " - Warning", - Color = Color(255, 160, 0) - }, - Error = { - Prefix = " - Error", - Color = Color(255, 80, 80) - } -} +do -- Clientside message delivery + util.AddNetworkString("ACF_ChatMessage") -function ACF.AddLogType(Name, Prefix, TitleColor) - if not Name then return end + function ACF.SendMessage(Player, Type, ...) + if not ... then return end - Types[Name] = { - Prefix = Prefix and (" - " .. Prefix) or "", - Color = TitleColor or Color(80, 255, 80), - } + local Message = istable(...) and ... or { ... } + + net.Start("ACF_ChatMessage") + net.WriteString(Type or "Normal") + net.WriteTable(Message) + if IsValid(Player) then + net.Send(Player) + else + net.Broadcast() + end + end end -function ACF.PrintLog(Type, ...) - if not ... then return end +do -- Tool data functions + local ToolData = {} + + do -- Data syncronization + util.AddNetworkString("ACF_ToolData") + + local function TranslateData(String) + return unpack(string.Explode(":", String)) + end - local Data = Types[Type] or Types.Normal - local Prefix = "[ACF" .. Data.Prefix .. "] " - local Message = istable(...) and ... or { ... } + net.Receive("ACF_ToolData", function(_, Player) + if not IsValid(Player) then return end - Message[#Message + 1] = "\n" + local Key, Value = TranslateData(net.ReadString()) - MsgC(Data.Color, Prefix, color_white, unpack(Message)) + ToolData[Player][Key] = Value + + print("Received", Player, Key, Value) + end) + + hook.Add("PlayerInitialSpawn", "ACF Tool Data", function(Player) + ToolData[Player] = {} + end) + + hook.Add("PlayerDisconnected", "ACF Tool Data", function(Player) + ToolData[Player] = nil + end) + end + + do -- Read functions + function ACF.ReadBool(Player, Key) + if not Key then return false end + if not ToolData[Player] then return false end + + return tobool(ToolData[Player][Key]) + end + + function ACF.ReadNumber(Player, Key) + if not Key then return 0 end + if not ToolData[Player] then return 0 end + + return tonumber(ToolData[Player][Key]) + end + + function ACF.ReadString(Player, Key) + if not Key then return "" end + if not ToolData[Player] then return "" end + + return tostring(ToolData[Player][Key]) + end + end end function ACF_GetHitAngle(HitNormal, HitVector) From 25837a7beda57375abd3af66e9c7105dbf2c1858 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sat, 15 Feb 2020 22:45:20 -0300 Subject: [PATCH 004/279] Added initial code to the menu's weapons option - Added a really early weapon selection menu - ACF_Panel's AddSlider function now requires Min and Max value arguments, and optionally Decimals at the end. --- lua/acf/client/cl_menu.lua | 16 ++--- lua/acf/client/menu_items/weapons_menu.lua | 73 ++++++++++++++++++++++ lua/vgui/acf_panel.lua | 5 +- 3 files changed, 85 insertions(+), 9 deletions(-) create mode 100644 lua/acf/client/menu_items/weapons_menu.lua diff --git a/lua/acf/client/cl_menu.lua b/lua/acf/client/cl_menu.lua index 51df2486b..40434528d 100644 --- a/lua/acf/client/cl_menu.lua +++ b/lua/acf/client/cl_menu.lua @@ -109,8 +109,8 @@ do -- ACF Menu context panel end local function UpdateTree(Tree, Old, New) - local OldParent = Old and Old.Parent or Old - local NewParent = New.Parent or New + local OldParent = Old and Old.Parent + local NewParent = New.Parent if OldParent == NewParent then return end @@ -140,25 +140,25 @@ do -- ACF Menu context panel end local Reload = Menu:AddButton("Reload Menu") - Reload.DoClickInternal = function() + function Reload:DoClickInternal() ACF.BuildContextPanel(Panel) end Menu:AddTitle("Available Options") local Tree = Menu:AddPanel("DTree") - Tree.OnNodeSelected = function(_, Node) - if Tree.Selected == Node then return end + function Tree:OnNodeSelected(Node) + if self.Selected == Node then return end if Node.Master then - Tree:SetSelectedItem(Node.Selected) + self:SetSelectedItem(Node.Selected) return end - UpdateTree(Tree, Tree.Selected, Node) + UpdateTree(self, self.Selected, Node) Node.Parent.Selected = Node - Tree.Selected = Node + self.Selected = Node Menu:ClearTemporal() Menu:StartTemporal() diff --git a/lua/acf/client/menu_items/weapons_menu.lua b/lua/acf/client/menu_items/weapons_menu.lua new file mode 100644 index 000000000..bc04fd269 --- /dev/null +++ b/lua/acf/client/menu_items/weapons_menu.lua @@ -0,0 +1,73 @@ +local Weapons = ACF.Classes.Weapons +local Selected = {} +local Sorted = {} + +local function LoadSortedList(Panel, List, Member) + local Choices = Sorted[List] + + if not Choices then + Choices = {} + + local Count = 0 + for _, V in pairs(List) do + Count = Count + 1 + Choices[Count] = V + end + + table.SortByMember(Choices, Member, true) + + Sorted[List] = Choices + Selected[Choices] = 1 + end + + Panel:Clear() + + for _, V in pairs(Choices) do + Panel:AddChoice(V.Name, V) + end + + Panel:ChooseOptionID(Selected[Choices]) +end + +local function CreateMenu(Menu) + local ClassList = Menu:AddComboBox() + local EntList = Menu:AddComboBox() + local Title = Menu:AddTitle() + local ClassDesc = Menu:AddParagraph() + + local Test1 = Menu:AddSlider("Test1", 37, 140, 2) + Test1:SetDataVariable("Test") + + local Test2 = Menu:AddSlider("Test2", 37, 140, 2) + Test2:SetDataVariable("Test") + + ACF.WriteValue("Class", "acf_gun") + + function ClassList:OnSelect(Index, _, Data) + if self.Selected == Data then return end + + self.Selected = Data + + local Choices = Sorted[Weapons] + Selected[Choices] = Index + + ClassDesc:SetText(Data.Description) + + LoadSortedList(EntList, Data.Items, "Caliber") + end + + function EntList:OnSelect(Index, _, Data) + if self.Selected == Data then return end + + self.Selected = Data + + local Choices = Sorted[ClassList.Selected.Items] + Selected[Choices] = Index + + Title:SetText(Data.Name) + end + + LoadSortedList(ClassList, Weapons, "Name") +end + +ACF.AddOptionItem("Entities", "Weapons", "gun", CreateMenu) diff --git a/lua/vgui/acf_panel.lua b/lua/vgui/acf_panel.lua index 8405144a3..c2e83eda9 100644 --- a/lua/vgui/acf_panel.lua +++ b/lua/vgui/acf_panel.lua @@ -131,9 +131,12 @@ function PANEL:AddComboBox() return Panel end -function PANEL:AddSlider(Title) +function PANEL:AddSlider(Title, Min, Max, Decimals) local Panel = self:AddPanel("DNumSlider") + Panel:SetDecimals(Decimals or 0) Panel:SetText(Title or "") + Panel:SetMinMax(Min, Max) + Panel:SetValue(Min) Panel:SetDark(true) return Panel From 0fe39eacfad9e10d177fc09fbb7f30b57caf4b4e Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Mon, 17 Feb 2020 04:53:14 -0300 Subject: [PATCH 005/279] Added min/max caliber data to weapon classes --- lua/acf/shared/guns/autocannon.lua | 6 ++++-- lua/acf/shared/guns/autoloader.lua | 6 ++++-- lua/acf/shared/guns/cannon.lua | 6 ++++-- lua/acf/shared/guns/grenadelauncher.lua | 6 ++++-- lua/acf/shared/guns/heavymachinegun.lua | 6 ++++-- lua/acf/shared/guns/howitzer.lua | 6 ++++-- lua/acf/shared/guns/machinegun.lua | 6 ++++-- lua/acf/shared/guns/mortar.lua | 6 ++++-- lua/acf/shared/guns/rotaryautocannon.lua | 6 ++++-- lua/acf/shared/guns/semiauto.lua | 6 ++++-- lua/acf/shared/guns/shortcannon.lua | 6 ++++-- lua/acf/shared/guns/smokelauncher.lua | 6 ++++-- 12 files changed, 48 insertions(+), 24 deletions(-) diff --git a/lua/acf/shared/guns/autocannon.lua b/lua/acf/shared/guns/autocannon.lua index ffb4cc0df..e4cb08828 100644 --- a/lua/acf/shared/guns/autocannon.lua +++ b/lua/acf/shared/guns/autocannon.lua @@ -87,8 +87,10 @@ ACF.RegisterWeaponClass("AC", { ROFMod = 0.85, Spread = 0.12, Sound = "weapons/ACF_Gun/ac_fire4.mp3", - soundDistance = " ", - soundNormal = " ", + Caliber = { + Min = 20, + Max = 50, + }, }) ACF.RegisterWeapon("20mmAC", "AC", { diff --git a/lua/acf/shared/guns/autoloader.lua b/lua/acf/shared/guns/autoloader.lua index 5fbd36caf..c10fd74c2 100644 --- a/lua/acf/shared/guns/autoloader.lua +++ b/lua/acf/shared/guns/autoloader.lua @@ -106,8 +106,10 @@ ACF.RegisterWeaponClass("AL", { ROFMod = 0.64, Spread = 0.08, Sound = "weapons/ACF_Gun/autoloader.mp3", - soundDistance = "Cannon.Fire", - soundNormal = " ", + Caliber = { + Min = 75, + Max = 140, + }, }) ACF.RegisterWeapon("75mmAL", "AL", { diff --git a/lua/acf/shared/guns/cannon.lua b/lua/acf/shared/guns/cannon.lua index 702005560..599ea92cb 100644 --- a/lua/acf/shared/guns/cannon.lua +++ b/lua/acf/shared/guns/cannon.lua @@ -122,8 +122,10 @@ ACF.RegisterWeaponClass("C", { ROFMod = 2, Spread = 0.08, Sound = "weapons/ACF_Gun/cannon_new.mp3", - soundDistance = "Cannon.Fire", - soundNormal = " ", + Caliber = { + Min = 20, + Max = 140, + }, }) ACF.RegisterWeapon("37mmC", "C", { diff --git a/lua/acf/shared/guns/grenadelauncher.lua b/lua/acf/shared/guns/grenadelauncher.lua index 4fa1e394e..aa3e783d6 100644 --- a/lua/acf/shared/guns/grenadelauncher.lua +++ b/lua/acf/shared/guns/grenadelauncher.lua @@ -34,8 +34,10 @@ ACF.RegisterWeaponClass("GL", { ROFMod = 1, Spread = 0.32, Sound = "weapons/acf_gun/grenadelauncher.mp3", - soundDistance = " ", - soundNormal = " ", + Caliber = { + Min = 25, + Max = 40, + }, }) ACF.RegisterWeapon("40mmGL", "GL", { diff --git a/lua/acf/shared/guns/heavymachinegun.lua b/lua/acf/shared/guns/heavymachinegun.lua index 45e35f63b..ec8de5857 100644 --- a/lua/acf/shared/guns/heavymachinegun.lua +++ b/lua/acf/shared/guns/heavymachinegun.lua @@ -91,8 +91,10 @@ ACF.RegisterWeaponClass("HMG", { ROFMod = 0.14, Spread = 0.4, Sound = "weapons/ACF_Gun/mg_fire3.mp3", - soundDistance = " ", - soundNormal = " ", + Caliber = { + Min = 13, + Max = 40, + }, LongBarrel = { Index = 2, Submodel = 4, diff --git a/lua/acf/shared/guns/howitzer.lua b/lua/acf/shared/guns/howitzer.lua index 7b806083b..c1a2cac20 100644 --- a/lua/acf/shared/guns/howitzer.lua +++ b/lua/acf/shared/guns/howitzer.lua @@ -119,8 +119,10 @@ ACF.RegisterWeaponClass("HW", { ROFMod = 1.8, Spread = 0.12, Sound = "weapons/ACF_Gun/howitzer_new2.mp3", - soundDistance = "Howitzer.Fire", - soundNormal = " ", + Caliber = { + Min = 75, + Max = 203, + }, }) ACF.RegisterWeapon("75mmHW", "HW", { diff --git a/lua/acf/shared/guns/machinegun.lua b/lua/acf/shared/guns/machinegun.lua index e48e23c31..4634cc866 100644 --- a/lua/acf/shared/guns/machinegun.lua +++ b/lua/acf/shared/guns/machinegun.lua @@ -89,8 +89,10 @@ ACF.RegisterWeaponClass("MG", { ROFMod = 0.9, Spread = 0.24, Sound = "weapons/ACF_Gun/mg_fire4.mp3", - soundNormal = "weapons/ACF_Gun/mg_fire4.mp3", - soundDistance = "", + Caliber = { + Min = 5.56, + Max = 14.5, + }, }) ACF.RegisterWeapon("7.62mmMG", "MG", { diff --git a/lua/acf/shared/guns/mortar.lua b/lua/acf/shared/guns/mortar.lua index 066ca3cd5..eec670ddc 100644 --- a/lua/acf/shared/guns/mortar.lua +++ b/lua/acf/shared/guns/mortar.lua @@ -106,8 +106,10 @@ ACF.RegisterWeaponClass("MO", { ROFMod = 2.5, Spread = 0.64, Sound = "weapons/ACF_Gun/mortar_new.mp3", - soundDistance = "Mortar.Fire", - soundNormal = " ", + Caliber = { + Min = 37, + Max = 150, + }, }) ACF.RegisterWeapon("60mmM", "MO", { diff --git a/lua/acf/shared/guns/rotaryautocannon.lua b/lua/acf/shared/guns/rotaryautocannon.lua index 7c2f1c623..dde1f45e7 100644 --- a/lua/acf/shared/guns/rotaryautocannon.lua +++ b/lua/acf/shared/guns/rotaryautocannon.lua @@ -104,8 +104,10 @@ ACF.RegisterWeaponClass("RAC", { ROFMod = 0.07, Spread = 0.4, Sound = "weapons/acf_gun/mg_fire3.mp3", - soundDistance = " ", - soundNormal = " ", + Caliber = { + Min = 7.62, + Max = 30, + }, }) ACF.RegisterWeapon("14.5mmRAC", "RAC", { diff --git a/lua/acf/shared/guns/semiauto.lua b/lua/acf/shared/guns/semiauto.lua index 248b2a85e..50f418a49 100644 --- a/lua/acf/shared/guns/semiauto.lua +++ b/lua/acf/shared/guns/semiauto.lua @@ -104,8 +104,10 @@ ACF.RegisterWeaponClass("SA", { ROFMod = 0.36, Spread = 0.1, Sound = "weapons/acf_gun/sa_fire1.mp3", - soundDistance = " ", - soundNormal = " ", + Caliber = { + Min = 20, + Max = 76, + }, }) ACF.RegisterWeapon("25mmSA", "SA", { diff --git a/lua/acf/shared/guns/shortcannon.lua b/lua/acf/shared/guns/shortcannon.lua index 1b6fb9603..4779098ee 100644 --- a/lua/acf/shared/guns/shortcannon.lua +++ b/lua/acf/shared/guns/shortcannon.lua @@ -106,8 +106,10 @@ ACF.RegisterWeaponClass("SC", { ROFMod = 1.7, Spread = 0.2, Sound = "weapons/ACF_Gun/cannon_new.mp3", - soundDistance = "Cannon.Fire", - soundNormal = " ", + Caliber = { + Min = 37, + Max = 140, + }, }) ACF.RegisterWeapon("37mmSC", "SC", { diff --git a/lua/acf/shared/guns/smokelauncher.lua b/lua/acf/shared/guns/smokelauncher.lua index 92a2e327b..e3538b2a9 100644 --- a/lua/acf/shared/guns/smokelauncher.lua +++ b/lua/acf/shared/guns/smokelauncher.lua @@ -54,8 +54,10 @@ ACF.RegisterWeaponClass("SL", { ROFMod = 45, Spread = 0.32, Sound = "weapons/acf_gun/smoke_launch.mp3", - soundDistance = "Mortar.Fire", - soundNormal = " ", + Caliber = { + Min = 40, + Max = 76, + }, }) ACF.RegisterWeapon("40mmSL", "SL", { From 439059e0c406c532697073054c58ea588a4382e6 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Mon, 17 Feb 2020 04:54:04 -0300 Subject: [PATCH 006/279] Added weapon stats info to the menu --- lua/acf/client/menu_items/weapons_menu.lua | 24 ++++++++++++++-------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/lua/acf/client/menu_items/weapons_menu.lua b/lua/acf/client/menu_items/weapons_menu.lua index bc04fd269..43b4b0a3e 100644 --- a/lua/acf/client/menu_items/weapons_menu.lua +++ b/lua/acf/client/menu_items/weapons_menu.lua @@ -30,16 +30,14 @@ local function LoadSortedList(Panel, List, Member) end local function CreateMenu(Menu) + local EntText = "Mass: %skg\nFirerate: %srpm\nSpread: %s degrees%s" + local MagText = "\nRounds: %s rounds\nReload: %s seconds" + local ClassList = Menu:AddComboBox() local EntList = Menu:AddComboBox() - local Title = Menu:AddTitle() + local EntName = Menu:AddSubtitle() local ClassDesc = Menu:AddParagraph() - - local Test1 = Menu:AddSlider("Test1", 37, 140, 2) - Test1:SetDataVariable("Test") - - local Test2 = Menu:AddSlider("Test2", 37, 140, 2) - Test2:SetDataVariable("Test") + local EntData = Menu:AddParagraph() ACF.WriteValue("Class", "acf_gun") @@ -61,10 +59,18 @@ local function CreateMenu(Menu) self.Selected = Data - local Choices = Sorted[ClassList.Selected.Items] + local ClassData = ClassList.Selected + local RoundVolume = 3.1416 * (Data.Caliber * 0.05) ^ 2 * Data.Round.MaxLength + local Firerate = 60 / (((RoundVolume / 500) ^ 0.6) * ClassData.ROFMod * (Data.ROFMod or 1)) + local Magazine = Data.MagSize and MagText:format(Data.MagSize, Data.MagReload) or "" + + local Choices = Sorted[ClassData.Items] Selected[Choices] = Index - Title:SetText(Data.Name) + ACF.WriteValue("Weapon", Data.ID) + + EntName:SetText(Data.Name) + EntData:SetText(EntText:format(Data.Mass, math.Round(Firerate, 2), ClassData.Spread * 100, Magazine)) end LoadSortedList(ClassList, Weapons, "Name") From a1e0bc2c799546db694533adb6866a1cd4bce313 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Tue, 18 Feb 2020 06:50:31 -0300 Subject: [PATCH 007/279] Added crate registration function --- lua/acf/base/sh_classes.lua | 27 ++- lua/acf/shared/ammo_crates/crates.lua | 251 ++++++++++++++++++++++++++ 2 files changed, 277 insertions(+), 1 deletion(-) create mode 100644 lua/acf/shared/ammo_crates/crates.lua diff --git a/lua/acf/base/sh_classes.lua b/lua/acf/base/sh_classes.lua index c3ef37840..da0b780b6 100644 --- a/lua/acf/base/sh_classes.lua +++ b/lua/acf/base/sh_classes.lua @@ -44,7 +44,6 @@ do -- Weapon class registration functions Class = Class, ClassID = ClassID, EntClass = "acf_gun", - Type = "Weapons", } Class.Count = Class.Count + 1 @@ -60,4 +59,30 @@ do -- Weapon class registration functions PrecacheParticleSystem(Weapon.MuzzleFlash) end end +end + +do -- Ammo crate registration function + ACF.Classes.Crates = ACF.Classes.Crates or {} + + local Crates = ACF.Classes.Crates + + function ACF.RegisterCrate(ID, Data) + if not ID then return end + if not Data then return end + + local Crate = Crates[ID] + + if not Crate then + Crate = { + ID = ID, + EntClass = "acf_ammo", + } + + Crates[ID] = Crate + end + + for K, V in pairs(Data) do + Crate[K] = V + end + end end \ No newline at end of file diff --git a/lua/acf/shared/ammo_crates/crates.lua b/lua/acf/shared/ammo_crates/crates.lua new file mode 100644 index 000000000..c619fde22 --- /dev/null +++ b/lua/acf/shared/ammo_crates/crates.lua @@ -0,0 +1,251 @@ +ACF.RegisterCrate("AmmoSmall", { + Name = "Small Ammo Crate", + Model = "models/ammocrate_small.mdl", + Mass = 10, + Volume = 2198, +}) + +ACF.RegisterCrate("AmmoMedCube", { + Name = "Medium Cubic Ammo Crate", + Model = "models/ammocrate_medium_small.mdl", + Mass = 80, + Volume = 17769, +}) + +ACF.RegisterCrate("AmmoMedium", { + Name = "Medium Ammo Crate", + Model = "models/ammocrate_medium.mdl", + Mass = 150, + Volume = 35105, +}) + +ACF.RegisterCrate("AmmoLarge", { + Name = "Large Ammo Crate", + Model = "models/ammocrate_large.mdl", + Mass = 1000, + Volume = 140503, +}) + +ACF.RegisterCrate("Ammo1x1x8", { + Name = "Modular 1x1x8 Ammo Crate", + Model = "models/ammocrates/ammo_1x1x8.mdl", + Mass = 40, + Volume = 10872, +}) + +ACF.RegisterCrate("Ammo1x1x6", { + Name = "Modular 1x1x6 Ammo Crate", + Model = "models/ammocrates/ammo_1x1x6.mdl", + Mass = 30, + Volume = 8202, +}) + +ACF.RegisterCrate("Ammo1x1x4", { + Name = "Modular 1x1x4 Ammo Crate", + Model = "models/ammocrates/ammo_1x1x4.mdl", + Mass = 20, + Volume = 5519, +}) + +ACF.RegisterCrate("Ammo1x1x2", { + Name = "Modular 1x1x2 Ammo Crate", + Model = "models/ammocrates/ammo_1x1x2.mdl", + Mass = 10, + Volume = 2743, +}) + +ACF.RegisterCrate("Ammo2x2x1", { + Name = "Modular 2x2x1 Ammo Crate", + Model = "models/ammocrates/ammocrate_2x2x1.mdl", + Mass = 20, + Volume = 3200, +}) + +ACF.RegisterCrate("Ammo2x2x2", { + Name = "Modular 2x2x2 Ammo Crate", + Model = "models/ammocrates/ammocrate_2x2x2.mdl", + Mass = 40, + Volume = 8000, +}) + +ACF.RegisterCrate("Ammo2x2x4", { + Name = "Modular 2x2x4 Ammo Crate", + Model = "models/ammocrates/ammocrate_2x2x4.mdl", + Mass = 80, + Volume = 18000, +}) + +ACF.RegisterCrate("Ammo2x2x6", { + Name = "Modular 2x2x6 Ammo Crate", + Model = "models/ammocrates/ammo_2x2x6.mdl", + Mass = 120, + Volume = 33179, +}) + +ACF.RegisterCrate("Ammo2x2x8", { + Name = "Modular 2x2x8 Ammo Crate", + Model = "models/ammocrates/ammo_2x2x8.mdl", + Mass = 160, + Volume = 45902, +}) + +ACF.RegisterCrate("Ammo2x3x1", { + Name = "Modular 2x3x1 Ammo Crate", + Model = "models/ammocrates/ammocrate_2x3x1.mdl", + Mass = 30, + Volume = 5119, +}) + +ACF.RegisterCrate("Ammo2x3x2", { + Name = "Modular 2x3x2 Ammo Crate", + Model = "models/ammocrates/ammocrate_2x3x2.mdl", + Mass = 60, + Volume = 12799, +}) + +ACF.RegisterCrate("Ammo2x3x4", { + Name = "Modular 2x3x4 Ammo Crate", + Model = "models/ammocrates/ammocrate_2x3x4.mdl", + Mass = 120, + Volume = 28800, +}) + +ACF.RegisterCrate("Ammo2x3x6", { + Name = "Modular 2x3x6 Ammo Crate", + Model = "models/ammocrates/ammocrate_2x3x6.mdl", + Mass = 180, + Volume = 43421, +}) + +ACF.RegisterCrate("Ammo2x3x8", { + Name = "Modular 2x3x8 Ammo Crate", + Model = "models/ammocrates/ammocrate_2x3x8.mdl", + Mass = 240, + Volume = 57509, +}) + +ACF.RegisterCrate("Ammo2x4x1", { + Name = "Modular 2x4x1 Ammo Crate", + Model = "models/ammocrates/ammocrate_2x4x1.mdl", + Mass = 40, + Volume = 7200, +}) + +ACF.RegisterCrate("Ammo2x4x2", { + Name = "Modular 2x4x2 Ammo Crate", + Model = "models/ammocrates/ammocrate_2x4x2.mdl", + Mass = 80, + Volume = 18000, +}) + +ACF.RegisterCrate("Ammo2x4x4", { + Name = "Modular 2x4x4 Ammo Crate", + Model = "models/ammocrates/ammocrate_2x4x4.mdl", + Mass = 160, + Volume = 40500, +}) + +ACF.RegisterCrate("Ammo2x4x6", { + Name = "Modular 2x4x6 Ammo Crate", + Model = "models/ammocrates/ammocrate_2x4x6.mdl", + Mass = 240, + Volume = 61200, +}) + +ACF.RegisterCrate("Ammo2x4x8", { + Name = "Modular 2x4x8 Ammo Crate", + Model = "models/ammocrates/ammocrate_2x4x8.mdl", + Mass = 320, + Volume = 80999, +}) + +ACF.RegisterCrate("Ammo3x4x1", { + Name = "Modular 3x4x1 Ammo Crate", + Model = "models/ammocrates/ammocrate_3x4x1.mdl", + Mass = 60, + Volume = 11520, +}) + +ACF.RegisterCrate("Ammo3x4x2", { + Name = "Modular 3x4x2 Ammo Crate", + Model = "models/ammocrates/ammocrate_3x4x2.mdl", + Mass = 120, + Volume = 28800, +}) + +ACF.RegisterCrate("Ammo3x4x4", { + Name = "Modular 3x4x4 Ammo Crate", + Model = "models/ammocrates/ammocrate_3x4x4.mdl", + Mass = 240, + Volume = 64800, +}) + +ACF.RegisterCrate("Ammo3x4x6", { + Name = "Modular 3x4x6 Ammo Crate", + Model = "models/ammocrates/ammocrate_3x4x6.mdl", + Mass = 360, + Volume = 97920, +}) + +ACF.RegisterCrate("Ammo3x4x8", { + Name = "Modular 3x4x8 Ammo Crate", + Model = "models/ammocrates/ammocrate_3x4x8.mdl", + Mass = 480, + Volume = 129599, +}) + +ACF.RegisterCrate("Ammo4x4x1", { + Name = "Modular 4x4x1 Ammo Crate", + Model = "models/ammocrates/ammo_4x4x1.mdl", + Mass = 80, + Volume = 23186, +}) + +ACF.RegisterCrate("Ammo4x4x2", { + Name = "Modular 4x4x2 Ammo Crate", + Model = "models/ammocrates/ammocrate_4x4x2.mdl", + Mass = 160, + Volume = 40500, +}) + +ACF.RegisterCrate("Ammo4x4x4", { + Name = "Modular 4x4x4 Ammo Crate", + Model = "models/ammocrates/ammocrate_4x4x4.mdl", + Mass = 320, + Volume = 91125, +}) + +ACF.RegisterCrate("Ammo4x4x6", { + Name = "Modular 4x4x6 Ammo Crate", + Model = "models/ammocrates/ammocrate_4x4x6.mdl", + Mass = 480, + Volume = 137700, +}) + +ACF.RegisterCrate("Ammo4x4x8", { + Name = "Modular 4x4x8 Ammo Crate", + Model = "models/ammocrates/ammocrate_4x4x8.mdl", + Mass = 640, + Volume = 182249, +}) + +ACF.RegisterCrate("Ammo4x6x6", { + Name = "Modular 4x6x6 Ammo Crate", + Model = "models/ammocrates/ammo_4x6x6.mdl", + Mass = 720, + Volume = 204106, +}) + +ACF.RegisterCrate("Ammo4x6x8", { + Name = "Modular 4x6x8 Ammo Crate", + Model = "models/ammocrates/ammo_4x6x8.mdl", + Mass = 800, + Volume = 272664, +}) + +ACF.RegisterCrate("Ammo4x8x8", { + Name = "Modular 4x8x8 Ammo Crate", + Model = "models/ammocrates/ammo_4x8x8.mdl", + Mass = 960, + Volume = 366397, +}) From 172770115541351dc4ed4e391d8c4c2e72fb64cb Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Fri, 21 Feb 2020 01:07:47 -0300 Subject: [PATCH 008/279] Added ACF.GetPlayerData function - Added ACF.GetPlayerData function to retrieve a copy of the tool data stored for each player - Serverside: You must specify the player which you want to get the info. - Clientside: No arguments are required, you can only retrieve a copy of your own data. --- lua/acf/base/util/cl_util.lua | 10 ++++++++++ lua/acf/base/util/sv_util.lua | 13 +++++++++++++ 2 files changed, 23 insertions(+) diff --git a/lua/acf/base/util/cl_util.lua b/lua/acf/base/util/cl_util.lua index cd73fe391..072171117 100644 --- a/lua/acf/base/util/cl_util.lua +++ b/lua/acf/base/util/cl_util.lua @@ -77,6 +77,16 @@ do -- Tool data functions local ToolData = {} do -- Read functions + function ACF.GetPlayerData() + local Result = {} + + for K, V in pairs(ToolData[Player]) do + Result[K] = V + end + + return Result + end + function ACF.ReadBool(Key) if not Key then return false end diff --git a/lua/acf/base/util/sv_util.lua b/lua/acf/base/util/sv_util.lua index fb1230b9f..1dbeb297b 100644 --- a/lua/acf/base/util/sv_util.lua +++ b/lua/acf/base/util/sv_util.lua @@ -89,6 +89,19 @@ do -- Tool data functions end do -- Read functions + function ACF.GetPlayerData(Player) + if not IsValid(Player) then return {} end + if not ToolData[Player] then return {} end + + local Result = {} + + for K, V in pairs(ToolData[Player]) do + Result[K] = V + end + + return Result + end + function ACF.ReadBool(Player, Key) if not Key then return false end if not ToolData[Player] then return false end From 71e3e93f9a1d4859ead43c23471dd4b2b8e01470 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Fri, 21 Feb 2020 01:09:45 -0300 Subject: [PATCH 009/279] Added Classes library (taken from ACF-3 Missiles) --- lua/acf/base/sh_classes.lua | 83 ++++++++++++++++++++++++++++++++++++- 1 file changed, 82 insertions(+), 1 deletion(-) diff --git a/lua/acf/base/sh_classes.lua b/lua/acf/base/sh_classes.lua index da0b780b6..20832e7fd 100644 --- a/lua/acf/base/sh_classes.lua +++ b/lua/acf/base/sh_classes.lua @@ -1,4 +1,85 @@ -do -- Weapon class registration functions +do -- Class registration function + local Classes = {} + local Queued = {} + + local function CreateInstance(Class) + local New = {} + + setmetatable(New, { __index = Class }) + + if New.OnCalled then + New:OnCalled() + end + + return New + end + + local function QueueBaseClass(Name, Base) + if not Queued[Base] then + Queued[Base] = { [Name] = true } + else + Queued[Base][Name] = true + end + end + + local function AttachMetaTable(Class, Name, Base) + local OldMeta = getmetatable(Class) or {} + + if Base then + local BaseClass = Classes[Base] + + if BaseClass then + Class.BaseClass = BaseClass + OldMeta.__index = BaseClass + else + QueueBaseClass(Name, Base) + end + end + + OldMeta.__call = function() + return CreateInstance(Class) + end + + setmetatable(Class, OldMeta) + + timer.Simple(0, function() + if Class.OnLoaded then + Class:OnLoaded() + end + end) + end + + function ACF.RegisterClass(Name, Base, Destiny) + if not Classes[Name] then + Classes[Name] = {} + end + + local Class = Classes[Name] + Class.Name = Name + + AttachMetaTable(Class, Name, Base) + + if Queued[Name] then + local Current + + for K in pairs(Queued[Name]) do + Current = Classes[K] + + AttachMetaTable(Current, Current.Name, Name) + end + + Queued[Name] = nil + end + + if Destiny then + Destiny[Name] = Class + end + + return Class + end +end + +do -- Weapon registration functions ACF.Classes.Weapons = ACF.Classes.Weapons or {} local Weapons = ACF.Classes.Weapons From 13a3bba4fd148722cfd56248de413675271293f7 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Fri, 21 Feb 2020 01:13:40 -0300 Subject: [PATCH 010/279] Added ACF.RegisterAmmoType function - Ported existing ammo types to use the new function --- lua/acf/base/sh_classes.lua | 13 +- lua/acf/shared/ammo_types/ap.lua | 209 ++++++++++++++ lua/acf/shared/ammo_types/aphe.lua | 172 ++++++++++++ lua/acf/shared/ammo_types/fl.lua | 241 +++++++++++++++++ lua/acf/shared/ammo_types/he.lua | 166 ++++++++++++ lua/acf/shared/ammo_types/heat.lua | 374 ++++++++++++++++++++++++++ lua/acf/shared/ammo_types/hp.lua | 145 ++++++++++ lua/acf/shared/ammo_types/refill.lua | 63 +++++ lua/acf/shared/ammo_types/smoke.lua | 224 +++++++++++++++ lua/acf/shared/guns/smokelauncher.lua | 2 +- 10 files changed, 1607 insertions(+), 2 deletions(-) create mode 100644 lua/acf/shared/ammo_types/ap.lua create mode 100644 lua/acf/shared/ammo_types/aphe.lua create mode 100644 lua/acf/shared/ammo_types/fl.lua create mode 100644 lua/acf/shared/ammo_types/he.lua create mode 100644 lua/acf/shared/ammo_types/heat.lua create mode 100644 lua/acf/shared/ammo_types/hp.lua create mode 100644 lua/acf/shared/ammo_types/refill.lua create mode 100644 lua/acf/shared/ammo_types/smoke.lua diff --git a/lua/acf/base/sh_classes.lua b/lua/acf/base/sh_classes.lua index 20832e7fd..2f5c8c97c 100644 --- a/lua/acf/base/sh_classes.lua +++ b/lua/acf/base/sh_classes.lua @@ -166,4 +166,15 @@ do -- Ammo crate registration function Crate[K] = V end end -end \ No newline at end of file +end + +do -- Ammo type registration function + ACF.Classes.AmmoTypes = ACF.Classes.AmmoTypes or {} + + local RegisterClass = ACF.RegisterClass + local Types = ACF.Classes.AmmoTypes + + function ACF.RegisterAmmoType(Name, Base) + return RegisterClass(Name, Base, Types) + end +end diff --git a/lua/acf/shared/ammo_types/ap.lua b/lua/acf/shared/ammo_types/ap.lua new file mode 100644 index 000000000..91e433b60 --- /dev/null +++ b/lua/acf/shared/ammo_types/ap.lua @@ -0,0 +1,209 @@ +local Ammo = ACF.RegisterAmmoType("Armor Piercing") +local DecalIndex = ACF.GetAmmoDecalIndex + +function Ammo:OnLoaded() + self.ID = "AP" + self.Type = "Ammo" + self.Model = "models/munitions/round_100mm_shot.mdl" + self.Description = "A shell made out of a solid piece of steel, meant to penetrate armor." + self.Blacklist = { "MO", "SL", "SB" } +end + +function Ammo.Create(_, BulletData) + ACF_CreateBullet(BulletData) +end + +function Ammo.Convert(_, PlayerData) + local Data = {} + local ServerData = {} + local GUIData = {} + + if not PlayerData.PropLength then + PlayerData.PropLength = 0 + end + + if not PlayerData.ProjLength then + PlayerData.ProjLength = 0 + end + + if not PlayerData.Data10 then + PlayerData.Data10 = 0 + end + + PlayerData, Data, ServerData, GUIData = ACF_RoundBaseGunpowder(PlayerData, Data, ServerData, GUIData) + + Data.ProjMass = Data.FrArea * (Data.ProjLength * 7.9 / 1000) --Volume of the projectile as a cylinder * density of steel + Data.ShovePower = 0.2 + Data.PenArea = Data.FrArea ^ ACF.PenAreaMod + Data.DragCoef = ((Data.FrArea / 10000) / Data.ProjMass) + Data.LimitVel = 800 --Most efficient penetration speed in m/s + Data.KETransfert = 0.1 --Kinetic energy transfert to the target for movement purposes + Data.Ricochet = 60 --Base ricochet angle + Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass, Data.Caliber) + Data.BoomPower = Data.PropMass + + --Only the crates need this part + if SERVER then + ServerData.Id = PlayerData.Id + ServerData.Type = PlayerData.Type + + return table.Merge(Data, ServerData) + end + + --Only the GUI needs this part + if CLIENT then + GUIData = table.Merge(GUIData, Ammo.GetDisplayData(Data)) + + return table.Merge(Data, GUIData) + end +end + +function Ammo.Network(Crate, BulletData) + Crate:SetNWString("AmmoType", "AP") + Crate:SetNWString("AmmoID", BulletData.Id) + Crate:SetNWFloat("Caliber", BulletData.Caliber) + Crate:SetNWFloat("ProjMass", BulletData.ProjMass) + Crate:SetNWFloat("PropMass", BulletData.PropMass) + Crate:SetNWFloat("DragCoef", BulletData.DragCoef) + Crate:SetNWFloat("MuzzleVel", BulletData.MuzzleVel) + Crate:SetNWFloat("Tracer", BulletData.Tracer) +end + +function Ammo.GetDisplayData(BulletData) + local Energy = ACF_Kinetic(BulletData.MuzzleVel * 39.37, BulletData.ProjMass, BulletData.LimitVel) + + return { + MaxPen = (Energy.Penetration / BulletData.PenArea) * ACF.KEtoRHA + } +end + +function Ammo.GetCrateText(BulletData) + local Data = Ammo.GetDisplayData(BulletData) + local Text = "Muzzle Velocity: %s m/s\nMax Penetration: %s mm" + + return Text:format(math.Round(BulletData.MuzzleVel, 2), math.floor(Data.MaxPen)) +end + +function Ammo.PropImpact(_, Bullet, Target, HitNormal, HitPos, Bone) + if ACF_Check(Target) then + local Speed = Bullet.Flight:Length() / ACF.Scale + local Energy = ACF_Kinetic(Speed, Bullet.ProjMass, Bullet.LimitVel) + local HitRes = ACF_RoundImpact(Bullet, Speed, Energy, Target, HitPos, HitNormal, Bone) + + if HitRes.Overkill > 0 then + table.insert(Bullet.Filter, Target) --"Penetrate" (Ingoring the prop for the retry trace) + Bullet.Flight = Bullet.Flight:GetNormalized() * (Energy.Kinetic * (1 - HitRes.Loss) * 2000 / Bullet.ProjMass) ^ 0.5 * 39.37 + + return "Penetrated" + elseif HitRes.Ricochet then + return "Ricochet" + else + return false + end + else + table.insert(Bullet.Filter, Target) + + return "Penetrated" + end +end + +function Ammo.WorldImpact(_, Bullet, HitPos, HitNormal) + local Energy = ACF_Kinetic(Bullet.Flight:Length() / ACF.Scale, Bullet.ProjMass, Bullet.LimitVel) + local HitRes = ACF_PenetrateGround(Bullet, Energy, HitPos, HitNormal) + + if HitRes.Penetrated then + return "Penetrated" + elseif HitRes.Ricochet then + return "Ricochet" + else + return false + end +end + +function Ammo.OnFlightEnd(Index) + ACF_RemoveBullet(Index) +end + +function Ammo.ImpactEffect(_, Bullet) + local Effect = EffectData() + Effect:SetOrigin(Bullet.SimPos) + Effect:SetNormal(Bullet.SimFlight:GetNormalized()) + Effect:SetRadius(Bullet.Caliber) + Effect:SetDamageType(DecalIndex(Bullet.AmmoType)) + + util.Effect("ACF_Impact", Effect) +end + +function Ammo.PenetrationEffect(_, Bullet) + local Effect = EffectData() + Effect:SetOrigin(Bullet.SimPos) + Effect:SetNormal(Bullet.SimFlight:GetNormalized()) + Effect:SetScale(Bullet.SimFlight:Length()) + Effect:SetMagnitude(Bullet.RoundMass) + Effect:SetRadius(Bullet.Caliber) + Effect:SetDamageType(DecalIndex(Bullet.AmmoType)) + + util.Effect("ACF_Penetration", Effect) +end + +function Ammo.RicochetEffect(_, Bullet) + local Effect = EffectData() + Effect:SetOrigin(Bullet.SimPos) + Effect:SetNormal(Bullet.SimFlight:GetNormalized()) + Effect:SetScale(Bullet.SimFlight:Length()) + Effect:SetMagnitude(Bullet.RoundMass) + Effect:SetRadius(Bullet.Caliber) + Effect:SetDamageType(DecalIndex(Bullet.AmmoType)) + + util.Effect("ACF_Ricochet", Effect) +end + +function Ammo.CreateMenu(Panel, Table) + acfmenupanel:AmmoSelect(Ammo.Blacklist) + + acfmenupanel:CPanelText("Desc", "") --Description (Name, Desc) + acfmenupanel:CPanelText("LengthDisplay", "") --Total round length (Name, Desc) + acfmenupanel:AmmoSlider("PropLength", 0, 0, 1000, 3, "Propellant Length", "") --Propellant Length Slider (Name, Value, Min, Max, Decimals, Title, Desc) + acfmenupanel:AmmoSlider("ProjLength", 0, 0, 1000, 3, "Projectile Length", "") --Projectile Length Slider (Name, Value, Min, Max, Decimals, Title, Desc) + acfmenupanel:AmmoCheckbox("Tracer", "Tracer", "") --Tracer checkbox (Name, Title, Desc) + acfmenupanel:CPanelText("VelocityDisplay", "") --Proj muzzle velocity (Name, Desc) + acfmenupanel:CPanelText("PenetrationDisplay", "") --Proj muzzle penetration (Name, Desc) + + Ammo.UpdateMenu(Panel, Table) +end + +function Ammo.UpdateMenu(Panel) + local PlayerData = { + Id = acfmenupanel.AmmoData.Data.id, --AmmoSelect GUI + Type = "AP", --Hardcoded, match ACFRoundTypes table index + PropLength = acfmenupanel.AmmoData.PropLength, --PropLength slider + ProjLength = acfmenupanel.AmmoData.ProjLength, --ProjLength slider + Data10 = acfmenupanel.AmmoData.Tracer and 1 or 0 + } + + local Data = Ammo.Convert(Panel, PlayerData) + + RunConsoleCommand("acfmenu_data1", acfmenupanel.AmmoData.Data.id) + RunConsoleCommand("acfmenu_data2", PlayerData.Type) + RunConsoleCommand("acfmenu_data3", Data.PropLength) --For Gun ammo, Data3 should always be Propellant + RunConsoleCommand("acfmenu_data4", Data.ProjLength) --And Data4 total round mass + RunConsoleCommand("acfmenu_data10", Data.Tracer) + + acfmenupanel:AmmoSlider("PropLength", Data.PropLength, Data.MinPropLength, Data.MaxTotalLength, 3, "Propellant Length", "Propellant Mass : " .. (math.floor(Data.PropMass * 1000)) .. " g") --Propellant Length Slider (Name, Min, Max, Decimals, Title, Desc) + acfmenupanel:AmmoSlider("ProjLength", Data.ProjLength, Data.MinProjLength, Data.MaxTotalLength, 3, "Projectile Length", "Projectile Mass : " .. (math.floor(Data.ProjMass * 1000)) .. " g") --Projectile Length Slider (Name, Min, Max, Decimals, Title, Desc) + acfmenupanel:AmmoCheckbox("Tracer", "Tracer : " .. (math.floor(Data.Tracer * 10) / 10) .. "cm\n", "") --Tracer checkbox (Name, Title, Desc) + acfmenupanel:CPanelText("Desc", Ammo.Description) --Description (Name, Desc) + acfmenupanel:CPanelText("LengthDisplay", "Round Length : " .. (math.floor((Data.PropLength + Data.ProjLength + Data.Tracer) * 100) / 100) .. "/" .. Data.MaxTotalLength .. " cm") --Total round length (Name, Desc) + acfmenupanel:CPanelText("VelocityDisplay", "Muzzle Velocity : " .. math.floor(Data.MuzzleVel * ACF.Scale) .. " m/s") --Proj muzzle velocity (Name, Desc) + + local R1V, R1P = ACF_PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 300) + local R2V, R2P = ACF_PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 800) + + acfmenupanel:CPanelText("PenetrationDisplay", "Maximum Penetration : " .. math.floor(Data.MaxPen) .. " mm RHA\n\n300m pen: " .. math.Round(R1P, 0) .. "mm @ " .. math.Round(R1V, 0) .. " m/s\n800m pen: " .. math.Round(R2P, 0) .. "mm @ " .. math.Round(R2V, 0) .. " m/s\n\nThe range data is an approximation and may not be entirely accurate.") --Proj muzzle penetration (Name, Desc) +end + +function Ammo.MenuAction(Menu) + Menu:AddParagraph("Testing AP menu.") +end + +ACF.RegisterAmmoDecal("AP", "damage/ap_pen", "damage/ap_rico") diff --git a/lua/acf/shared/ammo_types/aphe.lua b/lua/acf/shared/ammo_types/aphe.lua new file mode 100644 index 000000000..13665deee --- /dev/null +++ b/lua/acf/shared/ammo_types/aphe.lua @@ -0,0 +1,172 @@ +local Ammo = ACF.RegisterAmmoType("Armor Piercing Explosive", "Armor Piercing") + +function Ammo:OnLoaded() + Ammo.BaseClass.OnLoaded(self) + + self.ID = "APHE" + self.Description = "An armor piercing round with a cavity for High explosives. Less capable of defeating armor than plain Armor Piercing, but will explode after penetration" + self.Blacklist = { "MO", "MG", "SL", "RAC" } +end + +function Ammo.Convert(_, PlayerData) + local Data = {} + local ServerData = {} + local GUIData = {} + + if not PlayerData.PropLength then + PlayerData.PropLength = 0 + end + + if not PlayerData.ProjLength then + PlayerData.ProjLength = 0 + end + + PlayerData.Data5 = math.max(PlayerData.Data5 or 0, 0) + + if not PlayerData.Data10 then + PlayerData.Data10 = 0 + end + + PlayerData, Data, ServerData, GUIData = ACF_RoundBaseGunpowder(PlayerData, Data, ServerData, GUIData) + + Data.ProjMass = math.max(GUIData.ProjVolume - PlayerData.Data5, 0) * 7.9 / 1000 + math.min(PlayerData.Data5, GUIData.ProjVolume) * ACF.HEDensity / 1000 --Volume of the projectile as a cylinder - Volume of the filler * density of steel + Volume of the filler * density of TNT + Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass, Data.Caliber) + local Energy = ACF_Kinetic(Data.MuzzleVel * 39.37, Data.ProjMass, Data.LimitVel) + local MaxVol = ACF_RoundShellCapacity(Energy.Momentum, Data.FrArea, Data.Caliber, Data.ProjLength) + GUIData.MinFillerVol = 0 + GUIData.MaxFillerVol = math.min(GUIData.ProjVolume, MaxVol * 0.9) + GUIData.FillerVol = math.min(PlayerData.Data5, GUIData.MaxFillerVol) + Data.FillerMass = GUIData.FillerVol * ACF.HEDensity / 1000 + Data.ProjMass = math.max(GUIData.ProjVolume - GUIData.FillerVol, 0) * 7.9 / 1000 + Data.FillerMass + Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass, Data.Caliber) + Data.ShovePower = 0.1 + Data.PenArea = Data.FrArea ^ ACF.PenAreaMod + Data.DragCoef = ((Data.FrArea / 10000) / Data.ProjMass) + Data.LimitVel = 700 --Most efficient penetration speed in m/s + Data.KETransfert = 0.1 --Kinetic energy transfert to the target for movement purposes + Data.Ricochet = 65 --Base ricochet angle + Data.BoomPower = Data.PropMass + Data.FillerMass + + --Only the crates need this part + if SERVER then + ServerData.Id = PlayerData.Id + ServerData.Type = PlayerData.Type + + return table.Merge(Data, ServerData) + end + + --Only the GUI needs this part + if CLIENT then + GUIData = table.Merge(GUIData, Ammo.GetDisplayData(Data)) + + return table.Merge(Data, GUIData) + end +end + +function Ammo.Networkd(Crate, BulletData) + Crate:SetNWString("AmmoType", "APHE") + Crate:SetNWString("AmmoID", BulletData.Id) + Crate:SetNWFloat("Caliber", BulletData.Caliber) + Crate:SetNWFloat("ProjMass", BulletData.ProjMass) + Crate:SetNWFloat("FillerMass", BulletData.FillerMass) + Crate:SetNWFloat("PropMass", BulletData.PropMass) + Crate:SetNWFloat("DragCoef", BulletData.DragCoef) + Crate:SetNWFloat("MuzzleVel", BulletData.MuzzleVel) + Crate:SetNWFloat("Tracer", BulletData.Tracer) +end + +function Ammo.GetDisplayData(BulletData) + local Data = Ammo.BaseClass.GetDisplayData(BulletData) + local FragMass = BulletData.ProjMass - BulletData.FillerMass + + Data.BlastRadius = BulletData.FillerMass ^ 0.33 * 8 + Data.Fragments = math.max(math.floor((BulletData.FillerMass / FragMass) * ACF.HEFrag), 2) + Data.FragMass = FragMass / GUIData.Fragments + Data.FragVel = (BulletData.FillerMass * ACF.HEPower * 1000 / GUIData.FragMass / GUIData.Fragments) ^ 0.5 + + return Data +end + +function Ammo.GetCrateText(BulletData) + local Data = Ammo.GetDisplayData(BulletData) + local BaseText = Ammo.BaseClass.GetCrateText(BulletData) + local Text = BaseText .. "\nBlast Radius: %s m\nBlast Energy: %s KJ" + + return Text:format(math.Round(Data.BlastRadius, 2), math.floor(BulletData.FillerMass * ACF.HEPower)) +end + +function Ammo.OnFlightEnd(Index, Bullet, HitPos) + ACF_HE(HitPos - Bullet.Flight:GetNormalized() * 3, Bullet.FillerMass, Bullet.ProjMass - Bullet.FillerMass, Bullet.Owner, nil, Bullet.Gun) + + Ammo.BaseClass.OnFlightEnd(Index, Bullet, Hitpos) +end + +function Ammo.ImpactEffect(_, Bullet) + local Effect = EffectData() + Effect:SetOrigin(Bullet.SimPos) + Effect:SetNormal(Bullet.SimFlight:GetNormalized()) + Effect:SetScale(math.max(Bullet.FillerMass ^ 0.33 * 8 * 39.37, 1)) + Effect:SetRadius(Bullet.Caliber) + + util.Effect("ACF_Explosion", Effect) +end + +function Ammo.CreateMenu(Panel, Table) + acfmenupanel:AmmoSelect(Ammo.Blacklist) + + acfmenupanel:CPanelText("Desc", "") --Description (Name, Desc) + acfmenupanel:CPanelText("LengthDisplay", "") --Total round length (Name, Desc) + acfmenupanel:AmmoSlider("PropLength", 0, 0, 1000, 3, "Propellant Length", "") --Propellant Length Slider (Name, Value, Min, Max, Decimals, Title, Desc) + acfmenupanel:AmmoSlider("ProjLength", 0, 0, 1000, 3, "Projectile Length", "") --Projectile Length Slider (Name, Value, Min, Max, Decimals, Title, Desc) + acfmenupanel:AmmoSlider("FillerVol", 0, 0, 1000, 3, "HE Filler", "") --Hollow Point Cavity Slider (Name, Value, Min, Max, Decimals, Title, Desc) + acfmenupanel:AmmoCheckbox("Tracer", "Tracer", "") --Tracer checkbox (Name, Title, Desc) + acfmenupanel:CPanelText("VelocityDisplay", "") --Proj muzzle velocity (Name, Desc) + acfmenupanel:CPanelText("PenetrationDisplay", "") --Proj muzzle penetration (Name, Desc) + acfmenupanel:CPanelText("BlastDisplay", "") --HE Blast data (Name, Desc) + acfmenupanel:CPanelText("FragDisplay", "") --HE Fragmentation data (Name, Desc) + acfmenupanel:CPanelText("PenetrationRanging", "") --penetration ranging (Name, Desc) + + Ammo.UpdateMenu(Panel, Table) +end + +function Ammo.UpdateMenu(Panel) + local PlayerData = { + Id = acfmenupanel.AmmoData.Data.id, --AmmoSelect GUI + Type = "APHE", --Hardcoded, match ACFRoundTypes table index + PropLength = acfmenupanel.AmmoData.PropLength, --PropLength slider + ProjLength = acfmenupanel.AmmoData.ProjLength, --ProjLength slider + Data5 = acfmenupanel.AmmoData.FillerVol, + Data10 = acfmenupanel.AmmoData.Tracer and 1 or 0, + } + + local Data = Ammo.Convert(Panel, PlayerData) + + RunConsoleCommand("acfmenu_data1", acfmenupanel.AmmoData.Data.id) + RunConsoleCommand("acfmenu_data2", PlayerData.Type) + RunConsoleCommand("acfmenu_data3", Data.PropLength) --For Gun ammo, Data3 should always be Propellant + RunConsoleCommand("acfmenu_data4", Data.ProjLength) --And Data4 total round mass + RunConsoleCommand("acfmenu_data5", Data.FillerVol) + RunConsoleCommand("acfmenu_data10", Data.Tracer) + + acfmenupanel:AmmoSlider("PropLength", Data.PropLength, Data.MinPropLength, Data.MaxTotalLength, 3, "Propellant Length", "Propellant Mass : " .. (math.floor(Data.PropMass * 1000)) .. " g") --Propellant Length Slider (Name, Min, Max, Decimals, Title, Desc) + acfmenupanel:AmmoSlider("ProjLength", Data.ProjLength, Data.MinProjLength, Data.MaxTotalLength, 3, "Projectile Length", "Projectile Mass : " .. (math.floor(Data.ProjMass * 1000)) .. " g") --Projectile Length Slider (Name, Min, Max, Decimals, Title, Desc) + acfmenupanel:AmmoSlider("FillerVol", Data.FillerVol, Data.MinFillerVol, Data.MaxFillerVol, 3, "HE Filler Volume", "HE Filler Mass : " .. (math.floor(Data.FillerMass * 1000)) .. " g") --HE Filler Slider (Name, Min, Max, Decimals, Title, Desc) + acfmenupanel:AmmoCheckbox("Tracer", "Tracer : " .. (math.floor(Data.Tracer * 10) / 10) .. "cm\n", "") --Tracer checkbox (Name, Title, Desc) + acfmenupanel:CPanelText("Desc", Ammo.Description) --Description (Name, Desc) + acfmenupanel:CPanelText("LengthDisplay", "Round Length : " .. (math.floor((Data.PropLength + Data.ProjLength + Data.Tracer) * 100) / 100) .. "/" .. Data.MaxTotalLength .. " cm") --Total round length (Name, Desc) + acfmenupanel:CPanelText("VelocityDisplay", "Muzzle Velocity : " .. math.floor(Data.MuzzleVel * ACF.Scale) .. " m/s") --Proj muzzle velocity (Name, Desc) + acfmenupanel:CPanelText("PenetrationDisplay", "Maximum Penetration : " .. math.floor(Data.MaxPen) .. " mm RHA") --Proj muzzle penetration (Name, Desc) + acfmenupanel:CPanelText("BlastDisplay", "Blast Radius : " .. (math.floor(Data.BlastRadius * 100) / 100) .. " m") --Proj muzzle velocity (Name, Desc) + acfmenupanel:CPanelText("FragDisplay", "Fragments : " .. Data.Fragments .. "\n Average Fragment Weight : " .. (math.floor(Data.FragMass * 10000) / 10) .. " g \n Average Fragment Velocity : " .. math.floor(Data.FragVel) .. " m/s") --Proj muzzle penetration (Name, Desc) + + local R1V, R1P = ACF_PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 300) + local R2V, R2P = ACF_PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 800) + + acfmenupanel:CPanelText("PenetrationRanging", "\n300m pen: " .. math.Round(R1P, 0) .. "mm @ " .. math.Round(R1V, 0) .. " m/s\n800m pen: " .. math.Round(R2P, 0) .. "mm @ " .. math.Round(R2V, 0) .. " m/s\n\nThe range data is an approximation and may not be entirely accurate.") --Proj muzzle penetration (Name, Desc) +end + +function Ammo.MenuAction(Menu) + Menu:AddParagraph("Testing APHE menu.") +end + +ACF.RegisterAmmoDecal("APHE", "damage/ap_pen", "damage/ap_rico") diff --git a/lua/acf/shared/ammo_types/fl.lua b/lua/acf/shared/ammo_types/fl.lua new file mode 100644 index 000000000..2c55f3c17 --- /dev/null +++ b/lua/acf/shared/ammo_types/fl.lua @@ -0,0 +1,241 @@ +local Ammo = ACF.RegisterAmmoType("Flechette", "Armor Piercing") + +function Ammo:OnLoaded() + Ammo.BaseClass.OnLoaded(self) + + self.ID = "FL" + self.Model = "models/munitions/dart_100mm.mdl" + self.Description = "Flechette rounds contain several long thin steel spikes, functioning as a shotgun shell for cannons. While it seems like the spikes would penetrate well, they tend to tumble in flight and impact at less than ideal angles, causing only minor penetration and structural damage. They are best used against infantry or lightly armored mobile targets such as aircraft or light tanks, since flechettes trade brute damage for a better chance to hit." + self.Blacklist = { "AC", "RAC", "MG", "HMG", "GL", "SL" } +end + +function Ammo.Create(Gun, BulletData) + local FlechetteData = { + Caliber = math.Round(BulletData.FlechetteRadius * 0.2, 2), + Id = BulletData.Id, + Type = "AP", + Owner = BulletData.Owner, + Crate = BulletData.Crate, + Gun = BulletData.Gun, + Pos = BulletData.Pos, + FrArea = BulletData.FlechetteArea, + ProjMass = BulletData.FlechetteMass, + DragCoef = BulletData.FlechetteDragCoef, + Tracer = BulletData.Tracer, + LimitVel = BulletData.LimitVel, + Ricochet = BulletData.Ricochet, + PenArea = BulletData.FlechettePenArea, + ShovePower = BulletData.ShovePower, + KETransfert = BulletData.KETransfert, + } + + --if ammo is cooking off, shoot in random direction + if Gun:GetClass() == "acf_ammo" then + local MuzzleVec = VectorRand() + + for _ = 1, BulletData.Flechettes do + local Inaccuracy = VectorRand() / 360 * ((Gun.Spread or 0) + BulletData.FlechetteSpread) + + FlechetteData.Flight = (MuzzleVec + Inaccuracy):GetNormalized() * BulletData.MuzzleVel * 39.37 + Gun:GetVelocity() + + ACF_CreateBullet(FlechetteData) + end + else + local BaseInaccuracy = math.tan(math.rad(Gun:GetSpread())) + local AddInaccuracy = math.tan(math.rad(BulletData.FlechetteSpread)) + local MuzzleVec = Gun:GetForward() + + for _ = 1, BulletData.Flechettes do + local BaseInaccuracyMult = (math.random() ^ (1 / math.Clamp(ACF.GunInaccuracyBias, 0.5, 4))) * (Gun:GetUp() * (2 * math.random() - 1) + Gun:GetRight() * (2 * math.random() - 1)):GetNormalized() + local AddSpreadMult = (math.random() ^ (1 / math.Clamp(ACF.GunInaccuracyBias, 0.5, 4))) * (Gun:GetUp() * (2 * math.random() - 1) + Gun:GetRight() * (2 * math.random() - 1)):GetNormalized() + + BaseSpread = BaseInaccuracy * BaseInaccuracyMult + AddSpread = AddInaccuracy * AddSpreadMult + + FlechetteData.Flight = (MuzzleVec + BaseSpread + AddSpread):GetNormalized() * BulletData.MuzzleVel * 39.37 + Gun:GetVelocity() + + ACF_CreateBullet(FlechetteData) + end + end +end + +function Ammo.Convert(_, PlayerData) + local ServerData = {} + local GUIData = {} + local Data = { + LengthAdj = 0.5 + } + + if not PlayerData.PropLength then + PlayerData.PropLength = 0 + end + + if not PlayerData.ProjLength then + PlayerData.ProjLength = 0 + end + + --flechette count + if not PlayerData.Data5 then + PlayerData.Data5 = 3 + end + + --flechette spread + if not PlayerData.Data6 then + PlayerData.Data6 = 5 + end + + --tracer + if not PlayerData.Data10 then + PlayerData.Data10 = 0 + end + + PlayerData, Data, ServerData, GUIData = ACF_RoundBaseGunpowder(PlayerData, Data, ServerData, GUIData) + + local GunClass = ACF.Weapons.Guns[Data.Id or PlayerData.Id].gunclass + + if GunClass == "SA" then + Data.MaxFlechettes = math.Clamp(math.floor(Data.Caliber * 3 - 4.5), 1, 32) + elseif GunClass == "MO" then + Data.MaxFlechettes = math.Clamp(math.floor(Data.Caliber * 4) - 12, 1, 32) + elseif GunClass == "HW" then + Data.MaxFlechettes = math.Clamp(math.floor(Data.Caliber * 4) - 10, 1, 32) + else + Data.MaxFlechettes = math.Clamp(math.floor(Data.Caliber * 4) - 8, 1, 32) + end + + local PenAdj = 0.8 --higher means lower pen, but more structure (hp) damage (old: 2.35, 2.85) + local RadiusAdj = 1.0 -- lower means less structure (hp) damage, but higher pen (old: 1.0, 0.8) + + Data.MinFlechettes = math.min(6, Data.MaxFlechettes) --force bigger guns to have higher min count + Data.Flechettes = math.Clamp(math.floor(PlayerData.Data5), Data.MinFlechettes, Data.MaxFlechettes) --number of flechettes + Data.MinSpread = 0.25 + Data.MaxSpread = 30 + Data.FlechetteSpread = math.Clamp(tonumber(PlayerData.Data6), Data.MinSpread, Data.MaxSpread) + + local PackRatio = 0.0025 * Data.Flechettes + 0.69 --how efficiently flechettes are packed into shell + + Data.FlechetteRadius = math.sqrt(((PackRatio * RadiusAdj * Data.Caliber * 0.5) ^ 2) / Data.Flechettes) -- max radius flechette can be, to fit number of flechettes in a shell + Data.FlechetteArea = 3.1416 * Data.FlechetteRadius ^ 2 -- area of a single flechette + Data.FlechetteMass = Data.FlechetteArea * (Data.ProjLength * 7.9 / 1000) -- volume of single flechette * density of steel + Data.FlechettePenArea = (PenAdj * Data.FlechetteArea) ^ ACF.PenAreaMod + Data.FlechetteDragCoef = (Data.FlechetteArea / 10000) / Data.FlechetteMass + Data.ProjMass = Data.Flechettes * Data.FlechetteMass -- total mass of all flechettes + Data.PropMass = Data.PropMass + Data.ShovePower = 0.2 + Data.PenArea = Data.FrArea ^ ACF.PenAreaMod + Data.DragCoef = ((Data.FrArea / 10000) / Data.ProjMass) + Data.LimitVel = 500 --Most efficient penetration speed in m/s + Data.KETransfert = 0.1 --Kinetic energy transfert to the target for movement purposes + Data.Ricochet = 75 --Base ricochet angle + Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass, Data.Caliber) + Data.BoomPower = Data.PropMass + + --Only the crates need this part + if SERVER then + ServerData.Id = PlayerData.Id + ServerData.Type = PlayerData.Type + + return table.Merge(Data, ServerData) + end + + --Only the GUI needs this part + if CLIENT then + GUIData = table.Merge(GUIData, Ammo.GetDisplayData(Data)) + + return table.Merge(Data, GUIData) + end +end + +function Ammo.Network(Crate, BulletData) + Crate:SetNWString("AmmoType", "FL") + Crate:SetNWString("AmmoID", BulletData.Id) + Crate:SetNWFloat("PropMass", BulletData.PropMass) + Crate:SetNWFloat("MuzzleVel", BulletData.MuzzleVel) + Crate:SetNWFloat("Tracer", BulletData.Tracer) + Crate:SetNWFloat("Caliber", math.Round(BulletData.FlechetteRadius * 0.2, 2)) + Crate:SetNWFloat("ProjMass", BulletData.FlechetteMass) + Crate:SetNWFloat("DragCoef", BulletData.FlechetteDragCoef) + Crate:SetNWFloat("FillerMass", 0) +end + +function Ammo.GetDisplayData(BulletData) + local Energy = ACF_Kinetic(BulletData.MuzzleVel * 39.37, BulletData.FlechetteMass, BulletData.LimitVel) + + return { + MaxPen = (Energy.Penetration / BulletData.FlechettePenArea) * ACF.KEtoRHA + } +end + + +function Ammo.GetCrateText(BulletData) + local Text = "Muzzle Velocity: %s m/s\nMax Penetration: %s mm\nMax Spread: %s degrees" + local Data = Ammo.GetDisplayData(BulletData) + local Gun = ACF.Weapons.Guns[BulletData.Id] + local Spread = 0 + + if Gun then + local GunClass = ACF.Classes.GunClass[Gun.gunclass] + + Spread = GunClass and (GunClass.spread * ACF.GunInaccuracyScale) or 0 + end + + return Text:format(math.Round(BulletData.MuzzleVel, 2), math.floor(Data.MaxPen), math.ceil((BulletData.FlechetteSpread + Spread) * 10) * 0.1) +end + +function Ammo.CreateMenu(Panel, Table) + acfmenupanel:AmmoSelect(Ammo.Blacklist) + + acfmenupanel:CPanelText("Desc", "") --Description (Name, Desc) + acfmenupanel:CPanelText("LengthDisplay", "") --Total round length (Name, Desc) + acfmenupanel:AmmoSlider("PropLength", 0, 0, 1000, 3, "Propellant Length", "") --Propellant Length Slider (Name, Value, Min, Max, Decimals, Title, Desc) + acfmenupanel:AmmoSlider("ProjLength", 0, 0, 1000, 3, "Projectile Length", "") --Projectile Length Slider (Name, Value, Min, Max, Decimals, Title, Desc) + acfmenupanel:AmmoSlider("Flechettes", 3, 3, 32, 0, "Flechettes", "") --flechette count Slider (Name, Value, Min, Max, Decimals, Title, Desc) + acfmenupanel:AmmoSlider("FlechetteSpread", 10, 5, 60, 1, "Flechette Spread", "") --flechette spread Slider (Name, Value, Min, Max, Decimals, Title, Desc) + acfmenupanel:AmmoCheckbox("Tracer", "Tracer", "") --Tracer checkbox (Name, Title, Desc) + acfmenupanel:CPanelText("VelocityDisplay", "") --Proj muzzle velocity (Name, Desc) + acfmenupanel:CPanelText("PenetrationDisplay", "") --Proj muzzle penetration (Name, Desc) + + Ammo.UpdateMenu(Panel, Table) +end + +function Ammo.UpdateMenu(Panel) + local PlayerData = { + Id = acfmenupanel.AmmoData.Data.id, --AmmoSelect GUI + Type = "FL", --Hardcoded, match ACFRoundTypes table index + PropLength = acfmenupanel.AmmoData.PropLength, --PropLength slider + ProjLength = acfmenupanel.AmmoData.ProjLength, --ProjLength slider + Data5 = acfmenupanel.AmmoData.Flechettes, --Flechette count slider + Data6 = acfmenupanel.AmmoData.FlechetteSpread, --flechette spread slider + Data10 = acfmenupanel.AmmoData.Tracer and 1 or 0 -- Tracer + } + + local Data = Ammo.Convert(Panel, PlayerData) + + RunConsoleCommand("acfmenu_data1", acfmenupanel.AmmoData.Data.id) + RunConsoleCommand("acfmenu_data2", PlayerData.Type) + RunConsoleCommand("acfmenu_data3", Data.PropLength) --For Gun ammo, Data3 should always be Propellant + RunConsoleCommand("acfmenu_data4", Data.ProjLength) --And Data4 total round mass + RunConsoleCommand("acfmenu_data5", Data.Flechettes) + RunConsoleCommand("acfmenu_data6", Data.FlechetteSpread) + RunConsoleCommand("acfmenu_data10", Data.Tracer) + + acfmenupanel:AmmoSlider("PropLength", Data.PropLength, Data.MinPropLength, Data.MaxTotalLength, 3, "Propellant Length", "Propellant Mass : " .. (math.floor(Data.PropMass * 1000)) .. " g") --Propellant Length Slider (Name, Min, Max, Decimals, Title, Desc) + acfmenupanel:AmmoSlider("ProjLength", Data.ProjLength, Data.MinProjLength, Data.MaxTotalLength, 3, "Projectile Length", "Projectile Mass : " .. (math.floor(Data.ProjMass * 1000)) .. " g") --Projectile Length Slider (Name, Min, Max, Decimals, Title, Desc) + acfmenupanel:AmmoSlider("Flechettes", Data.Flechettes, Data.MinFlechettes, Data.MaxFlechettes, 0, "Flechettes", "Flechette Radius: " .. math.Round(Data.FlechetteRadius * 10, 2) .. " mm") + acfmenupanel:AmmoSlider("FlechetteSpread", Data.FlechetteSpread, Data.MinSpread, Data.MaxSpread, 1, "Flechette Spread", "") + acfmenupanel:AmmoCheckbox("Tracer", "Tracer : " .. (math.floor(Data.Tracer * 10) / 10) .. "cm\n", "") --Tracer checkbox (Name, Title, Desc) + acfmenupanel:CPanelText("Desc", Ammo.Description) --Description (Name, Desc) + acfmenupanel:CPanelText("LengthDisplay", "Round Length : " .. (math.floor((Data.PropLength + Data.ProjLength + Data.Tracer) * 100) / 100) .. "/" .. Data.MaxTotalLength .. " cm") --Total round length (Name, Desc) + acfmenupanel:CPanelText("VelocityDisplay", "Muzzle Velocity : " .. math.floor(Data.MuzzleVel * ACF.Scale) .. " m/s") --Proj muzzle velocity (Name, Desc) + + local R1V, R1P = ACF_PenRanging(Data.MuzzleVel, Data.FlechetteDragCoef, Data.FlechetteMass, Data.FlechettePenArea, Data.LimitVel, 300) + local R2V, R2P = ACF_PenRanging(Data.MuzzleVel, Data.FlechetteDragCoef, Data.FlechetteMass, Data.FlechettePenArea, Data.LimitVel, 800) + + acfmenupanel:CPanelText("PenetrationDisplay", "Maximum Penetration : " .. math.floor(Data.MaxPen) .. " mm RHA\n\n300m pen: " .. math.Round(R1P, 0) .. "mm @ " .. math.Round(R1V, 0) .. " m\\s\n800m pen: " .. math.Round(R2P, 0) .. "mm @ " .. math.Round(R2V, 0) .. " m\\s\n\nThe range data is an approximation and may not be entirely accurate.") --Proj muzzle penetration (Name, Desc) +end + +function Ammo.MenuAction(Menu) + Menu:AddParagraph("Testing FL menu.") +end + +ACF.RegisterAmmoDecal("FL", "damage/ap_pen", "damage/ap_rico") \ No newline at end of file diff --git a/lua/acf/shared/ammo_types/he.lua b/lua/acf/shared/ammo_types/he.lua new file mode 100644 index 000000000..3702b41d6 --- /dev/null +++ b/lua/acf/shared/ammo_types/he.lua @@ -0,0 +1,166 @@ +local Ammo = ACF.RegisterAmmoType("High Explosive", "Armor Piercing Explosive") + +function Ammo:OnLoaded() + Ammo.BaseClass.OnLoaded(self) + + self.ID = "HE" + self.Description = "A shell filled with explosives, detonating on impact." + self.Blacklist = { "MG", "RAC" } +end + +function Ammo.Convert(_, PlayerData) + local Data = {} + local ServerData = {} + local GUIData = {} + + if not PlayerData.PropLength then + PlayerData.PropLength = 0 + end + + if not PlayerData.ProjLength then + PlayerData.ProjLength = 0 + end + + PlayerData.Data5 = math.max(PlayerData.Data5 or 0, 0) + + if not PlayerData.Data10 then + PlayerData.Data10 = 0 + end + + PlayerData, Data, ServerData, GUIData = ACF_RoundBaseGunpowder(PlayerData, Data, ServerData, GUIData) + + Data.ProjMass = math.max(GUIData.ProjVolume - PlayerData.Data5, 0) * 7.9 / 1000 + math.min(PlayerData.Data5, GUIData.ProjVolume) * ACF.HEDensity / 1000 --Volume of the projectile as a cylinder - Volume of the filler * density of steel + Volume of the filler * density of TNT + Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass, Data.Caliber) + + local Energy = ACF_Kinetic(Data.MuzzleVel * 39.37, Data.ProjMass, Data.LimitVel) + local MaxVol = ACF_RoundShellCapacity(Energy.Momentum, Data.FrArea, Data.Caliber, Data.ProjLength) + + GUIData.MinFillerVol = 0 + GUIData.MaxFillerVol = math.min(GUIData.ProjVolume, MaxVol) + GUIData.FillerVol = math.min(PlayerData.Data5, GUIData.MaxFillerVol) + Data.FillerMass = GUIData.FillerVol * ACF.HEDensity / 1000 + Data.ProjMass = math.max(GUIData.ProjVolume - GUIData.FillerVol, 0) * 7.9 / 1000 + Data.FillerMass + Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass, Data.Caliber) + Data.ShovePower = 0.1 + Data.PenArea = Data.FrArea ^ ACF.PenAreaMod + Data.DragCoef = ((Data.FrArea / 10000) / Data.ProjMass) + Data.LimitVel = 100 --Most efficient penetration speed in m/s + Data.KETransfert = 0.1 --Kinetic energy transfert to the target for movement purposes + Data.Ricochet = 60 --Base ricochet angle + Data.DetonatorAngle = 80 + Data.BoomPower = Data.PropMass + Data.FillerMass + Data.CanFuze = Data.Caliber > 2 -- Can fuze on calibers > 20mm + + --Only the crates need this part + if SERVER then + ServerData.Id = PlayerData.Id + ServerData.Type = PlayerData.Type + + return table.Merge(Data, ServerData) + end + + --Only the GUI needs this part + if CLIENT then + GUIData = table.Merge(GUIData, Ammo.GetDisplayData(Data)) + + return table.Merge(Data, GUIData) + end +end + +function Ammo.Network(Crate, BulletData) + Crate:SetNWString("AmmoType", "HE") + Crate:SetNWString("AmmoID", BulletData.Id) + Crate:SetNWFloat("Caliber", BulletData.Caliber) + Crate:SetNWFloat("ProjMass", BulletData.ProjMass) + Crate:SetNWFloat("FillerMass", BulletData.FillerMass) + Crate:SetNWFloat("PropMass", BulletData.PropMass) + Crate:SetNWFloat("DragCoef", BulletData.DragCoef) + Crate:SetNWFloat("MuzzleVel", BulletData.MuzzleVel) + Crate:SetNWFloat("Tracer", BulletData.Tracer) +end + +function Ammo.GetDisplayData(Data) + local FragMass = Data.ProjMass - Data.FillerMass + + return { + BlastRadius = Data.FillerMass ^ 0.33 * 8, + Fragments = math.max(math.floor((Data.FillerMass / FragMass) * ACF.HEFrag), 2), + FragMass = FragMass / GUIData.Fragments, + FragVel = (Data.FillerMass * ACF.HEPower * 1000 / GUIData.FragMass / GUIData.Fragments) ^ 0.5, + } +end + +function Ammo.GetCrateText(BulletData) + local Text = "Muzzle Velocity: %s m/s\nBlast Radius: %s m\nBlast Energy: %s KJ" + local Data = Ammo.GetDisplayData(BulletData) + + return Text:format(math.Round(BulletData.MuzzleVel, 2), math.Round(Data.BlastRadius, 2), math.floor(BulletData.FillerMass * ACF.HEPower)) +end + +function Ammo.PropImpact(_, Bullet, Target, HitNormal, HitPos, Bone) + if ACF_Check(Target) then + local Speed = Bullet.Flight:Length() / ACF.Scale + local Energy = ACF_Kinetic(Speed, Bullet.ProjMass - Bullet.FillerMass, Bullet.LimitVel) + local HitRes = ACF_RoundImpact(Bullet, Speed, Energy, Target, HitPos, HitNormal, Bone) + + if HitRes.Ricochet then return "Ricochet" end + end + + return false +end + +function Ammo.WorldImpact() + return false +end + +function Ammo.CreateMenu(Panel, Table) + acfmenupanel:AmmoSelect(Ammo.Blacklist) + + acfmenupanel:CPanelText("Desc", "") --Description (Name, Desc) + acfmenupanel:CPanelText("LengthDisplay", "") --Total round length (Name, Desc) + acfmenupanel:AmmoSlider("PropLength", 0, 0, 1000, 3, "Propellant Length", "") --Slider (Name, Value, Min, Max, Decimals, Title, Desc) + acfmenupanel:AmmoSlider("ProjLength", 0, 0, 1000, 3, "Projectile Length", "") --Slider (Name, Value, Min, Max, Decimals, Title, Desc) + acfmenupanel:AmmoSlider("FillerVol", 0, 0, 1000, 3, "HE Filler", "") --Slider (Name, Value, Min, Max, Decimals, Title, Desc) + acfmenupanel:AmmoCheckbox("Tracer", "Tracer", "") --Tracer checkbox (Name, Title, Desc) + acfmenupanel:CPanelText("VelocityDisplay", "") --Proj muzzle velocity (Name, Desc) + acfmenupanel:CPanelText("BlastDisplay", "") --HE Blast data (Name, Desc) + acfmenupanel:CPanelText("FragDisplay", "") --HE Fragmentation data (Name, Desc) + + Ammo.UpdateMenu(Panel, Table) +end + +function Ammo.UpdateMenu(Panel) + local PlayerData = { + Id = acfmenupanel.AmmoData.Data.id, --AmmoSelect GUI + Type = "HE", --Hardcoded, match ACFRoundTypes table index + PropLength = acfmenupanel.AmmoData.PropLength, --PropLength slider + ProjLength = acfmenupanel.AmmoData.ProjLength, --ProjLength slider + Data5 = acfmenupanel.AmmoData.FillerVol, + Data10 = acfmenupanel.AmmoData.Tracer and 1 or 0, --Tracer + } + + local Data = Ammo.Convert(Panel, PlayerData) + + RunConsoleCommand("acfmenu_data1", acfmenupanel.AmmoData.Data.id) + RunConsoleCommand("acfmenu_data2", PlayerData.Type) + RunConsoleCommand("acfmenu_data3", Data.PropLength) --For Gun ammo, Data3 should always be Propellant + RunConsoleCommand("acfmenu_data4", Data.ProjLength) --And Data4 total round mass + RunConsoleCommand("acfmenu_data5", Data.FillerVol) + RunConsoleCommand("acfmenu_data10", Data.Tracer) + + acfmenupanel:AmmoSlider("PropLength", Data.PropLength, Data.MinPropLength, Data.MaxTotalLength, 3, "Propellant Length", "Propellant Mass : " .. (math.floor(Data.PropMass * 1000)) .. " g") --Propellant Length Slider (Name, Min, Max, Decimals, Title, Desc) + acfmenupanel:AmmoSlider("ProjLength", Data.ProjLength, Data.MinProjLength, Data.MaxTotalLength, 3, "Projectile Length", "Projectile Mass : " .. (math.floor(Data.ProjMass * 1000)) .. " g") --Projectile Length Slider (Name, Min, Max, Decimals, Title, Desc) + acfmenupanel:AmmoSlider("FillerVol", Data.FillerVol, Data.MinFillerVol, Data.MaxFillerVol, 3, "HE Filler Volume", "HE Filler Mass : " .. (math.floor(Data.FillerMass * 1000)) .. " g") --HE Filler Slider (Name, Min, Max, Decimals, Title, Desc) + acfmenupanel:AmmoCheckbox("Tracer", "Tracer : " .. (math.floor(Data.Tracer * 10) / 10) .. "cm\n", "") --Tracer checkbox (Name, Title, Desc) + acfmenupanel:CPanelText("Desc", Ammo.Description) --Description (Name, Desc) + acfmenupanel:CPanelText("LengthDisplay", "Round Length : " .. (math.floor((Data.PropLength + Data.ProjLength + Data.Tracer) * 100) / 100) .. "/" .. Data.MaxTotalLength .. " cm") --Total round length (Name, Desc) + acfmenupanel:CPanelText("VelocityDisplay", "Muzzle Velocity : " .. math.floor(Data.MuzzleVel * ACF.Scale) .. " m/s") --Proj muzzle velocity (Name, Desc) + acfmenupanel:CPanelText("BlastDisplay", "Blast Radius : " .. (math.floor(Data.BlastRadius * 100) / 100) .. " m") --Proj muzzle velocity (Name, Desc) + acfmenupanel:CPanelText("FragDisplay", "Fragments : " .. Data.Fragments .. "\n Average Fragment Weight : " .. (math.floor(Data.FragMass * 10000) / 10) .. " g \n Average Fragment Velocity : " .. math.floor(Data.FragVel) .. " m/s") --Proj muzzle penetration (Name, Desc) +end + +function Ammo.MenuAction(Menu) + Menu:AddParagraph("Testing HE menu.") +end + +ACF.RegisterAmmoDecal("HE", "damage/he_pen", "damage/he_rico") diff --git a/lua/acf/shared/ammo_types/heat.lua b/lua/acf/shared/ammo_types/heat.lua new file mode 100644 index 000000000..52b330867 --- /dev/null +++ b/lua/acf/shared/ammo_types/heat.lua @@ -0,0 +1,374 @@ +local Ammo = ACF.RegisterAmmoType("High Explosive Anti-Tank", "Armor Piercing") +local DecalIndex = ACF.GetAmmoDecalIndex + +function Ammo:OnLoaded() + Ammo.BaseClass.OnLoaded(self) + + self.ID = "HEAT" + self.Description = "A shell with a shaped charge. When the round detonates, the explosive energy is focused into driving a small molten metal penetrator into the victim with extreme force, though this results in reduced damage from the explosion itself. Multiple layers of armor will dissipate the penetrator quickly." + self.Blacklist = { "MG", "HMG", "RAC", "AC", "SL", "SB" } +end + +function Ammo.ConeCalc(ConeAngle, Radius) + local ConeLength = math.tan(math.rad(ConeAngle)) * Radius + local ConeArea = 3.1416 * Radius * (Radius ^ 2 + ConeLength ^ 2) ^ 0.5 + local ConeVol = (3.1416 * Radius ^ 2 * ConeLength) / 3 + + return ConeLength, ConeArea, ConeVol +end + +-- calculates conversion of filler from powering HEAT jet to raw HE based on crush vel +-- above a threshold vel, HEAT jet doesn't have time to form properly, converting to raw HE proportionally +-- Vel needs to be in m/s (gmu*0.0254) +function Ammo.CrushCalc(Vel, FillerMass) + local Crushed = math.Clamp((Vel - ACF.HEATMinCrush) / (ACF.HEATMaxCrush - ACF.HEATMinCrush), 0, 1) + local HE_Filler = Lerp(Crushed, FillerMass * ACF.HEATBoomConvert, FillerMass) + local HEAT_Filler = Lerp(Crushed, FillerMass, 0) + + return Crushed, HEAT_Filler, HE_Filler +end + +-- coneang now required for slug recalculation at detonation, defaults to 55 if not present +function Ammo.CalcSlugMV(Data, HEATFillerMass) + --keep fillermass/2 so that penetrator stays the same. + return (HEATFillerMass / 2 * ACF.HEPower * math.sin(math.rad(10 + (Data.ConeAng or 55)) / 2) / Data.SlugMass) ^ ACF.HEATMVScale +end + +function Ammo.Convert(_, PlayerData) + local Data = {} + local ServerData = {} + local GUIData = {} + + if not PlayerData.PropLength then + PlayerData.PropLength = 0 + end + + if not PlayerData.ProjLength then + PlayerData.ProjLength = 0 + end + + PlayerData.Data5 = math.max(PlayerData.Data5 or 0, 0) + + if not PlayerData.Data6 then + PlayerData.Data6 = 0 + end + + if not PlayerData.Data7 then + PlayerData.Data7 = 0 + end + + if not PlayerData.Data10 then + PlayerData.Data10 = 0 + end + + PlayerData, Data, ServerData, GUIData = ACF_RoundBaseGunpowder(PlayerData, Data, ServerData, GUIData) + + local _, ConeArea, AirVol = Ammo.ConeCalc(PlayerData.Data6, Data.Caliber / 2, PlayerData.ProjLength) + local ConeThick = Data.Caliber / 50 + + Data.ProjMass = math.max(GUIData.ProjVolume - PlayerData.Data5, 0) * 7.9 / 1000 + math.min(PlayerData.Data5, GUIData.ProjVolume) * ACF.HEDensity / 1000 + ConeArea * ConeThick * 7.9 / 1000 --Volume of the projectile as a cylinder - Volume of the filler - Volume of the crush cone * density of steel + Volume of the filler * density of TNT + Area of the cone * thickness * density of steel + Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass, Data.Caliber) + + local Energy = ACF_Kinetic(Data.MuzzleVel * 39.37, Data.ProjMass, Data.LimitVel) + local MaxVol = ACF_RoundShellCapacity(Energy.Momentum, Data.FrArea, Data.Caliber, Data.ProjLength) + + GUIData.MinConeAng = 0 + GUIData.MaxConeAng = math.deg(math.atan((Data.ProjLength - ConeThick) / (Data.Caliber * 0.5))) + + Data.ConeAng = math.Clamp(PlayerData.Data6 * 1, GUIData.MinConeAng, GUIData.MaxConeAng) + + _, ConeArea, AirVol = Ammo.ConeCalc(Data.ConeAng, Data.Caliber / 2, Data.ProjLength) + + local ConeVol = ConeArea * ConeThick + + GUIData.MinFillerVol = 0 + GUIData.MaxFillerVol = math.max(MaxVol - AirVol - ConeVol, GUIData.MinFillerVol) + GUIData.FillerVol = math.Clamp(PlayerData.Data5 * 1, GUIData.MinFillerVol, GUIData.MaxFillerVol) + + -- fillermass used for shell mass calcs + -- heatfillermass is how much fillermass is used to power heat jet + -- boomfillermass is how much fillermass creates HE damage on detonation. technically get 1/3 extra fillermass free as HE with no crushing, but screw trying to rebalance heat pen to properly use 1/3 of filler for HE and 2/3 for jet + -- distribution of heat and boom fillermass is calculated at detonation, or for GUI stuff + Data.FillerMass = GUIData.FillerVol * ACF.HEDensity / 1450 + Data.ProjMass = math.max(GUIData.ProjVolume - GUIData.FillerVol - AirVol - ConeVol, 0) * 7.9 / 1000 + Data.FillerMass + ConeVol * 7.9 / 1000 + Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass, Data.Caliber) + + --Let's calculate the actual HEAT slug + local Rad = math.rad(Data.ConeAng / 2) + + Data.SlugMass = ConeVol * 7.9 / 1000 + Data.SlugCaliber = Data.Caliber - Data.Caliber * (math.sin(Rad) * 0.5 + math.cos(Rad) * 1.5) * 0.5 + + local SlugFrArea = 3.1416 * (Data.SlugCaliber * 0.5) ^ 2 + + Data.SlugPenArea = SlugFrArea ^ ACF.PenAreaMod + Data.SlugDragCoef = ((SlugFrArea / 10000) / Data.SlugMass) + Data.SlugRicochet = 500 --Base ricochet angle (The HEAT slug shouldn't ricochet at all) + + -- these are only for compatibility with other stuff. it's recalculated when the round is detonated + local _, HEATFiller, BoomFiller = Ammo.CrushCalc(Data.MuzzleVel, Data.FillerMass) + + Data.BoomFillerMass = BoomFiller + Data.SlugMV = Ammo.CalcSlugMV(Data, HEATFiller) + Data.CasingMass = Data.ProjMass - Data.FillerMass - ConeVol * 7.9 / 1000 + Data.ShovePower = 0.1 + Data.PenArea = Data.FrArea ^ ACF.PenAreaMod + Data.DragCoef = ((Data.FrArea / 10000) / Data.ProjMass) + Data.LimitVel = 100 --Most efficient penetration speed in m/s + Data.KETransfert = 0.1 --Kinetic energy transfert to the target for movement purposes + Data.Ricochet = 60 --Base ricochet angle + Data.DetonatorAngle = 75 + Data.Detonated = false + Data.NotFirstPen = false + Data.CanFuze = Data.Caliber > 2 -- Can fuze on calibers > 20mm + + --Only the crates need this part + if SERVER then + ServerData.Id = PlayerData.Id + ServerData.Type = PlayerData.Type + + return table.Merge(Data, ServerData) + end + + --Only the GUI needs this part + if CLIENT then + GUIData = table.Merge(GUIData, Ammo.GetDisplayData(Data)) + + return table.Merge(Data, GUIData) + end +end + +function Ammo.Network(Crate, BulletData) + Crate:SetNWString("AmmoType", "HEAT") + Crate:SetNWString("AmmoID", BulletData.Id) + Crate:SetNWFloat("Caliber", BulletData.Caliber) + Crate:SetNWFloat("ProjMass", BulletData.ProjMass) + Crate:SetNWFloat("FillerMass", BulletData.FillerMass) + Crate:SetNWFloat("PropMass", BulletData.PropMass) + Crate:SetNWFloat("DragCoef", BulletData.DragCoef) + Crate:SetNWFloat("SlugMass", BulletData.SlugMass) + Crate:SetNWFloat("SlugCaliber", BulletData.SlugCaliber) + Crate:SetNWFloat("SlugDragCoef", BulletData.SlugDragCoef) + Crate:SetNWFloat("MuzzleVel", BulletData.MuzzleVel) + Crate:SetNWFloat("Tracer", BulletData.Tracer) +end + +function Ammo.GetDisplayData(Data) + local Crushed, HEATFiller, BoomFiller = Ammo.CrushCalc(Data.MuzzleVel, Data.FillerMass) + local SlugMV = Ammo.CalcSlugMV(Data, HEATFiller) * (Data.SlugPenMul or 1) + local MassUsed = Data.SlugMass * (1 - Crushed) + local Energy = ACF_Kinetic(Data.MuzzleVel * 39.37 + SlugMV * 39.37, MassUsed, 999999) + local FragMass = Data.CasingMass + Data.SlugMass * Crushed + local Fragments = math.max(math.floor((BoomFiller / FragMass) * ACF.HEFrag), 2) + + return { + Crushed = Crushed, + HEATFillerMass = HEATFiller, + BoomFillerMass = BoomFiller, + SlugMV = SlugMV, + SlugMassUsed = MassUsed, + MaxPen = (Energy.Penetration / Data.SlugPenArea) * ACF.KEtoRHA, + TotalFragMass = FragMass, + BlastRadius = BoomFiller ^ 0.33 * 8, + Fragments = Fragments, + FragMass = FragMass / Fragments, + FragVel = (BoomFiller * ACF.HEPower * 1000 / FragMass) ^ 0.5, + } +end + +function Ammo.GetCrateText(BulletData) + local Text = "Muzzle Velocity: %s m/s\nMax Penetration: %s mm\nBlast Radius: %s m\n", "Blast Energy: %s KJ" + local Data = Ammo.GetDisplayData(BulletData) + + return Text:format(math.Round(BulletData.MuzzleVel, 2), math.floor(Data.MaxPen), math.Round(Data.BlastRadius, 2), math.floor(Data.BoomFillerMass * ACF.HEPower)) +end + +function Ammo.Detonate(_, Bullet, HitPos) + local Crushed, HEATFillerMass, BoomFillerMass = Ammo.CrushCalc(Bullet.Flight:Length() * 0.0254, Bullet.FillerMass) + + ACF_HE(HitPos - Bullet.Flight:GetNormalized() * 3, BoomFillerMass, Bullet.CasingMass + Bullet.SlugMass * Crushed, Bullet.Owner, nil, Bullet.Gun) + + if Crushed == 1 then return false end -- no HEAT jet to fire off, it was all converted to HE + + Bullet.Detonated = true + Bullet.InitTime = ACF.CurTime + Bullet.Flight = Bullet.Flight + Bullet.Flight:GetNormalized() * Ammo.CalcSlugMV(Bullet, HEATFillerMass) * 39.37 + Bullet.FuseLength = 0.005 + 40 / (Bullet.Flight:Length() * 0.0254) + Bullet.Pos = HitPos + Bullet.DragCoef = Bullet.SlugDragCoef + Bullet.ProjMass = Bullet.SlugMass * (1 - Crushed) + Bullet.Caliber = Bullet.SlugCaliber + Bullet.PenArea = Bullet.SlugPenArea + Bullet.Ricochet = Bullet.SlugRicochet + + local DeltaTime = ACF.CurTime - Bullet.LastThink + + Bullet.StartTrace = Bullet.Pos - Bullet.Flight:GetNormalized() * math.min(ACF.PhysMaxVel * DeltaTime, Bullet.FlightTime * Bullet.Flight:Length()) + Bullet.NextPos = Bullet.Pos + (Bullet.Flight * ACF.Scale * DeltaTime) --Calculates the next shell position + + return true +end + +function Ammo.PropImpact(Index, Bullet, Target, HitNormal, HitPos, Bone) + if ACF_Check(Target) then + if Bullet.Detonated then + Bullet.NotFirstPen = true + + local Speed = Bullet.Flight:Length() / ACF.Scale + local Energy = ACF_Kinetic(Speed, Bullet.ProjMass, 999999) + local HitRes = ACF_RoundImpact(Bullet, Speed, Energy, Target, HitPos, HitNormal, Bone) + + if HitRes.Overkill > 0 then + table.insert(Bullet.Filter, Target) --"Penetrate" (Ingoring the prop for the retry trace) + + Bullet.Flight = Bullet.Flight:GetNormalized() * math.sqrt(Energy.Kinetic * (1 - HitRes.Loss) * ((Bullet.NotFirstPen and ACF.HEATPenLayerMul) or 1) * 2000 / Bullet.ProjMass) * 39.37 + + return "Penetrated" + else + return false + end + else + local Speed = Bullet.Flight:Length() / ACF.Scale + local Energy = ACF_Kinetic(Speed, Bullet.ProjMass - Bullet.FillerMass, Bullet.LimitVel) + local HitRes = ACF_RoundImpact(Bullet, Speed, Energy, Target, HitPos, HitNormal, Bone) + + if HitRes.Ricochet then + return "Ricochet" + else + if Ammo.Detonate(Index, Bullet, HitPos, HitNormal) then + return "Penetrated" + else + return false + end + end + end + else + table.insert(Bullet.Filter, Target) + + return "Penetrated" + end + + return false +end + +function Ammo.WorldImpact(Index, Bullet, HitPos, HitNormal) + if not Bullet.Detonated then + if Ammo.Detonate(Index, Bullet, HitPos, HitNormal) then + return "Penetrated" + else + return false + end + end + + local Energy = ACF_Kinetic(Bullet.Flight:Length() / ACF.Scale, Bullet.ProjMass, 999999) + local HitRes = ACF_PenetrateGround(Bullet, Energy, HitPos, HitNormal) + + if HitRes.Penetrated then + return "Penetrated" + else + return false + end +end + +function Ammo.PenetrationEffect(Effect, Bullet) + if Bullet.Detonated then + local Data = EffectData() + Data:SetOrigin(Bullet.SimPos) + Data:SetNormal(Bullet.SimFlight:GetNormalized()) + Data:SetScale(Bullet.SimFlight:Length()) + Data:SetMagnitude(Bullet.RoundMass) + Data:SetRadius(Bullet.Caliber) + Data:SetDamageType(DecalIndex(Bullet.AmmoType)) + + util.Effect("ACF_Penetration", Data) + else + local _, _, BoomFillerMass = Ammo.CrushCalc(Bullet.SimFlight:Length() * 0.0254, Bullet.FillerMass) + local Data = EffectData() + Data:SetOrigin(Bullet.SimPos) + Data:SetNormal(Bullet.SimFlight:GetNormalized()) + Data:SetRadius(math.max(BoomFillerMass ^ 0.33 * 8 * 39.37, 1)) + + util.Effect("ACF_HEAT_Explosion", Data) + + Bullet.Detonated = true + + Effect:SetModel("models/Gibs/wood_gib01e.mdl") + end +end + +function Ammo.RicochetEffect(_, Bullet) + local Detonated = Bullet.Detonated + local Effect = EffectData() + Effect:SetOrigin(Bullet.SimPos) + Effect:SetNormal(Bullet.SimFlight:GetNormalized()) + Effect:SetScale(Bullet.SimFlight:Length()) + Effect:SetMagnitude(Bullet.RoundMass) + Effect:SetRadius(Bullet.Caliber) + Effect:SetDamageType(DecalIndex(Detonated and Bullet.AmmoType or "AP")) + + util.Effect("ACF_Ricochet", Effect) +end + +function Ammo.CreateMenu(Panel, Table) + acfmenupanel:AmmoSelect(Ammo.Blacklist) + + acfmenupanel:CPanelText("Desc", "") --Description (Name, Desc) + acfmenupanel:CPanelText("LengthDisplay", "") --Total round length (Name, Desc) + acfmenupanel:AmmoSlider("PropLength", 0, 0, 1000, 3, "Propellant Length", "") + acfmenupanel:AmmoSlider("ProjLength", 0, 0, 1000, 3, "Projectile Length", "") + acfmenupanel:AmmoSlider("ConeAng", 0, 0, 1000, 3, "HEAT Cone Angle", "") + acfmenupanel:AmmoSlider("FillerVol", 0, 0, 1000, 3, "Total HEAT Warhead volume", "") + acfmenupanel:AmmoCheckbox("Tracer", "Tracer", "") --Tracer checkbox (Name, Title, Desc) + acfmenupanel:CPanelText("VelocityDisplay", "") --Proj muzzle velocity (Name, Desc) + acfmenupanel:CPanelText("BlastDisplay", "") --HE Blast data (Name, Desc) + acfmenupanel:CPanelText("FragDisplay", "") --HE Fragmentation data (Name, Desc) + acfmenupanel:CPanelText("SlugDisplay", "") --HEAT Slug data (Name, Desc) + + Ammo.UpdateMenu(Panel, Table) +end + +function Ammo.UpdateMenu(Panel) + local PlayerData = { + Id = acfmenupanel.AmmoData.Data.id, --AmmoSelect GUI + Type = "HEAT", --Hardcoded, match ACFRoundTypes table index + PropLength = acfmenupanel.AmmoData.PropLength, --PropLength slider + ProjLength = acfmenupanel.AmmoData.ProjLength, --ProjLength slider + Data5 = acfmenupanel.AmmoData.FillerVol, + Data6 = acfmenupanel.AmmoData.ConeAng, + Data10 = acfmenupanel.AmmoData.Tracer and 1 or 0, + } + + local Data = Ammo.Convert(Panel, PlayerData) + + RunConsoleCommand("acfmenu_data1", acfmenupanel.AmmoData.Data.id) + RunConsoleCommand("acfmenu_data2", PlayerData.Type) + RunConsoleCommand("acfmenu_data3", Data.PropLength) --For Gun ammo, Data3 should always be Propellant + RunConsoleCommand("acfmenu_data4", Data.ProjLength) + RunConsoleCommand("acfmenu_data5", Data.FillerVol) + RunConsoleCommand("acfmenu_data6", Data.ConeAng) + RunConsoleCommand("acfmenu_data10", Data.Tracer) + + acfmenupanel:AmmoSlider("PropLength", Data.PropLength, Data.MinPropLength, Data.MaxTotalLength, 3, "Propellant Length", "Propellant Mass : " .. (math.floor(Data.PropMass * 1000)) .. " g") --Propellant Length Slider (Name, Min, Max, Decimals, Title, Desc) + acfmenupanel:AmmoSlider("ProjLength", Data.ProjLength, Data.MinProjLength, Data.MaxTotalLength, 3, "Projectile Length", "Projectile Mass : " .. (math.floor(Data.ProjMass * 1000)) .. " g") --Projectile Length Slider (Name, Min, Max, Decimals, Title, Desc) + acfmenupanel:AmmoSlider("ConeAng", Data.ConeAng, Data.MinConeAng, Data.MaxConeAng, 0, "Crush Cone Angle", "") --HE Filler Slider (Name, Min, Max, Decimals, Title, Desc) + acfmenupanel:AmmoSlider("FillerVol", Data.FillerVol, Data.MinFillerVol, Data.MaxFillerVol, 3, "HE Filler Volume", "HE Filler Mass : " .. (math.floor(Data.FillerMass * 1000)) .. " g") --HE Filler Slider (Name, Min, Max, Decimals, Title, Desc) + acfmenupanel:AmmoCheckbox("Tracer", "Tracer : " .. (math.floor(Data.Tracer * 10) / 10) .. "cm\n", "") --Tracer checkbox (Name, Title, Desc) + acfmenupanel:CPanelText("Desc", Ammo.Description) --Description (Name, Desc) + acfmenupanel:CPanelText("LengthDisplay", "Round Length : " .. (math.floor((Data.PropLength + Data.ProjLength + Data.Tracer) * 100) / 100) .. "/" .. Data.MaxTotalLength .. " cm") --Total round length (Name, Desc) + acfmenupanel:CPanelText("VelocityDisplay", "Muzzle Velocity : " .. math.floor(Data.MuzzleVel * ACF.Scale) .. " m/s") --Proj muzzle velocity (Name, Desc) + acfmenupanel:CPanelText("BlastDisplay", "Blast Radius : " .. (math.floor(Data.BlastRadius * 100) / 100) .. " m") --Proj muzzle velocity (Name, Desc) + acfmenupanel:CPanelText("FragDisplay", "Fragments : " .. Data.Fragments .. "\n Average Fragment Weight : " .. (math.floor(Data.FragMass * 10000) / 10) .. " g \n Average Fragment Velocity : " .. math.floor(Data.FragVel) .. " m/s") --Proj muzzle penetration (Name, Desc) + + local R1V, R1P = ACF_PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 300) + R1P = (ACF_Kinetic((R1V + Data.SlugMV) * 39.37, Data.SlugMassUsed, 999999).Penetration / Data.SlugPenArea) * ACF.KEtoRHA + local R2V, R2P = ACF_PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 800) + R2P = (ACF_Kinetic((R2V + Data.SlugMV) * 39.37, Data.SlugMassUsed, 999999).Penetration / Data.SlugPenArea) * ACF.KEtoRHA + + acfmenupanel:CPanelText("SlugDisplay", "Penetrator Mass : " .. (math.floor(Data.SlugMassUsed * 10000) / 10) .. " g \n Penetrator Caliber : " .. (math.floor(Data.SlugCaliber * 100) / 10) .. " mm \n Penetrator Velocity : " .. math.floor(Data.MuzzleVel + Data.SlugMV) .. " m/s \n Penetrator Maximum Penetration : " .. math.floor(Data.MaxPen) .. " mm RHA\n\n300m pen: " .. math.Round(R1P, 0) .. "mm @ " .. math.Round(R1V, 0) .. " m\\s\n800m pen: " .. math.Round(R2P, 0) .. "mm @ " .. math.Round(R2V, 0) .. " m\\s\n\nThe range data is an approximation and may not be entirely accurate.") --Proj muzzle penetration (Name, Desc) +end + +function Ammo.MenuAction(Menu) + Menu:AddParagraph("Testing HEAT menu.") +end + +ACF.RegisterAmmoDecal("HEAT", "damage/heat_pen", "damage/heat_rico", function(Caliber) return Caliber * 0.1667 end) diff --git a/lua/acf/shared/ammo_types/hp.lua b/lua/acf/shared/ammo_types/hp.lua new file mode 100644 index 000000000..00b7a4ab6 --- /dev/null +++ b/lua/acf/shared/ammo_types/hp.lua @@ -0,0 +1,145 @@ +local Ammo = ACF.RegisterAmmoType("Hollow Point", "Armor Piercing") + +function Ammo:OnLoaded() + Ammo.BaseClass.OnLoaded(self) + + self.ID = "HP" + self.Description = "A solid shell with a soft point, meant to flatten against armor." +end + +function Ammo.Convert(_, PlayerData) + local Data = {} + local ServerData = {} + local GUIData = {} + + if not PlayerData.PropLength then + PlayerData.PropLength = 0 + end + + if not PlayerData.ProjLength then + PlayerData.ProjLength = 0 + end + + PlayerData.Data5 = math.max(PlayerData.Data5 or 0, 0) + + if not PlayerData.Data10 then + PlayerData.Data10 = 0 + end + + PlayerData, Data, ServerData, GUIData = ACF_RoundBaseGunpowder(PlayerData, Data, ServerData, GUIData) + + Data.ProjMass = math.max(GUIData.ProjVolume * 0.5, 0) * 7.9 / 1000 --(Volume of the projectile as a cylinder - Volume of the cavity) * density of steel + Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass, Data.Caliber) + + local Energy = ACF_Kinetic(Data.MuzzleVel * 39.37, Data.ProjMass, Data.LimitVel) + local MaxVol = ACF_RoundShellCapacity(Energy.Momentum, Data.FrArea, Data.Caliber, Data.ProjLength) + + GUIData.MinCavVol = 0 + GUIData.MaxCavVol = math.min(GUIData.ProjVolume, MaxVol) + + Data.CavVol = math.Clamp(PlayerData.Data5, GUIData.MinCavVol, GUIData.MaxCavVol) + Data.ProjMass = ((Data.FrArea * Data.ProjLength) - Data.CavVol) * 7.9 / 1000 --Volume of the projectile as a cylinder * fraction missing due to hollow point (Data5) * density of steel + Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass, Data.Caliber) + + local ExpRatio = (Data.CavVol / GUIData.ProjVolume) + + Data.ShovePower = 0.2 + ExpRatio / 2 + Data.ExpCaliber = Data.Caliber + ExpRatio * Data.ProjLength + Data.PenArea = (3.1416 * Data.ExpCaliber / 2) ^ 2 ^ ACF.PenAreaMod + Data.DragCoef = ((Data.FrArea / 10000) / Data.ProjMass) + Data.LimitVel = 400 --Most efficient penetration speed in m/s + Data.KETransfert = 0.1 --Kinetic energy transfert to the target for movement purposes + Data.Ricochet = 90 --Base ricochet angle + Data.BoomPower = Data.PropMass + + --Only the crates need this part + if SERVER then + ServerData.Id = PlayerData.Id + ServerData.Type = PlayerData.Type + + return table.Merge(Data, ServerData) + end + + --Only tthe GUI needs this part + if CLIENT then + GUIData = table.Merge(GUIData, Ammo.GetDisplayData(Data)) + + return table.Merge(Data, GUIData) + end +end + +function Ammo.Network(Crate, BulletData) + Crate:SetNWString("AmmoType", "HP") + Crate:SetNWString("AmmoID", BulletData.Id) + Crate:SetNWFloat("Caliber", BulletData.Caliber) + Crate:SetNWFloat("ProjMass", BulletData.ProjMass) + Crate:SetNWFloat("PropMass", BulletData.PropMass) + Crate:SetNWFloat("ExpCaliber", BulletData.ExpCaliber) + Crate:SetNWFloat("DragCoef", BulletData.DragCoef) + Crate:SetNWFloat("MuzzleVel", BulletData.MuzzleVel) + Crate:SetNWFloat("Tracer", BulletData.Tracer) +end + +function Ammo.GetCrateText(BulletData) + local Data = Ammo.GetDisplayData(BulletData) + local BaseText = Ammo.BaseClass.GetCrateText(BulletData) + local Text = BaseText .. "\nExpanded Caliber: %s mm\nImparted Energy: %s KJ" + + return Text:format(math.floor(BulletData.ExpCaliber * 10), math.floor(Data.MaxKETransfert)) +end + +function Ammo.CreateMenu(Panel) + acfmenupanel:AmmoSelect(Ammo.Blacklist) + + acfmenupanel:CPanelText("Desc", "") --Description (Name, Desc) + acfmenupanel:CPanelText("LengthDisplay", "") --Total round length (Name, Desc) + acfmenupanel:AmmoSlider("PropLength", 0, 0, 1000, 3, "Propellant Length", "") --Propellant Length Slider (Name, Value, Min, Max, Decimals, Title, Desc) + acfmenupanel:AmmoSlider("ProjLength", 0, 0, 1000, 3, "Projectile Length", "") --Projectile Length Slider (Name, Value, Min, Max, Decimals, Title, Desc) + acfmenupanel:AmmoSlider("CavVol", 0, 0, 1000, 2, "Hollow Point Length", "") --Hollow Point Cavity Slider (Name, Value, Min, Max, Decimals, Title, Desc) + acfmenupanel:AmmoCheckbox("Tracer", "Tracer", "") --Tracer checkbox (Name, Title, Desc) + acfmenupanel:CPanelText("VelocityDisplay", "") --Proj muzzle velocity (Name, Desc) + acfmenupanel:CPanelText("KEDisplay", "") --Proj muzzle KE (Name, Desc) + acfmenupanel:CPanelText("PenetrationDisplay", "") --Proj muzzle penetration (Name, Desc) + + Ammo.UpdateMenu(Panel) +end + +function Ammo.CreateMenu(Panel) + local PlayerData = { + Id = acfmenupanel.AmmoData.Data.id, --AmmoSelect GUI + Type = "HP", --Hardcoded, match ACFRoundTypes table index + PropLength = acfmenupanel.AmmoData.PropLength, --PropLength slider + ProjLength = acfmenupanel.AmmoData.ProjLength, --ProjLength slider + Data5 = acfmenupanel.AmmoData.CavVol, + Data10 = acfmenupanel.AmmoData.Tracer and 1 or 0, + } + + local Data = Ammo.Convert(Panel, PlayerData) + + RunConsoleCommand("acfmenu_data1", acfmenupanel.AmmoData.Data.id) + RunConsoleCommand("acfmenu_data2", PlayerData.Type) + RunConsoleCommand("acfmenu_data3", Data.PropLength) --For Gun ammo, Data3 should always be Propellant + RunConsoleCommand("acfmenu_data4", Data.ProjLength) --And Data4 total round mass + RunConsoleCommand("acfmenu_data5", Data.CavVol) + RunConsoleCommand("acfmenu_data10", Data.Tracer) + + acfmenupanel:AmmoSlider("PropLength", Data.PropLength, Data.MinPropLength, Data.MaxTotalLength, 3, "Propellant Length", "Propellant Mass : " .. (math.floor(Data.PropMass * 1000)) .. " g") --Propellant Length Slider (Name, Min, Max, Decimals, Title, Desc) + acfmenupanel:AmmoSlider("ProjLength", Data.ProjLength, Data.MinProjLength, Data.MaxTotalLength, 3, "Projectile Length", "Projectile Mass : " .. (math.floor(Data.ProjMass * 1000)) .. " g") --Projectile Length Slider (Name, Min, Max, Decimals, Title, Desc) + acfmenupanel:AmmoSlider("CavVol", Data.CavVol, Data.MinCavVol, Data.MaxCavVol, 2, "Hollow Point cavity Volume", "Expanded caliber : " .. (math.floor(Data.ExpCaliber * 10)) .. " mm") --Hollow Point Cavity Slider (Name, Min, Max, Decimals, Title, Desc) + acfmenupanel:AmmoCheckbox("Tracer", "Tracer : " .. (math.floor(Data.Tracer * 10) / 10) .. "cm\n", "") --Tracer checkbox (Name, Title, Desc) + acfmenupanel:CPanelText("Desc", Ammo.Description) --Description (Name, Desc) + acfmenupanel:CPanelText("LengthDisplay", "Round Length : " .. (math.floor((Data.PropLength + Data.ProjLength + Data.Tracer) * 100) / 100) .. "/" .. Data.MaxTotalLength .. " cm") --Total round length (Name, Desc) + acfmenupanel:CPanelText("VelocityDisplay", "Muzzle Velocity : " .. math.floor(Data.MuzzleVel * ACF.Scale) .. " m/s") --Proj muzzle velocity (Name, Desc) + acfmenupanel:CPanelText("KEDisplay", "Kinetic Energy Transfered : " .. math.floor(Data.MaxKETransfert) .. " KJ") --Proj muzzle KE (Name, Desc) + + local R1V, R1P = ACF_PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 300) + local R2V, R2P = ACF_PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 800) + + acfmenupanel:CPanelText("PenetrationDisplay", "Maximum Penetration : " .. math.floor(Data.MaxPen) .. " mm RHA\n\n300m pen: " .. math.Round(R1P, 0) .. "mm @ " .. math.Round(R1V, 0) .. " m\\s\n800m pen: " .. math.Round(R2P, 0) .. "mm @ " .. math.Round(R2V, 0) .. " m\\s\n\nThe range data is an approximation and may not be entirely accurate.") --Proj muzzle penetration (Name, Desc) +end + +function Ammo.MenuAction(Menu) + Menu:AddParagraph("Testing HP menu.") +end + +ACF.RegisterAmmoDecal("HP", "damage/ap_pen", "damage/ap_rico") diff --git a/lua/acf/shared/ammo_types/refill.lua b/lua/acf/shared/ammo_types/refill.lua new file mode 100644 index 000000000..0f0afb047 --- /dev/null +++ b/lua/acf/shared/ammo_types/refill.lua @@ -0,0 +1,63 @@ +local Ammo = ACF.RegisterAmmoType("Refill", "Armor Piercing") + +function Ammo:OnLoaded() + self.ID = "Refill" + self.Description = "Ammunition refilling station." + self.Blacklist = {} +end + +function Ammo.Convert(_, PlayerData) + return { + Id = PlayerData.Id, + Type = PlayerData.Type, + Caliber = ACF.Weapons.Guns[PlayerData.Id].caliber, + ProjMass = 6 * 7.9 / 100, --Volume of the projectile as a cylinder * streamline factor (Data5) * density of steel + PropMass = 6 * ACF.PDensity / 1000, --Volume of the case as a cylinder * Powder density converted from g to kg + FillerMass = 0, + DragCoef = 0, + Tracer = 0, + MuzzleVel = 0, + RoundVolume = 36, + } +end + +function Ammo.Network(Crate, BulletData) + Crate:SetNWString("AmmoType", "Refill") + Crate:SetNWString("AmmoID", BulletData.Id) + Crate:SetNWFloat("Caliber", BulletData.Caliber) + Crate:SetNWFloat("ProjMass", BulletData.ProjMass) + Crate:SetNWFloat("FillerMass", BulletData.FillerMass) + Crate:SetNWFloat("PropMass", BulletData.PropMass) + Crate:SetNWFloat("DragCoef", BulletData.DragCoef) + Crate:SetNWFloat("MuzzleVel", BulletData.MuzzleVel) + Crate:SetNWFloat("Tracer", BulletData.Tracer) +end + +function Ammo.GetDisplayData() + return {} +end + +function Ammo.GetCrateText() + return "" +end + +function Ammo.CreateMenu(Panel, Table) + acfmenupanel:AmmoSelect() + + acfmenupanel:CPanelText("Desc", "") --Description (Name, Desc) + + Ammo.UpdateMenu(Panel, Table) +end + +function Ammo.UpdateMenu() + RunConsoleCommand("acfmenu_data1", acfmenupanel.CData.AmmoId or "12.7mmMG") + RunConsoleCommand("acfmenu_data2", "Refill") + + acfmenupanel:CPanelText("Desc", Ammo.Description) + + acfmenupanel.CustomDisplay:PerformLayout() +end + +function Ammo.MenuAction(Menu) + Menu:AddParagraph("Testing Refill menu.") +end diff --git a/lua/acf/shared/ammo_types/smoke.lua b/lua/acf/shared/ammo_types/smoke.lua new file mode 100644 index 000000000..2d33c32b5 --- /dev/null +++ b/lua/acf/shared/ammo_types/smoke.lua @@ -0,0 +1,224 @@ +local Ammo = ACF.RegisterAmmoType("Smoke", "Armor Piercing") + +function Ammo:OnLoaded() + self.ID = "SM" + self.Description = "A shell filled white phosporous, detonating on impact. Smoke filler produces a long lasting cloud but takes a while to be effective, whereas WP filler quickly creates a cloud that also dissipates quickly." + self.Blacklist = { "MG", "C", "GL", "HMG", "AL", "AC", "RAC", "SA", "SC" } +end + +function Ammo.Convert(_, PlayerData) + local Data = {} + local ServerData = {} + local GUIData = {} + + if not PlayerData.PropLength then + PlayerData.PropLength = 0 + end + + if not PlayerData.ProjLength then + PlayerData.ProjLength = 0 + end + + PlayerData.Data5 = math.max(PlayerData.Data5 or 0, 0) + PlayerData.Data6 = math.max(PlayerData.Data6 or 0, 0) + PlayerData.Data7 = tonumber(PlayerData.Data7) or 0 --catching some possible errors with string data in legacy dupes + + if not PlayerData.Data10 then + PlayerData.Data10 = 0 + end + + PlayerData, Data, ServerData, GUIData = ACF_RoundBaseGunpowder(PlayerData, Data, ServerData, GUIData) + + Data.ProjMass = math.max(GUIData.ProjVolume - PlayerData.Data5, 0) * 7.9 / 1000 + math.min(PlayerData.Data5, GUIData.ProjVolume) * ACF.HEDensity / 2000 --Volume of the projectile as a cylinder - Volume of the filler * density of steel + Volume of the filler * density of TNT + Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass, Data.Caliber) + + local Energy = ACF_Kinetic(Data.MuzzleVel * 39.37, Data.ProjMass, Data.LimitVel) + local MaxVol = ACF_RoundShellCapacity(Energy.Momentum, Data.FrArea, Data.Caliber, Data.ProjLength) + + GUIData.MinFillerVol = 0 + GUIData.MaxFillerVol = math.min(GUIData.ProjVolume, MaxVol) + GUIData.MaxSmokeVol = math.max(GUIData.MaxFillerVol - PlayerData.Data6, GUIData.MinFillerVol) + GUIData.MaxWPVol = math.max(GUIData.MaxFillerVol - PlayerData.Data5, GUIData.MinFillerVol) + + local Ratio = math.min(GUIData.MaxFillerVol / (PlayerData.Data5 + PlayerData.Data6), 1) + + GUIData.FillerVol = math.min(PlayerData.Data5 * Ratio, GUIData.MaxSmokeVol) + GUIData.WPVol = math.min(PlayerData.Data6 * Ratio, GUIData.MaxWPVol) + + Data.FillerMass = GUIData.FillerVol * ACF.HEDensity / 2000 + Data.WPMass = GUIData.WPVol * ACF.HEDensity / 2000 + Data.ProjMass = math.max(GUIData.ProjVolume - (GUIData.FillerVol + GUIData.WPVol), 0) * 7.9 / 1000 + Data.FillerMass + Data.WPMass + Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass, Data.Caliber) + Data.ShovePower = 0.1 + Data.PenArea = Data.FrArea ^ ACF.PenAreaMod + Data.DragCoef = ((Data.FrArea / 10000) / Data.ProjMass) + Data.LimitVel = 100 --Most efficient penetration speed in m/s + Data.KETransfert = 0.1 --Kinetic energy transfert to the target for movement purposes + Data.Ricochet = 60 --Base ricochet angle + Data.DetonatorAngle = 80 + Data.CanFuze = Data.Caliber > 2 -- Can fuze on calibers > 20mm + + if PlayerData.Data7 < 0.5 then + PlayerData.Data7 = 0 + Data.FuseLength = PlayerData.Data7 + else + PlayerData.Data7 = math.max(math.Round(PlayerData.Data7, 1), 0.5) + Data.FuseLength = PlayerData.Data7 + end + + Data.BoomPower = Data.PropMass + Data.FillerMass + Data.WPMass + + --Only the crates need this part + if SERVER then + ServerData.Id = PlayerData.Id + ServerData.Type = PlayerData.Type + + return table.Merge(Data, ServerData) + end + + --Only tthe GUI needs this part + if CLIENT then + GUIData = table.Merge(GUIData, Ammo.GetDisplayData(Data)) + + return table.Merge(Data, GUIData) + end +end + +function Ammo.Network(Crate, BulletData) + Crate:SetNWString("AmmoType", "SM") + Crate:SetNWString("AmmoID", BulletData.Id) + Crate:SetNWFloat("Caliber", BulletData.Caliber) + Crate:SetNWFloat("ProjMass", BulletData.ProjMass) + Crate:SetNWFloat("FillerMass", BulletData.FillerMass) + Crate:SetNWFloat("WPMass", BulletData.WPMass) + Crate:SetNWFloat("PropMass", BulletData.PropMass) + Crate:SetNWFloat("DragCoef", BulletData.DragCoef) + Crate:SetNWFloat("MuzzleVel", BulletData.MuzzleVel) + Crate:SetNWFloat("Tracer", BulletData.Tracer) +end + +function Ammo.GetDisplayData(Data) + local SMFiller = math.min(math.log(1 + Data.FillerMass * 8 * 39.37) / 0.02303, 350) + local WPFiller = math.min(math.log(1 + Data.WPMass * 8 * 39.37) / 0.02303, 350) + + return { + SMFiller = SMFiller, --smoke filler + SMLife = math.Round(20 + SMFiller * 0.25, 1), + SMRadiusMin = math.Round(SMFiller * 1.25 * 0.15 * 0.0254, 1), + SMRadiusMax = math.Round(SMFiller * 1.25 * 2 * 0.0254, 1), + WPFiller = WPFiller, --wp filler + WPLife = math.Round(6 + WPFiller * 0.1, 1), + WPRadiusMin = math.Round(WPFiller * 1.25 * 0.0254, 1), + WPRadiusMax = math.Round(WPFiller * 1.25 * 2 * 0.0254, 1), + } +end + +function Ammo.GetCrateText(BulletData) + local Text = "Muzzle Velocity: %s m/s%s%s" + local Data = Ammo.GetDisplayData(BulletData) + local WPText, SMText = "", "" + + + if Data.WPFiller > 0 then + local Template = "\nWP Radius: %s m to %s m\nWP Lifetime: %s s" + + WPText = Template:format(Data.WPRadiusMin, Data.WPRadiusMax, Data.WPLife) + end + + if Data.SMFiller > 0 then + local Template = "\nSM Radius: %s m to %s m\nSM Lifetime: %s s" + + SMText = Template:format(Data.SMRadiusMin, Data.SMRadiusMax, Data.SMLife) + end + + return Text:format(math.Round(BulletData.MuzzleVel, 2), WPText, SMText) +end + +function Ammo.PropImpact(_, Bullet, Target, HitNormal, HitPos, Bone) + if ACF_Check(Target) then + local Speed = Bullet.Flight:Length() / ACF.Scale + local Energy = ACF_Kinetic(Speed, Bullet.ProjMass - (Bullet.FillerMass + Bullet.WPMass), Bullet.LimitVel) + local HitRes = ACF_RoundImpact(Bullet, Speed, Energy, Target, HitPos, HitNormal, Bone) + + if HitRes.Ricochet then return "Ricochet" end + end + + return false +end + +function Ammo.WorldImpact() + return false +end + +function Ammo.ImpactEffect(_, Bullet) + local Crate = Bullet.Crate + local Color = IsValid(Crate) and Crate:GetColor() or Color(255, 255, 255) + + local Effect = EffectData() + Effect:SetOrigin(Bullet.SimPos) + Effect:SetNormal(Bullet.SimFlight:GetNormalized()) + Effect:SetScale(math.max(Bullet.FillerMass * 8 * 39.37, 0)) + Effect:SetMagnitude(math.max(Bullet.WPMass * 8 * 39.37, 0)) + Effect:SetStart(Vector(Color.r, Color.g, Color.b)) + Effect:SetRadius(Bullet.Caliber) + + util.Effect("ACF_Smoke", Effect) +end + +function Ammo.CreateMenu(Panel, Table) + acfmenupanel:AmmoSelect(Ammo.Blacklist) + + acfmenupanel:CPanelText("Desc", "") --Description (Name, Desc) + acfmenupanel:CPanelText("LengthDisplay", "") --Total round length (Name, Desc) + acfmenupanel:AmmoSlider("PropLength", 0, 0, 1000, 3, "Propellant Length", "") --Slider (Name, Value, Min, Max, Decimals, Title, Desc) + acfmenupanel:AmmoSlider("ProjLength", 0, 0, 1000, 3, "Projectile Length", "") --Slider (Name, Value, Min, Max, Decimals, Title, Desc) + acfmenupanel:AmmoSlider("FillerVol", 0, 0, 1000, 3, "Smoke Filler", "") --Slider (Name, Value, Min, Max, Decimals, Title, Desc) + acfmenupanel:AmmoSlider("WPVol", 0, 0, 1000, 3, "WP Filler", "") --Slider (Name, Value, Min, Max, Decimals, Title, Desc) + acfmenupanel:AmmoSlider("FuseLength", 0, 0, 1000, 3, "Timed Fuse", "") + acfmenupanel:AmmoCheckbox("Tracer", "Tracer", "") --Tracer checkbox (Name, Title, Desc) + acfmenupanel:CPanelText("VelocityDisplay", "") --Proj muzzle velocity (Name, Desc) + acfmenupanel:CPanelText("BlastDisplay", "") --HE Blast data (Name, Desc) + acfmenupanel:CPanelText("FragDisplay", "") --HE Fragmentation data (Name, Desc) + + Ammo.UpdateMenu(Panel, Table) +end + +function Ammo.UpdateMenu(Panel) + local PlayerData = { + Id = acfmenupanel.AmmoData.Data.id, --AmmoSelect GUI + Type = "SM", --Hardcoded, match ACFRoundTypes table index + PropLength = acfmenupanel.AmmoData.PropLength, --PropLength slider + ProjLength = acfmenupanel.AmmoData.ProjLength, --ProjLength slider + Data5 = acfmenupanel.AmmoData.FillerVol, + Data6 = acfmenupanel.AmmoData.WPVol, + Data7 = acfmenupanel.AmmoData.FuseLength, + Data10 = acfmenupanel.AmmoData.Tracer and 1 or 0, + } + + local Data = Ammo.Convert(Panel, PlayerData) + + RunConsoleCommand("acfmenu_data1", acfmenupanel.AmmoData.Data.id) + RunConsoleCommand("acfmenu_data2", PlayerData.Type) + RunConsoleCommand("acfmenu_data3", Data.PropLength) --For Gun ammo, Data3 should always be Propellant + RunConsoleCommand("acfmenu_data4", Data.ProjLength) --And Data4 total round mass + RunConsoleCommand("acfmenu_data5", Data.FillerVol) + RunConsoleCommand("acfmenu_data6", Data.WPVol) + RunConsoleCommand("acfmenu_data7", Data.FuseLength) + RunConsoleCommand("acfmenu_data10", Data.Tracer) + + acfmenupanel:AmmoSlider("PropLength", Data.PropLength, Data.MinPropLength, Data.MaxTotalLength, 3, "Propellant Length", "Propellant Mass : " .. (math.floor(Data.PropMass * 1000)) .. " g") --Propellant Length Slider (Name, Min, Max, Decimals, Title, Desc) + acfmenupanel:AmmoSlider("ProjLength", Data.ProjLength, Data.MinProjLength, Data.MaxTotalLength, 3, "Projectile Length", "Projectile Mass : " .. (math.floor(Data.ProjMass * 1000)) .. " g") --Projectile Length Slider (Name, Min, Max, Decimals, Title, Desc) + acfmenupanel:AmmoSlider("FillerVol", Data.FillerVol, Data.MinFillerVol, Data.MaxFillerVol, 3, "Smoke Filler Volume", "Smoke Filler Mass : " .. (math.floor(Data.FillerMass * 1000)) .. " g") --HE Filler Slider (Name, Min, Max, Decimals, Title, Desc) + acfmenupanel:AmmoSlider("WPVol", Data.WPVol, Data.MinFillerVol, Data.MaxFillerVol, 3, "WP Filler Volume", "WP Filler Mass : " .. (math.floor(Data.WPMass * 1000)) .. " g") --HE Filler Slider (Name, Min, Max, Decimals, Title, Desc) + acfmenupanel:AmmoSlider("FuseLength", Data.FuseLength, 0, 10, 1, "Fuse Time", Data.FuseLength .. " s") + acfmenupanel:AmmoCheckbox("Tracer", "Tracer : " .. (math.floor(Data.Tracer * 10) / 10) .. "cm\n", "") --Tracer checkbox (Name, Title, Desc) + acfmenupanel:CPanelText("Desc", Ammo.Description) --Description (Name, Desc) + acfmenupanel:CPanelText("LengthDisplay", "Round Length : " .. (math.floor((Data.PropLength + Data.ProjLength + Data.Tracer) * 100) / 100) .. "/" .. Data.MaxTotalLength .. " cm") --Total round length (Name, Desc) + acfmenupanel:CPanelText("VelocityDisplay", "Muzzle Velocity : " .. math.floor(Data.MuzzleVel * ACF.Scale) .. " m/s") --Proj muzzle velocity (Name, Desc) +end + +function Ammo.MenuAction(Menu) + Menu:AddParagraph("Testing SM menu.") +end + +ACF.RegisterAmmoDecal("SM", "damage/he_pen", "damage/he_rico") diff --git a/lua/acf/shared/guns/smokelauncher.lua b/lua/acf/shared/guns/smokelauncher.lua index e3538b2a9..0b6d9b3aa 100644 --- a/lua/acf/shared/guns/smokelauncher.lua +++ b/lua/acf/shared/guns/smokelauncher.lua @@ -56,7 +56,7 @@ ACF.RegisterWeaponClass("SL", { Sound = "weapons/acf_gun/smoke_launch.mp3", Caliber = { Min = 40, - Max = 76, + Max = 81, }, }) From ff25b99d6781c2a6cb3ae5ed02d377d1761690da Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Fri, 21 Feb 2020 01:15:59 -0300 Subject: [PATCH 011/279] Added crate model and ammo type selection to the weapon's menu --- lua/acf/client/menu_items/weapons_menu.lua | 44 +++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/lua/acf/client/menu_items/weapons_menu.lua b/lua/acf/client/menu_items/weapons_menu.lua index 43b4b0a3e..9af8ff529 100644 --- a/lua/acf/client/menu_items/weapons_menu.lua +++ b/lua/acf/client/menu_items/weapons_menu.lua @@ -1,4 +1,6 @@ +local AmmoTypes = ACF.Classes.AmmoTypes local Weapons = ACF.Classes.Weapons +local Crates = ACF.Classes.Crates local Selected = {} local Sorted = {} @@ -39,6 +41,11 @@ local function CreateMenu(Menu) local ClassDesc = Menu:AddParagraph() local EntData = Menu:AddParagraph() + Menu:AddSubtitle("Ammo Settings") + + local CrateList = Menu:AddComboBox() + local AmmoList = Menu:AddComboBox() + ACF.WriteValue("Class", "acf_gun") function ClassList:OnSelect(Index, _, Data) @@ -49,6 +56,8 @@ local function CreateMenu(Menu) local Choices = Sorted[Weapons] Selected[Choices] = Index + ACF.WriteValue("Class", Data.ID) + ClassDesc:SetText(Data.Description) LoadSortedList(EntList, Data.Items, "Caliber") @@ -61,7 +70,7 @@ local function CreateMenu(Menu) local ClassData = ClassList.Selected local RoundVolume = 3.1416 * (Data.Caliber * 0.05) ^ 2 * Data.Round.MaxLength - local Firerate = 60 / (((RoundVolume / 500) ^ 0.6) * ClassData.ROFMod * (Data.ROFMod or 1)) + local Firerate = 60 / (((RoundVolume * 0.002) ^ 0.6) * ClassData.ROFMod * (Data.ROFMod or 1)) local Magazine = Data.MagSize and MagText:format(Data.MagSize, Data.MagReload) or "" local Choices = Sorted[ClassData.Items] @@ -73,7 +82,40 @@ local function CreateMenu(Menu) EntData:SetText(EntText:format(Data.Mass, math.Round(Firerate, 2), ClassData.Spread * 100, Magazine)) end + function CrateList:OnSelect(Index, _, Data) + if self.Selected == Data then return end + + self.Selected = Data + + local Choices = Sorted[Crates] + Selected[Choices] = Index + + ACF.WriteValue("Crate", Data.ID) + end + + function AmmoList:OnSelect(Index, _, Data) + if self.Selected == Data then return end + + self.Selected = Data + + local Choices = Sorted[AmmoTypes] + Selected[Choices] = Index + + ACF.WriteValue("Ammo", Data.ID) + + Menu:ClearTemporal(self) + Menu:StartTemporal(self) + + if Data.MenuAction then + Data.MenuAction(Menu) + end + + Menu:EndTemporal(self) + end + LoadSortedList(ClassList, Weapons, "Name") + LoadSortedList(CrateList, Crates, "ID") + LoadSortedList(AmmoList, AmmoTypes, "Name") end ACF.AddOptionItem("Entities", "Weapons", "gun", CreateMenu) From 65a6eda927be05e99224b3956ca30b29d0950c98 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Fri, 21 Feb 2020 02:24:42 -0300 Subject: [PATCH 012/279] Fixed unproper menu reload in case of Lua errors --- lua/acf/client/cl_menu.lua | 4 +++- lua/acf/client/menu_items/weapons_menu.lua | 2 +- lua/vgui/acf_panel.lua | 15 ++++++++++++--- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/lua/acf/client/cl_menu.lua b/lua/acf/client/cl_menu.lua index 40434528d..d2c6484e8 100644 --- a/lua/acf/client/cl_menu.lua +++ b/lua/acf/client/cl_menu.lua @@ -136,10 +136,12 @@ do -- ACF Menu context panel Panel:AddItem(Menu) else - Menu:Clear() + Menu:ClearAllTemporal() + Menu:ClearAll() end local Reload = Menu:AddButton("Reload Menu") + Reload:SetTooltip("You can also type 'acf_reload_menu' in console.") function Reload:DoClickInternal() ACF.BuildContextPanel(Panel) end diff --git a/lua/acf/client/menu_items/weapons_menu.lua b/lua/acf/client/menu_items/weapons_menu.lua index 9af8ff529..5be473bdc 100644 --- a/lua/acf/client/menu_items/weapons_menu.lua +++ b/lua/acf/client/menu_items/weapons_menu.lua @@ -32,7 +32,7 @@ local function LoadSortedList(Panel, List, Member) end local function CreateMenu(Menu) - local EntText = "Mass: %skg\nFirerate: %srpm\nSpread: %s degrees%s" + local EntText = "Mass: %s kg\nFirerate: %s rpm\nSpread: %s degrees%s" local MagText = "\nRounds: %s rounds\nReload: %s seconds" local ClassList = Menu:AddComboBox() diff --git a/lua/vgui/acf_panel.lua b/lua/vgui/acf_panel.lua index c2e83eda9..a1cb667a6 100644 --- a/lua/vgui/acf_panel.lua +++ b/lua/vgui/acf_panel.lua @@ -7,9 +7,7 @@ function PANEL:Init() self.TempItems = {} end -function PANEL:Clear() - if not next(self.Items) then return end - +function PANEL:ClearAll() for K in pairs(self.Items) do if IsValid(K) then K:Remove() @@ -17,6 +15,8 @@ function PANEL:Clear() self.Items[K] = nil end + + self:Clear() end function PANEL:ClearTemporal(Panel) @@ -51,6 +51,15 @@ function PANEL:EndTemporal(Panel) TemporalPanels[Target] = nil end +function PANEL:ClearAllTemporal() + for Panel in pairs(TemporalPanels) do + if not IsValid(Panel) then continue end + + self:EndTemporal(Panel) + self:ClearTemporal(Panel) + end +end + function PANEL:AddPanel(Name) if not Name then return end From 7db930c0ecd005595539abd085a76f5d33771279 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Fri, 21 Feb 2020 02:25:47 -0300 Subject: [PATCH 013/279] Changed class library to store ID instead of Name --- lua/acf/base/sh_classes.lua | 36 ++++++++++++++-------------- lua/acf/shared/ammo_types/ap.lua | 4 ++-- lua/acf/shared/ammo_types/aphe.lua | 4 ++-- lua/acf/shared/ammo_types/fl.lua | 4 ++-- lua/acf/shared/ammo_types/he.lua | 4 ++-- lua/acf/shared/ammo_types/heat.lua | 4 ++-- lua/acf/shared/ammo_types/hp.lua | 4 ++-- lua/acf/shared/ammo_types/refill.lua | 4 ++-- lua/acf/shared/ammo_types/smoke.lua | 4 ++-- 9 files changed, 34 insertions(+), 34 deletions(-) diff --git a/lua/acf/base/sh_classes.lua b/lua/acf/base/sh_classes.lua index 2f5c8c97c..a4cb0b3ad 100644 --- a/lua/acf/base/sh_classes.lua +++ b/lua/acf/base/sh_classes.lua @@ -14,15 +14,15 @@ do -- Class registration function return New end - local function QueueBaseClass(Name, Base) + local function QueueBaseClass(ID, Base) if not Queued[Base] then - Queued[Base] = { [Name] = true } + Queued[Base] = { [ID] = true } else - Queued[Base][Name] = true + Queued[Base][ID] = true end end - local function AttachMetaTable(Class, Name, Base) + local function AttachMetaTable(Class, ID, Base) local OldMeta = getmetatable(Class) or {} if Base then @@ -32,7 +32,7 @@ do -- Class registration function Class.BaseClass = BaseClass OldMeta.__index = BaseClass else - QueueBaseClass(Name, Base) + QueueBaseClass(ID, Base) end end @@ -49,30 +49,30 @@ do -- Class registration function end) end - function ACF.RegisterClass(Name, Base, Destiny) - if not Classes[Name] then - Classes[Name] = {} + function ACF.RegisterClass(ID, Base, Destiny) + if not Classes[ID] then + Classes[ID] = {} end - local Class = Classes[Name] - Class.Name = Name + local Class = Classes[ID] + Class.ID = ID - AttachMetaTable(Class, Name, Base) + AttachMetaTable(Class, ID, Base) - if Queued[Name] then + if Queued[ID] then local Current - for K in pairs(Queued[Name]) do + for K in pairs(Queued[ID]) do Current = Classes[K] - AttachMetaTable(Current, Current.Name, Name) + AttachMetaTable(Current, Current.ID, ID) end - Queued[Name] = nil + Queued[ID] = nil end if Destiny then - Destiny[Name] = Class + Destiny[ID] = Class end return Class @@ -174,7 +174,7 @@ do -- Ammo type registration function local RegisterClass = ACF.RegisterClass local Types = ACF.Classes.AmmoTypes - function ACF.RegisterAmmoType(Name, Base) - return RegisterClass(Name, Base, Types) + function ACF.RegisterAmmoType(ID, Base) + return RegisterClass(ID, Base, Types) end end diff --git a/lua/acf/shared/ammo_types/ap.lua b/lua/acf/shared/ammo_types/ap.lua index 91e433b60..42db9e78c 100644 --- a/lua/acf/shared/ammo_types/ap.lua +++ b/lua/acf/shared/ammo_types/ap.lua @@ -1,8 +1,8 @@ -local Ammo = ACF.RegisterAmmoType("Armor Piercing") +local Ammo = ACF.RegisterAmmoType("AP") local DecalIndex = ACF.GetAmmoDecalIndex function Ammo:OnLoaded() - self.ID = "AP" + self.Name = "Armor Piercing" self.Type = "Ammo" self.Model = "models/munitions/round_100mm_shot.mdl" self.Description = "A shell made out of a solid piece of steel, meant to penetrate armor." diff --git a/lua/acf/shared/ammo_types/aphe.lua b/lua/acf/shared/ammo_types/aphe.lua index 13665deee..14ca2ba11 100644 --- a/lua/acf/shared/ammo_types/aphe.lua +++ b/lua/acf/shared/ammo_types/aphe.lua @@ -1,9 +1,9 @@ -local Ammo = ACF.RegisterAmmoType("Armor Piercing Explosive", "Armor Piercing") +local Ammo = ACF.RegisterAmmoType("APHE", "AP") function Ammo:OnLoaded() Ammo.BaseClass.OnLoaded(self) - self.ID = "APHE" + self.Name = "Armor Piercing High Explosive" self.Description = "An armor piercing round with a cavity for High explosives. Less capable of defeating armor than plain Armor Piercing, but will explode after penetration" self.Blacklist = { "MO", "MG", "SL", "RAC" } end diff --git a/lua/acf/shared/ammo_types/fl.lua b/lua/acf/shared/ammo_types/fl.lua index 2c55f3c17..07b3c3ffc 100644 --- a/lua/acf/shared/ammo_types/fl.lua +++ b/lua/acf/shared/ammo_types/fl.lua @@ -1,9 +1,9 @@ -local Ammo = ACF.RegisterAmmoType("Flechette", "Armor Piercing") +local Ammo = ACF.RegisterAmmoType("FL", "AP") function Ammo:OnLoaded() Ammo.BaseClass.OnLoaded(self) - self.ID = "FL" + self.Name = "Flechette" self.Model = "models/munitions/dart_100mm.mdl" self.Description = "Flechette rounds contain several long thin steel spikes, functioning as a shotgun shell for cannons. While it seems like the spikes would penetrate well, they tend to tumble in flight and impact at less than ideal angles, causing only minor penetration and structural damage. They are best used against infantry or lightly armored mobile targets such as aircraft or light tanks, since flechettes trade brute damage for a better chance to hit." self.Blacklist = { "AC", "RAC", "MG", "HMG", "GL", "SL" } diff --git a/lua/acf/shared/ammo_types/he.lua b/lua/acf/shared/ammo_types/he.lua index 3702b41d6..382a9725d 100644 --- a/lua/acf/shared/ammo_types/he.lua +++ b/lua/acf/shared/ammo_types/he.lua @@ -1,9 +1,9 @@ -local Ammo = ACF.RegisterAmmoType("High Explosive", "Armor Piercing Explosive") +local Ammo = ACF.RegisterAmmoType("HE", "APHE") function Ammo:OnLoaded() Ammo.BaseClass.OnLoaded(self) - self.ID = "HE" + self.Name = "High Explosive" self.Description = "A shell filled with explosives, detonating on impact." self.Blacklist = { "MG", "RAC" } end diff --git a/lua/acf/shared/ammo_types/heat.lua b/lua/acf/shared/ammo_types/heat.lua index 52b330867..1fa937642 100644 --- a/lua/acf/shared/ammo_types/heat.lua +++ b/lua/acf/shared/ammo_types/heat.lua @@ -1,10 +1,10 @@ -local Ammo = ACF.RegisterAmmoType("High Explosive Anti-Tank", "Armor Piercing") +local Ammo = ACF.RegisterAmmoType("HEAT", "AP") local DecalIndex = ACF.GetAmmoDecalIndex function Ammo:OnLoaded() Ammo.BaseClass.OnLoaded(self) - self.ID = "HEAT" + self.Name = "High Explosive Anti-Tank" self.Description = "A shell with a shaped charge. When the round detonates, the explosive energy is focused into driving a small molten metal penetrator into the victim with extreme force, though this results in reduced damage from the explosion itself. Multiple layers of armor will dissipate the penetrator quickly." self.Blacklist = { "MG", "HMG", "RAC", "AC", "SL", "SB" } end diff --git a/lua/acf/shared/ammo_types/hp.lua b/lua/acf/shared/ammo_types/hp.lua index 00b7a4ab6..a0a08fe4e 100644 --- a/lua/acf/shared/ammo_types/hp.lua +++ b/lua/acf/shared/ammo_types/hp.lua @@ -1,9 +1,9 @@ -local Ammo = ACF.RegisterAmmoType("Hollow Point", "Armor Piercing") +local Ammo = ACF.RegisterAmmoType("HP", "AP") function Ammo:OnLoaded() Ammo.BaseClass.OnLoaded(self) - self.ID = "HP" + self.Name = "Hollow Point" self.Description = "A solid shell with a soft point, meant to flatten against armor." end diff --git a/lua/acf/shared/ammo_types/refill.lua b/lua/acf/shared/ammo_types/refill.lua index 0f0afb047..97daad816 100644 --- a/lua/acf/shared/ammo_types/refill.lua +++ b/lua/acf/shared/ammo_types/refill.lua @@ -1,7 +1,7 @@ -local Ammo = ACF.RegisterAmmoType("Refill", "Armor Piercing") +local Ammo = ACF.RegisterAmmoType("Refill", "AP") function Ammo:OnLoaded() - self.ID = "Refill" + self.Name = "Refill" self.Description = "Ammunition refilling station." self.Blacklist = {} end diff --git a/lua/acf/shared/ammo_types/smoke.lua b/lua/acf/shared/ammo_types/smoke.lua index 2d33c32b5..267e94013 100644 --- a/lua/acf/shared/ammo_types/smoke.lua +++ b/lua/acf/shared/ammo_types/smoke.lua @@ -1,7 +1,7 @@ -local Ammo = ACF.RegisterAmmoType("Smoke", "Armor Piercing") +local Ammo = ACF.RegisterAmmoType("SM", "AP") function Ammo:OnLoaded() - self.ID = "SM" + self.Name = "Smoke" self.Description = "A shell filled white phosporous, detonating on impact. Smoke filler produces a long lasting cloud but takes a while to be effective, whereas WP filler quickly creates a cloud that also dissipates quickly." self.Blacklist = { "MG", "C", "GL", "HMG", "AL", "AC", "RAC", "SA", "SC" } end From 69dcd8b7fc58a823ce0e8c1bdc1ff3c7dc97f5d6 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Fri, 21 Feb 2020 06:07:20 -0300 Subject: [PATCH 014/279] Renamed tool data variable to prevent conflicts --- lua/acf/client/menu_items/weapons_menu.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/acf/client/menu_items/weapons_menu.lua b/lua/acf/client/menu_items/weapons_menu.lua index 5be473bdc..b28ed4f6a 100644 --- a/lua/acf/client/menu_items/weapons_menu.lua +++ b/lua/acf/client/menu_items/weapons_menu.lua @@ -56,7 +56,7 @@ local function CreateMenu(Menu) local Choices = Sorted[Weapons] Selected[Choices] = Index - ACF.WriteValue("Class", Data.ID) + ACF.WriteValue("WeaponClass", Data.ID) ClassDesc:SetText(Data.Description) From e465976a121e942662a6769cdfcca06c26c016c7 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sun, 23 Feb 2020 05:12:12 -0300 Subject: [PATCH 015/279] Renamed ACF.GetPlayerData to ACF.GetToolData --- lua/acf/base/util/cl_util.lua | 21 +++++---------------- lua/acf/base/util/sv_util.lua | 2 +- 2 files changed, 6 insertions(+), 17 deletions(-) diff --git a/lua/acf/base/util/cl_util.lua b/lua/acf/base/util/cl_util.lua index 072171117..c1f73932a 100644 --- a/lua/acf/base/util/cl_util.lua +++ b/lua/acf/base/util/cl_util.lua @@ -77,14 +77,8 @@ do -- Tool data functions local ToolData = {} do -- Read functions - function ACF.GetPlayerData() - local Result = {} - - for K, V in pairs(ToolData[Player]) do - Result[K] = V - end - - return Result + function ACF.GetToolData() + return ToolData end function ACF.ReadBool(Key) @@ -122,7 +116,9 @@ do -- Tool data functions return tostring(Value):match(ValuePattern) and true or false end - local function UpdateKeyValue(Key, Value) + function ACF.WriteValue(Key, Value) + if not IsValidKey(Key) then return end + if not IsValidValue(Value) then return end if ToolData[Key] == Value then return end ToolData[Key] = Value @@ -135,13 +131,6 @@ do -- Tool data functions print("Sent", LocalPlayer(), Key, Value) end - - function ACF.WriteValue(Key, Value) - if not IsValidKey(Key) then return end - if not IsValidValue(Value) then return end - - UpdateKeyValue(Key, Value) - end end do -- Panel functions diff --git a/lua/acf/base/util/sv_util.lua b/lua/acf/base/util/sv_util.lua index 1dbeb297b..42a3980fd 100644 --- a/lua/acf/base/util/sv_util.lua +++ b/lua/acf/base/util/sv_util.lua @@ -89,7 +89,7 @@ do -- Tool data functions end do -- Read functions - function ACF.GetPlayerData(Player) + function ACF.GetToolData(Player) if not IsValid(Player) then return {} end if not ToolData[Player] then return {} end From 4560058cabc1b08d47bb376b56d7f87ef4f37670 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sun, 23 Feb 2020 05:17:33 -0300 Subject: [PATCH 016/279] Added data tracking and custom value setting panel functions - PANEL.SetDataVariable was renamed to PANEL.SetDataVar. - PANEL.ClearDataVariable was renamed to PANEL.ClearDataVars. - Added PANEL.TrackDataVar and PANEL.SetValueFunction. - Added a test combobox on the weapon's menu to test these functions. --- lua/acf/base/util/cl_util.lua | 104 ++++++++++++++++----- lua/acf/client/menu_items/weapons_menu.lua | 7 ++ 2 files changed, 89 insertions(+), 22 deletions(-) diff --git a/lua/acf/base/util/cl_util.lua b/lua/acf/base/util/cl_util.lua index c1f73932a..e7855483b 100644 --- a/lua/acf/base/util/cl_util.lua +++ b/lua/acf/base/util/cl_util.lua @@ -135,59 +135,119 @@ do -- Tool data functions do -- Panel functions local PANEL = FindMetaTable("Panel") + local Variables = {} local Panels = {} - local function AddFunctions(Panel) + local function AddVariable(Panel, Key) + local PData = Panels[Panel] + local VData = Variables[Key] + + if not PData then + Panels[Panel] = { + [Key] = true + } + else + PData[Key] = true + end + + if not VData then + Variables[Key] = { + [Panel] = true + } + else + VData[Panel] = true + end + end + + local function ClearVariables(Panel) + local Vars = Panels[Panel] + + if not Vars then return end + + for K in pairs(Vars) do + Variables[K][Panel] = nil + end + + Panels[Panel] = nil + end + + local function LoadFunctions(Panel) + if Panel.LegacyRemove then return end + Panel.LegacySetValue = Panel.SetValue Panel.LegacyRemove = Panel.Remove - Panels[Panel] = true + function Panel:SetValue(Value) + if not self.DataVar then + return Panel:LegacySetValue(Value) + end - function Panel:SetValue(Value, ...) ACF.WriteValue(self.DataVar, Value) - - self:LegacySetValue(Value, ...) end - function Panel:Remove(...) - Panels[Panel] = nil + function Panel:Remove() + ClearVariables(self) - self:LegacyRemove(...) + self:LegacyRemove() end end - function PANEL:SetDataVariable(Key) + function PANEL:SetDataVar(Key) if not Key then return end if not self.SetValue then return end self.DataVar = Key + AddVariable(self, Key) + LoadFunctions(self) + if not ToolData[Key] then ACF.WriteValue(Key, self:GetValue()) end + end - if not self.LegacySetValue then - AddFunctions(self) - end + function PANEL:TrackDataVar(Key) + AddVariable(self, Key) + LoadFunctions(self) end - function PANEL:ClearDataVariable() - if not self.LegacySetValue then return end + function PANEL:SetValueFunction(Function) + if not isfunction(Function) then return end + + LoadFunctions(self) + + self.ValueFunction = Function + + self:LegacySetValue(self:ValueFunction()) + end - Panels[self] = nil + function PANEL:ClearDataVars() + if self.LegacyRemove then + self.SetValue = self.LegacySetValue + self.Remove = self.LegacyRemove + self.LegacySetValue = nil + self.LegacyRemove = nil + end - self.SetValue = self.LegacySetValue - self.Remove = self.LegacyRemove - self.LegacySetValue = nil - self.LegacyRemove = nil + self.ValueFunction = nil self.DataVar = nil + + ClearVariables(self) end hook.Add("OnToolDataUpdate", "ACF Update Panel Values", function(Key, Value) - for Panel in pairs(Panels) do - if Panel.DataVar == Key then - Panel:LegacySetValue(Value) + local Affected = Variables[Key] + + if not Affected then return end + + for Panel in pairs(Affected) do + local RealValue = Value + + if Panel.ValueFunction then + RealValue = Panel:ValueFunction() end + + Panel:LegacySetValue(RealValue) end end) end diff --git a/lua/acf/client/menu_items/weapons_menu.lua b/lua/acf/client/menu_items/weapons_menu.lua index b28ed4f6a..281c35fb0 100644 --- a/lua/acf/client/menu_items/weapons_menu.lua +++ b/lua/acf/client/menu_items/weapons_menu.lua @@ -113,6 +113,13 @@ local function CreateMenu(Menu) Menu:EndTemporal(self) end + local Test = Menu:AddComboBox() + Test:TrackDataVar("WeaponClass") + Test:TrackDataVar("Weapon") + Test:SetValueFunction(function() + return ACF.ReadString("WeaponClass") .. " - " .. ACF.ReadString("Weapon") + end) + LoadSortedList(ClassList, Weapons, "Name") LoadSortedList(CrateList, Crates, "ID") LoadSortedList(AmmoList, AmmoTypes, "Name") From bae3e43b3ab46b8ff38f61976768726c8d69aa61 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Mon, 24 Feb 2020 03:45:23 -0300 Subject: [PATCH 017/279] Fixed tonumber/tostring receiving nil values --- lua/acf/base/util/cl_util.lua | 12 ++++++++++-- lua/acf/base/util/sv_util.lua | 26 ++++++++++++++++++++------ 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/lua/acf/base/util/cl_util.lua b/lua/acf/base/util/cl_util.lua index e7855483b..3a4ecfe27 100644 --- a/lua/acf/base/util/cl_util.lua +++ b/lua/acf/base/util/cl_util.lua @@ -90,13 +90,21 @@ do -- Tool data functions function ACF.ReadNumber(Key) if not Key then return 0 end - return tonumber(ToolData[Key]) + local Data = ToolData[Key] + + if Data == nil then return 0 end + + return tonumber(Data) end function ACF.ReadString(Key) if not Key then return "" end - return tostring(ToolData[Key]) + local Data = ToolData[Key] + + if Data == nil then return "" end + + return tostring(Data) end end diff --git a/lua/acf/base/util/sv_util.lua b/lua/acf/base/util/sv_util.lua index 42a3980fd..c5741c8f5 100644 --- a/lua/acf/base/util/sv_util.lua +++ b/lua/acf/base/util/sv_util.lua @@ -103,24 +103,38 @@ do -- Tool data functions end function ACF.ReadBool(Player, Key) + if not IsValid(Player) then return false end if not Key then return false end - if not ToolData[Player] then return false end - return tobool(ToolData[Player][Key]) + local Data = ToolData[Player] + + if not Data then return false end + + return tobool(Data[Key]) end function ACF.ReadNumber(Player, Key) + if not IsValid(Player) then return 0 end if not Key then return 0 end - if not ToolData[Player] then return 0 end - return tonumber(ToolData[Player][Key]) + local Data = ToolData[Player] + + if not Data then return 0 end + if not Data[Key] then return 0 end + + return tonumber(Data[Key]) end function ACF.ReadString(Player, Key) + if not IsValid(Player) then return "" end if not Key then return "" end - if not ToolData[Player] then return "" end - return tostring(ToolData[Player][Key]) + local Data = ToolData[Player] + + if not Data then return "" end + if not Data[Key] then return "" end + + return tostring(Data[Key]) end end end From ba732ccfe5bd69b316d0394b1c920fa00d5421f1 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Mon, 24 Feb 2020 03:48:13 -0300 Subject: [PATCH 018/279] Fixed panel update conflict when changing a tool data variable - Panel datavars are now separated between setters and trackers. When a datavar is changed, setter panels will be updated first, followed by tracker panels. - Added test sliders for projectile and propellant. --- lua/acf/base/util/cl_util.lua | 106 +++++++++++++++------ lua/acf/client/menu_items/weapons_menu.lua | 30 ++++++ 2 files changed, 106 insertions(+), 30 deletions(-) diff --git a/lua/acf/base/util/cl_util.lua b/lua/acf/base/util/cl_util.lua index 3a4ecfe27..56f26b931 100644 --- a/lua/acf/base/util/cl_util.lua +++ b/lua/acf/base/util/cl_util.lua @@ -143,40 +143,70 @@ do -- Tool data functions do -- Panel functions local PANEL = FindMetaTable("Panel") - local Variables = {} - local Panels = {} + local Trackers = {} + local Setters = {} + local Variables = { + Trackers = {}, + Setters = {}, + } + + local function AddVariable(Panel, Key, Target) + local Data = Variables[Target] + local VData = Data[Key] + + if not VData then + Data[Key] = { + [Panel] = true + } + else + VData[Panel] = true + end + end - local function AddVariable(Panel, Key) - local PData = Panels[Panel] - local VData = Variables[Key] + local function AddTracker(Panel, Key) + local Data = Trackers[Panel] - if not PData then - Panels[Panel] = { + if not Data then + Trackers[Panel] = { [Key] = true } else - PData[Key] = true + Data[Key] = true end - if not VData then - Variables[Key] = { - [Panel] = true + AddVariable(Panel, Key, "Trackers") + end + + local function AddSetter(Panel, Key) + local Data = Setters[Panel] + + if not Data then + Setters[Panel] = { + [Key] = true } else - VData[Panel] = true + Data[Key] = true end + + AddVariable(Panel, Key, "Setters") end local function ClearVariables(Panel) - local Vars = Panels[Panel] - - if not Vars then return end + if Trackers[Panel] then + for K in pairs(Trackers[Panel]) do + Variables.Trackers[K][Panel] = nil + end - for K in pairs(Vars) do - Variables[K][Panel] = nil + Trackers[Panel] = nil end - Panels[Panel] = nil + if Setters[Panel] then + for K in pairs(Setters[Panel]) do + Variables.Setters[K][Panel] = nil + end + + Setters[Panel] = nil + end end local function LoadFunctions(Panel) @@ -186,11 +216,12 @@ do -- Tool data functions Panel.LegacyRemove = Panel.Remove function Panel:SetValue(Value) - if not self.DataVar then - return Panel:LegacySetValue(Value) + if self.DataVar then + ACF.WriteValue(self.DataVar, Value) + return end - ACF.WriteValue(self.DataVar, Value) + self:LegacySetValue(Value) end function Panel:Remove() @@ -206,7 +237,7 @@ do -- Tool data functions self.DataVar = Key - AddVariable(self, Key) + AddSetter(self, Key) LoadFunctions(self) if not ToolData[Key] then @@ -215,7 +246,7 @@ do -- Tool data functions end function PANEL:TrackDataVar(Key) - AddVariable(self, Key) + AddTracker(self, Key) LoadFunctions(self) end @@ -244,18 +275,33 @@ do -- Tool data functions end hook.Add("OnToolDataUpdate", "ACF Update Panel Values", function(Key, Value) - local Affected = Variables[Key] + local TrackerPanels = Variables.Trackers[Key] + local SetterPanels = Variables.Setters[Key] - if not Affected then return end + -- First we'll process the panels that set the value of this key + if SetterPanels then + for Panel in pairs(SetterPanels) do + local NewValue = Value - for Panel in pairs(Affected) do - local RealValue = Value + if Panel.ValueFunction then + NewValue = Panel:ValueFunction() + end - if Panel.ValueFunction then - RealValue = Panel:ValueFunction() + Panel:LegacySetValue(NewValue) end + end - Panel:LegacySetValue(RealValue) + -- Then we'll process the panels that just keep track of this value + if TrackerPanels then + for Panel in pairs(TrackerPanels) do + local NewValue = Value + + if Panel.ValueFunction then + NewValue = Panel:ValueFunction() + end + + Panel:LegacySetValue(NewValue) + end end end) end diff --git a/lua/acf/client/menu_items/weapons_menu.lua b/lua/acf/client/menu_items/weapons_menu.lua index 281c35fb0..11f3919b0 100644 --- a/lua/acf/client/menu_items/weapons_menu.lua +++ b/lua/acf/client/menu_items/weapons_menu.lua @@ -120,6 +120,36 @@ local function CreateMenu(Menu) return ACF.ReadString("WeaponClass") .. " - " .. ACF.ReadString("Weapon") end) + local Test1 = Menu:AddSlider("Projectile", 0, 10, 2) + Test1:SetDataVar("Projectile") + Test1:TrackDataVar("Propellant") + Test1:SetValueFunction(function(Panel) + local Min, Max = Panel:GetMin(), Panel:GetMax() + local Projectile = math.Clamp(ACF.ReadNumber("Projectile"), Min, Max) + local Propellant = ACF.ReadNumber("Propellant") + local Difference = Max - Projectile + + ACF.WriteValue("Projectile", Projectile) + ACF.WriteValue("Propellant", math.min(Propellant, Difference)) + + return Projectile + end) + + local Test2 = Menu:AddSlider("Propellant", 0, 10, 2) + Test2:SetDataVar("Propellant") + Test2:TrackDataVar("Projectile") + Test2:SetValueFunction(function(Panel) + local Min, Max = Panel:GetMin(), Panel:GetMax() + local Projectile = ACF.ReadNumber("Projectile") + local Propellant = math.Clamp(ACF.ReadNumber("Propellant"), Min, Max) + local Difference = Max - Propellant + + ACF.WriteValue("Propellant", Propellant) + ACF.WriteValue("Projectile", math.min(Projectile, Difference)) + + return Propellant + end) + LoadSortedList(ClassList, Weapons, "Name") LoadSortedList(CrateList, Crates, "ID") LoadSortedList(AmmoList, AmmoTypes, "Name") From a6d58c47045111f71464a33d06758674390cb580 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Thu, 27 Feb 2020 02:10:31 -0300 Subject: [PATCH 019/279] Fixed DataVar tracking panel update - DataVar tracking panels will now only update if they have a custom value function. --- lua/acf/base/util/cl_util.lua | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/lua/acf/base/util/cl_util.lua b/lua/acf/base/util/cl_util.lua index 56f26b931..ac793a780 100644 --- a/lua/acf/base/util/cl_util.lua +++ b/lua/acf/base/util/cl_util.lua @@ -294,13 +294,9 @@ do -- Tool data functions -- Then we'll process the panels that just keep track of this value if TrackerPanels then for Panel in pairs(TrackerPanels) do - local NewValue = Value - - if Panel.ValueFunction then - NewValue = Panel:ValueFunction() - end + if not Panel.ValueFunction then continue end - Panel:LegacySetValue(NewValue) + Panel:LegacySetValue(Panel:ValueFunction()) end end end) From 44b7ce75fce85f318bc1433b49d3921c80aaa0c3 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Thu, 27 Feb 2020 02:14:04 -0300 Subject: [PATCH 020/279] Update round functions - All previously existing round function were moved inside the ACF namespace. - ACF.RoundBaseGunpowder was slightly modified to support the new menu changes. - Added ACF.GetWeaponBlacklist function to help reduce the amount of code needed to blacklist multiple weapon classes. --- lua/acf/base/sh_round_functions.lua | 103 ++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 lua/acf/base/sh_round_functions.lua diff --git a/lua/acf/base/sh_round_functions.lua b/lua/acf/base/sh_round_functions.lua new file mode 100644 index 000000000..9968d5043 --- /dev/null +++ b/lua/acf/base/sh_round_functions.lua @@ -0,0 +1,103 @@ +function ACF.RoundBaseGunpowder(ToolData, Data) + local ClassData = ACF.Classes.Weapons[ToolData.WeaponClass] + local WeaponData = ClassData and ClassData.Lookup[ToolData.Weapon] + + if not WeaponData then return Data, {} end + + local RoundData = WeaponData.Round + local Projectile = ToolData.Projectile + local Propellant = ToolData.Propellant + local GUIData = {} + + Data.Caliber = WeaponData.Caliber + Data.FrArea = 3.1416 * (Data.Caliber * 0.05) ^ 2 + Data.Tracer = ToolData.Tracer and math.min(50 / Data.Caliber, 2.5) or 0 + + GUIData.MaxTotalLength = RoundData.MaxLength * (Data.LengthAdj or 1) + + local PropMax = RoundData.PropMass * 1000 / ACF.PDensity / Data.FrArea --Current casing absolute max propellant capacity + local CurLength = Projectile + math.min(Propellant, PropMax) + Data.Tracer + + GUIData.MinPropLength = 0.01 + GUIData.MaxPropLength = math.max(math.min(GUIData.MaxTotalLength - CurLength + Propellant, PropMax), GUIData.MinPropLength) --Check if the desired prop lenght fits in the case and doesn't exceed the gun max + GUIData.MinProjLength = Data.Caliber * 0.15 + GUIData.MaxProjLength = math.max(GUIData.MaxTotalLength - CurLength + Projectile, GUIData.MinProjLength) --Check if the desired proj lenght fits in the case + + local Ratio = math.min((GUIData.MaxTotalLength - Data.Tracer) / (Projectile + math.min(Propellant, PropMax)), 1) + + Data.ProjLength = math.Clamp(Projectile * Ratio, GUIData.MinProjLength, GUIData.MaxProjLength) + Data.PropLength = math.Clamp(Propellant * Ratio, GUIData.MinPropLength, GUIData.MaxPropLength) + Data.PropMass = Data.FrArea * (Data.PropLength * ACF.PDensity / 1000) --Volume of the case as a cylinder * Powder density converted from g to kg + Data.RoundVolume = Data.FrArea * (Data.ProjLength + Data.PropLength) + + GUIData.ProjVolume = Data.FrArea * Data.ProjLength + + return Data, GUIData +end + +local Classes = ACF.Classes +local Ignore = { + -- Old + GunClass = true, + Radar = true, + Rack = true, + -- New/upcoming + Components = true, + AmmoTypes = true, + FuelTanks = true, + Gearboxes = true, + Guidances = true, + Engines = true, + Sensors = true, + Crates = true, + Racks = true, + Fuzes = true, +} + +function ACF.GetWeaponBlacklist(Whitelist) + local Result = {} + + for K, V in pairs(Classes) do + if Ignore[K] then continue end + + for ID in pairs(V) do + if Whitelist[ID] then continue end + + Result[ID] = true + end + end + + return Result +end + +function ACF.RoundShellCapacity(Momentum, FrArea, Caliber, ProjLength) + local MinWall = 0.2 + ((Momentum / FrArea) ^ 0.7) * 0.02 --The minimal shell wall thickness required to survive firing at the current energy level + local Length = math.max(ProjLength - MinWall, 0) + local Radius = math.max((Caliber * 0.05) - MinWall, 0) + local Volume = 3.1416 * Radius ^ 2 * Length + + return Volume, Length, Radius --Returning the cavity volume and the minimum wall thickness +end + +function ACF.RicoProbability(Rico, Speed) + local MinAngle = math.min(Rico - Speed * 0.066, 89) + + return { + Min = math.Round(math.max(MinAngle, 0.01), 2), + Mean = math.Round(math.max(MinAngle + (90 - MinAngle) / 2, 0.01), 2), + Max = 90 + } +end + +--Formula from https://mathscinotes.wordpress.com/2013/10/03/parameter-determination-for-pejsa-velocity-model/ +--not terribly accurate for acf, particularly small caliber (7.62mm off by 120 m/s at 800m), but is good enough for quick indicator +--range in m, vel is m/s +function ACF.PenRanging(MuzzleVel, DragCoef, ProjMass, PenArea, LimitVel, Range) + local V0 = MuzzleVel * 39.37 * ACF.Scale --initial velocity + local D0 = DragCoef * V0 ^ 2 / ACF.DragDiv --initial drag + local K1 = (D0 / (V0 ^ 1.5)) ^ -1 --estimated drag coefficient + local Vel = (math.sqrt(V0) - ((Range * 39.37) / (2 * K1))) ^ 2 + local Pen = ACF_Kinetic(Vel, ProjMass, LimitVel).Penetration / PenArea * ACF.KEtoRHA + + return Vel * 0.0254, Pen +end From 948924ce54f807c2062a16cd9f0186b5b2757037 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Thu, 27 Feb 2020 02:17:47 -0300 Subject: [PATCH 021/279] Updated all ammo blacklists - Ammo blacklists are now lookup tables. --- lua/acf/shared/ammo_types/ap.lua | 6 ++- lua/acf/shared/ammo_types/aphe.lua | 7 ++- lua/acf/shared/ammo_types/fl.lua | 9 +++- lua/acf/shared/ammo_types/he.lua | 5 +- lua/acf/shared/ammo_types/heat.lua | 9 +++- lua/acf/shared/ammo_types/refill.lua | 1 + lua/acf/shared/ammo_types/smoke.lua | 12 ++++- lua/acf/shared/rounds/acf_roundfunctions.lua | 48 ++++++++++---------- 8 files changed, 68 insertions(+), 29 deletions(-) diff --git a/lua/acf/shared/ammo_types/ap.lua b/lua/acf/shared/ammo_types/ap.lua index 42db9e78c..5785050c6 100644 --- a/lua/acf/shared/ammo_types/ap.lua +++ b/lua/acf/shared/ammo_types/ap.lua @@ -6,7 +6,11 @@ function Ammo:OnLoaded() self.Type = "Ammo" self.Model = "models/munitions/round_100mm_shot.mdl" self.Description = "A shell made out of a solid piece of steel, meant to penetrate armor." - self.Blacklist = { "MO", "SL", "SB" } + self.Blacklist = { + MO = true, + SL = true, + SB = true, + } end function Ammo.Create(_, BulletData) diff --git a/lua/acf/shared/ammo_types/aphe.lua b/lua/acf/shared/ammo_types/aphe.lua index 14ca2ba11..a740c19cd 100644 --- a/lua/acf/shared/ammo_types/aphe.lua +++ b/lua/acf/shared/ammo_types/aphe.lua @@ -5,7 +5,12 @@ function Ammo:OnLoaded() self.Name = "Armor Piercing High Explosive" self.Description = "An armor piercing round with a cavity for High explosives. Less capable of defeating armor than plain Armor Piercing, but will explode after penetration" - self.Blacklist = { "MO", "MG", "SL", "RAC" } + self.Blacklist = { + MO = true, + MG = true, + SL = true, + RAC = true, + } end function Ammo.Convert(_, PlayerData) diff --git a/lua/acf/shared/ammo_types/fl.lua b/lua/acf/shared/ammo_types/fl.lua index 07b3c3ffc..a670b59a2 100644 --- a/lua/acf/shared/ammo_types/fl.lua +++ b/lua/acf/shared/ammo_types/fl.lua @@ -6,7 +6,14 @@ function Ammo:OnLoaded() self.Name = "Flechette" self.Model = "models/munitions/dart_100mm.mdl" self.Description = "Flechette rounds contain several long thin steel spikes, functioning as a shotgun shell for cannons. While it seems like the spikes would penetrate well, they tend to tumble in flight and impact at less than ideal angles, causing only minor penetration and structural damage. They are best used against infantry or lightly armored mobile targets such as aircraft or light tanks, since flechettes trade brute damage for a better chance to hit." - self.Blacklist = { "AC", "RAC", "MG", "HMG", "GL", "SL" } + self.Blacklist = { + AC = true, + RAC = true, + MG = true, + HMG = true, + GL = true, + SL = true, + } end function Ammo.Create(Gun, BulletData) diff --git a/lua/acf/shared/ammo_types/he.lua b/lua/acf/shared/ammo_types/he.lua index 382a9725d..3737c9eab 100644 --- a/lua/acf/shared/ammo_types/he.lua +++ b/lua/acf/shared/ammo_types/he.lua @@ -5,7 +5,10 @@ function Ammo:OnLoaded() self.Name = "High Explosive" self.Description = "A shell filled with explosives, detonating on impact." - self.Blacklist = { "MG", "RAC" } + self.Blacklist = { + MG = true, + RAC = true, + } end function Ammo.Convert(_, PlayerData) diff --git a/lua/acf/shared/ammo_types/heat.lua b/lua/acf/shared/ammo_types/heat.lua index 1fa937642..0e45e03e6 100644 --- a/lua/acf/shared/ammo_types/heat.lua +++ b/lua/acf/shared/ammo_types/heat.lua @@ -6,7 +6,14 @@ function Ammo:OnLoaded() self.Name = "High Explosive Anti-Tank" self.Description = "A shell with a shaped charge. When the round detonates, the explosive energy is focused into driving a small molten metal penetrator into the victim with extreme force, though this results in reduced damage from the explosion itself. Multiple layers of armor will dissipate the penetrator quickly." - self.Blacklist = { "MG", "HMG", "RAC", "AC", "SL", "SB" } + self.Blacklist = { + MG = true, + HMG = true, + RAC = true, + AC = true, + SL = true, + SB = true, + } end function Ammo.ConeCalc(ConeAngle, Radius) diff --git a/lua/acf/shared/ammo_types/refill.lua b/lua/acf/shared/ammo_types/refill.lua index 97daad816..fda435cbf 100644 --- a/lua/acf/shared/ammo_types/refill.lua +++ b/lua/acf/shared/ammo_types/refill.lua @@ -3,6 +3,7 @@ local Ammo = ACF.RegisterAmmoType("Refill", "AP") function Ammo:OnLoaded() self.Name = "Refill" self.Description = "Ammunition refilling station." + self.Unlistable = true self.Blacklist = {} end diff --git a/lua/acf/shared/ammo_types/smoke.lua b/lua/acf/shared/ammo_types/smoke.lua index 267e94013..4c72fc069 100644 --- a/lua/acf/shared/ammo_types/smoke.lua +++ b/lua/acf/shared/ammo_types/smoke.lua @@ -3,7 +3,17 @@ local Ammo = ACF.RegisterAmmoType("SM", "AP") function Ammo:OnLoaded() self.Name = "Smoke" self.Description = "A shell filled white phosporous, detonating on impact. Smoke filler produces a long lasting cloud but takes a while to be effective, whereas WP filler quickly creates a cloud that also dissipates quickly." - self.Blacklist = { "MG", "C", "GL", "HMG", "AL", "AC", "RAC", "SA", "SC" } + self.Blacklist = { + MG = true, + C = true, + GL = true, + HMG = true, + AL = true, + AC = true, + RAC = true, + SA = true, + SC = true, + } end function Ammo.Convert(_, PlayerData) diff --git a/lua/acf/shared/rounds/acf_roundfunctions.lua b/lua/acf/shared/rounds/acf_roundfunctions.lua index d6ba029d9..e810432b0 100644 --- a/lua/acf/shared/rounds/acf_roundfunctions.lua +++ b/lua/acf/shared/rounds/acf_roundfunctions.lua @@ -1,28 +1,30 @@ function ACF_RoundBaseGunpowder(PlayerData, Data, ServerData, GUIData) - local BulletMax = ACF.Weapons["Guns"][PlayerData["Id"]]["round"] - GUIData["MaxTotalLength"] = BulletMax["maxlength"] * (Data["LengthAdj"] or 1) - Data["Caliber"] = ACF.Weapons["Guns"][PlayerData["Id"]]["caliber"] - Data["FrArea"] = 3.1416 * (Data["Caliber"] / 2) ^ 2 - Data["Tracer"] = 0 - - --Check for tracer - if PlayerData["Data10"] * 1 > 0 then - Data["Tracer"] = math.min(5 / Data["Caliber"], 2.5) --Tracer space calcs - end - - local PropMax = (BulletMax["propweight"] * 1000 / ACF.PDensity) / Data["FrArea"] --Current casing absolute max propellant capacity - local CurLength = (PlayerData["ProjLength"] + math.min(PlayerData["PropLength"], PropMax) + Data["Tracer"]) - GUIData["MinPropLength"] = 0.01 - GUIData["MaxPropLength"] = math.max(math.min(GUIData["MaxTotalLength"] - CurLength + PlayerData["PropLength"], PropMax), GUIData["MinPropLength"]) --Check if the desired prop lenght fits in the case and doesn't exceed the gun max - GUIData["MinProjLength"] = Data["Caliber"] * 1.5 - GUIData["MaxProjLength"] = math.max(GUIData["MaxTotalLength"] - CurLength + PlayerData["ProjLength"], GUIData["MinProjLength"]) --Check if the desired proj lenght fits in the case - local Ratio = math.min((GUIData["MaxTotalLength"] - Data["Tracer"]) / (PlayerData["ProjLength"] + math.min(PlayerData["PropLength"], PropMax)), 1) --This is to check the current ratio between elements if i need to clamp it - Data["ProjLength"] = math.Clamp(PlayerData["ProjLength"] * Ratio, GUIData["MinProjLength"], GUIData["MaxProjLength"]) - Data["PropLength"] = math.Clamp(PlayerData["PropLength"] * Ratio, GUIData["MinPropLength"], GUIData["MaxPropLength"]) - Data["PropMass"] = Data["FrArea"] * (Data["PropLength"] * ACF.PDensity / 1000) --Volume of the case as a cylinder * Powder density converted from g to kg - GUIData["ProjVolume"] = Data["FrArea"] * Data["ProjLength"] - Data["RoundVolume"] = Data["FrArea"] * (Data["ProjLength"] + Data["PropLength"]) + local Bullet = ACF.Weapons.Guns[PlayerData.Id] + local Round = Bullet.round + + Data.Caliber = Bullet.caliber + Data.FrArea = 3.1416 * (Data.Caliber * 0.5) ^ 2 + Data.Tracer = tonumber(PlayerData.Data10) > 0 and math.min(5 / Data.Caliber, 2.5) or 0 + + GUIData.MaxTotalLength = Round.maxlength * (Data.LengthAdj or 1) + + local PropMax = Round.propweight * 1000 / ACF.PDensity / Data.FrArea --Current casing absolute max propellant capacity + local CurLength = PlayerData.ProjLength + math.min(PlayerData.PropLength, PropMax) + Data.Tracer + + GUIData.MinPropLength = 0.01 + GUIData.MaxPropLength = math.max(math.min(GUIData.MaxTotalLength - CurLength + PlayerData.PropLength, PropMax), GUIData.MinPropLength) --Check if the desired prop lenght fits in the case and doesn't exceed the gun max + GUIData.MinProjLength = Data.Caliber * 1.5 + GUIData.MaxProjLength = math.max(GUIData.MaxTotalLength - CurLength + PlayerData.ProjLength, GUIData.MinProjLength) --Check if the desired proj lenght fits in the case + + local Ratio = math.min((GUIData.MaxTotalLength - Data.Tracer) / (PlayerData.ProjLength + math.min(PlayerData.PropLength, PropMax)), 1) --This is to check the current ratio between elements if i need to clamp it + + Data.ProjLength = math.Clamp(PlayerData.ProjLength * Ratio, GUIData.MinProjLength, GUIData.MaxProjLength) + Data.PropLength = math.Clamp(PlayerData.PropLength * Ratio, GUIData.MinPropLength, GUIData.MaxPropLength) + Data.PropMass = Data.FrArea * (Data.PropLength * ACF.PDensity / 1000) --Volume of the case as a cylinder * Powder density converted from g to kg + Data.RoundVolume = Data.FrArea * (Data.ProjLength + Data.PropLength) + + GUIData.ProjVolume = Data.FrArea * Data.ProjLength return PlayerData, Data, ServerData, GUIData end From 21b8bbbbeaf50e1a4d542316ea034f031d082a74 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Thu, 27 Feb 2020 02:22:22 -0300 Subject: [PATCH 022/279] Update ammo selection combobox - The ammo type selection combobox will now filter the blacklisted ammo types the current weapon class can't use. - Added PANEL:AddCheckBox function to acf_panel vgui object. - acf_panel's sliders will now use the ACF_Control font. - Divided Ammo.Convert into a client and serverside version, Ammo.ClientConvert and Ammo.ServerConvert respectively, along with adding a new convert method that will be shared by both. - Added test menu for Armor Piercing rounds. --- lua/acf/client/menu_items/weapons_menu.lua | 70 +++++------ lua/acf/shared/ammo_types/ap.lua | 133 +++++++++++++++------ lua/vgui/acf_panel.lua | 11 ++ 3 files changed, 139 insertions(+), 75 deletions(-) diff --git a/lua/acf/client/menu_items/weapons_menu.lua b/lua/acf/client/menu_items/weapons_menu.lua index 11f3919b0..3fe9bea5d 100644 --- a/lua/acf/client/menu_items/weapons_menu.lua +++ b/lua/acf/client/menu_items/weapons_menu.lua @@ -1,9 +1,28 @@ local AmmoTypes = ACF.Classes.AmmoTypes local Weapons = ACF.Classes.Weapons local Crates = ACF.Classes.Crates +local AmmoLists = {} local Selected = {} local Sorted = {} +local function GetAmmoList(Class) + if not Class then return {} end + if AmmoLists[Class] then return AmmoLists[Class] end + + local Result = {} + + for K, V in pairs(AmmoTypes) do + if V.Unlistable then continue end + if V.Blacklist[Class] then continue end + + Result[K] = V + end + + AmmoLists[Class] = Result + + return Result +end + local function LoadSortedList(Panel, List, Member) local Choices = Sorted[List] @@ -61,6 +80,7 @@ local function CreateMenu(Menu) ClassDesc:SetText(Data.Description) LoadSortedList(EntList, Data.Items, "Caliber") + LoadSortedList(AmmoList, GetAmmoList(Data.ID), "Name") end function EntList:OnSelect(Index, _, Data) @@ -80,6 +100,8 @@ local function CreateMenu(Menu) EntName:SetText(Data.Name) EntData:SetText(EntText:format(Data.Mass, math.Round(Firerate, 2), ClassData.Spread * 100, Magazine)) + + AmmoList:UpdateMenu() end function CrateList:OnSelect(Index, _, Data) @@ -98,11 +120,19 @@ local function CreateMenu(Menu) self.Selected = Data - local Choices = Sorted[AmmoTypes] + local Choices = Sorted[GetAmmoList(ClassList.Selected.ID)] Selected[Choices] = Index ACF.WriteValue("Ammo", Data.ID) + self:UpdateMenu() + end + + function AmmoList:UpdateMenu() + if not self.Selected then return end + + local Data = self.Selected + Menu:ClearTemporal(self) Menu:StartTemporal(self) @@ -113,46 +143,8 @@ local function CreateMenu(Menu) Menu:EndTemporal(self) end - local Test = Menu:AddComboBox() - Test:TrackDataVar("WeaponClass") - Test:TrackDataVar("Weapon") - Test:SetValueFunction(function() - return ACF.ReadString("WeaponClass") .. " - " .. ACF.ReadString("Weapon") - end) - - local Test1 = Menu:AddSlider("Projectile", 0, 10, 2) - Test1:SetDataVar("Projectile") - Test1:TrackDataVar("Propellant") - Test1:SetValueFunction(function(Panel) - local Min, Max = Panel:GetMin(), Panel:GetMax() - local Projectile = math.Clamp(ACF.ReadNumber("Projectile"), Min, Max) - local Propellant = ACF.ReadNumber("Propellant") - local Difference = Max - Projectile - - ACF.WriteValue("Projectile", Projectile) - ACF.WriteValue("Propellant", math.min(Propellant, Difference)) - - return Projectile - end) - - local Test2 = Menu:AddSlider("Propellant", 0, 10, 2) - Test2:SetDataVar("Propellant") - Test2:TrackDataVar("Projectile") - Test2:SetValueFunction(function(Panel) - local Min, Max = Panel:GetMin(), Panel:GetMax() - local Projectile = ACF.ReadNumber("Projectile") - local Propellant = math.Clamp(ACF.ReadNumber("Propellant"), Min, Max) - local Difference = Max - Propellant - - ACF.WriteValue("Propellant", Propellant) - ACF.WriteValue("Projectile", math.min(Projectile, Difference)) - - return Propellant - end) - LoadSortedList(ClassList, Weapons, "Name") LoadSortedList(CrateList, Crates, "ID") - LoadSortedList(AmmoList, AmmoTypes, "Name") end ACF.AddOptionItem("Entities", "Weapons", "gun", CreateMenu) diff --git a/lua/acf/shared/ammo_types/ap.lua b/lua/acf/shared/ammo_types/ap.lua index 5785050c6..7e1d225cf 100644 --- a/lua/acf/shared/ammo_types/ap.lua +++ b/lua/acf/shared/ammo_types/ap.lua @@ -17,24 +17,11 @@ function Ammo.Create(_, BulletData) ACF_CreateBullet(BulletData) end -function Ammo.Convert(_, PlayerData) - local Data = {} - local ServerData = {} - local GUIData = {} +function Ammo.BaseConvert(_, ToolData) + if not ToolData.Projectile then ToolData.Projectile = 0 end + if not ToolData.Propellant then ToolData.Propellant = 0 end - if not PlayerData.PropLength then - PlayerData.PropLength = 0 - end - - if not PlayerData.ProjLength then - PlayerData.ProjLength = 0 - end - - if not PlayerData.Data10 then - PlayerData.Data10 = 0 - end - - PlayerData, Data, ServerData, GUIData = ACF_RoundBaseGunpowder(PlayerData, Data, ServerData, GUIData) + local Data, GUIData = ACF.RoundBaseGunpowder(ToolData, {}) Data.ProjMass = Data.FrArea * (Data.ProjLength * 7.9 / 1000) --Volume of the projectile as a cylinder * density of steel Data.ShovePower = 0.2 @@ -46,31 +33,41 @@ function Ammo.Convert(_, PlayerData) Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass, Data.Caliber) Data.BoomPower = Data.PropMass - --Only the crates need this part - if SERVER then - ServerData.Id = PlayerData.Id - ServerData.Type = PlayerData.Type + return Data, GUIData +end - return table.Merge(Data, ServerData) - end +function Ammo.ClientConvert(_, ToolData) + local Data, GUIData = Ammo.BaseConvert(_, ToolData) - --Only the GUI needs this part - if CLIENT then - GUIData = table.Merge(GUIData, Ammo.GetDisplayData(Data)) + for K, V in pairs(GUIData) do + Data[K] = V + end - return table.Merge(Data, GUIData) + for K, V in pairs(Ammo.GetDisplayData(Data)) do + Data[K] = V end + + return Data +end + +function Ammo.ServerConvert(_, ToolData) + local Data = Ammo.BaseConvert(_, ToolData) + + Data.Id = ToolData.Weapon + Data.Type = ToolData.Ammo + + return Data end function Ammo.Network(Crate, BulletData) - Crate:SetNWString("AmmoType", "AP") - Crate:SetNWString("AmmoID", BulletData.Id) - Crate:SetNWFloat("Caliber", BulletData.Caliber) - Crate:SetNWFloat("ProjMass", BulletData.ProjMass) - Crate:SetNWFloat("PropMass", BulletData.PropMass) - Crate:SetNWFloat("DragCoef", BulletData.DragCoef) - Crate:SetNWFloat("MuzzleVel", BulletData.MuzzleVel) - Crate:SetNWFloat("Tracer", BulletData.Tracer) + Crate:SetNW2String("AmmoType", "AP") + Crate:SetNW2String("AmmoID", BulletData.Id) + Crate:SetNW2Float("Caliber", BulletData.Caliber) + Crate:SetNW2Float("ProjMass", BulletData.ProjMass) + Crate:SetNW2Float("PropMass", BulletData.PropMass) + Crate:SetNW2Float("DragCoef", BulletData.DragCoef) + Crate:SetNW2Float("MuzzleVel", BulletData.MuzzleVel) + Crate:SetNW2Float("Tracer", BulletData.Tracer) end function Ammo.GetDisplayData(BulletData) @@ -207,7 +204,71 @@ function Ammo.UpdateMenu(Panel) end function Ammo.MenuAction(Menu) - Menu:AddParagraph("Testing AP menu.") + local ToolData = { + Weapon = ACF.ReadString("Weapon"), + WeaponClass = ACF.ReadString("WeaponClass"), + Projectile = ACF.ReadNumber("Projectile"), + Propellant = ACF.ReadNumber("Propellant"), + Tracer = ACF.ReadBool("Tracer"), + } + + local Data = Ammo.ClientConvert(Panel, ToolData) + + Menu:AddParagraph(Ammo.Description) + + local Projectile = Menu:AddSlider("Projectile Length", Data.MinProjLength, Data.MaxProjLength, 2) + Projectile:SetDataVar("Projectile") + Projectile:TrackDataVar("Propellant") + Projectile:TrackDataVar("Tracer") + + local Propellant = Menu:AddSlider("Propellant Length", Data.MinPropLength, Data.MaxPropLength, 2) + Propellant:SetDataVar("Propellant") + Propellant:TrackDataVar("Projectile") + Propellant:TrackDataVar("Tracer") + + local Tracer = Menu:AddCheckBox("Tracer") + Tracer:SetDataVar("Tracer") + + --[[ + + local Test = Menu:AddComboBox() + Test:TrackDataVar("WeaponClass") + Test:TrackDataVar("Weapon") + Test:SetValueFunction(function() + return ACF.ReadString("WeaponClass") .. " - " .. ACF.ReadString("Weapon") + end) + + local Test1 = Menu:AddSlider("Projectile", 0, 10, 2) + Test1:SetDataVar("Projectile") + Test1:TrackDataVar("Propellant") + Test1:SetValueFunction(function(Panel) + local Min, Max = Panel:GetMin(), Panel:GetMax() + local Projectile = math.Clamp(ACF.ReadNumber("Projectile"), Min, Max) + local Propellant = ACF.ReadNumber("Propellant") + local Difference = Max - Projectile + + ACF.WriteValue("Projectile", Projectile) + ACF.WriteValue("Propellant", math.min(Propellant, Difference)) + + return Projectile + end) + + local Test2 = Menu:AddSlider("Propellant", 0, 10, 2) + Test2:SetDataVar("Propellant") + Test2:TrackDataVar("Projectile") + Test2:SetValueFunction(function(Panel) + local Min, Max = Panel:GetMin(), Panel:GetMax() + local Projectile = ACF.ReadNumber("Projectile") + local Propellant = math.Clamp(ACF.ReadNumber("Propellant"), Min, Max) + local Difference = Max - Propellant + + ACF.WriteValue("Propellant", Propellant) + ACF.WriteValue("Projectile", math.min(Projectile, Difference)) + + return Propellant + end) + + ]]-- end ACF.RegisterAmmoDecal("AP", "damage/ap_pen", "damage/ap_rico") diff --git a/lua/vgui/acf_panel.lua b/lua/vgui/acf_panel.lua index a1cb667a6..2c6967fc4 100644 --- a/lua/vgui/acf_panel.lua +++ b/lua/vgui/acf_panel.lua @@ -95,6 +95,15 @@ function PANEL:AddButton(Text, Command, ...) return Panel end +function PANEL:AddCheckBox(Text) + local Panel = self:AddPanel("DCheckBoxLabel") + Panel:SetText(Text or "Checkbox") + Panel:SetFont("ACF_Control") + Panel:SetDark(true) + + return Panel +end + function PANEL:AddTitle(Text) local Panel = self:AddPanel("DLabel") Panel:SetAutoStretchVertical(true) @@ -148,6 +157,8 @@ function PANEL:AddSlider(Title, Min, Max, Decimals) Panel:SetValue(Min) Panel:SetDark(true) + Panel.Label:SetFont("ACF_Control") + return Panel end From 636a4c7f6527603f77cca525eb3b0512ed0fee52 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sun, 1 Mar 2020 05:21:38 -0300 Subject: [PATCH 023/279] Added ACF.GetProperMass function - Added ACF.GetProperMass function to convert grams to a proper mass unit. --- lua/acf/base/util/sh_util.lua | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/lua/acf/base/util/sh_util.lua b/lua/acf/base/util/sh_util.lua index 38c748d23..4c14c2a97 100644 --- a/lua/acf/base/util/sh_util.lua +++ b/lua/acf/base/util/sh_util.lua @@ -101,7 +101,7 @@ do -- Ricochet/Penetration materials end end -do -- Time lapse function +do -- Unit conversion local Units = { { Unit = "year", Reduction = 1970 }, { Unit = "month", Reduction = 1 }, @@ -131,4 +131,16 @@ do -- Time lapse function end end end + + function ACF.GetProperMass(Grams) + local Unit, Mult = "g", 1 + + if Grams > 1000000 then + Unit, Mult = "t", 0.000001 + elseif Grams > 1000 then + Unit, Mult = "kg", 0.001 + end + + return math.Round(Grams * Mult, 2) .. " " .. Unit + end end From 984ea8300f78e120fc39d46d5880de9f736e97a2 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sun, 1 Mar 2020 05:24:07 -0300 Subject: [PATCH 024/279] Improved tool data network messages - Now the client will be able to send one update network message per key per tick. - Fixed tool data being unable to update a value if given false. --- lua/acf/base/util/cl_util.lua | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/lua/acf/base/util/cl_util.lua b/lua/acf/base/util/cl_util.lua index ac793a780..a7b7e631d 100644 --- a/lua/acf/base/util/cl_util.lua +++ b/lua/acf/base/util/cl_util.lua @@ -109,6 +109,7 @@ do -- Tool data functions end do -- Write function + local LastSent = {} local KeyPattern = "^[%w]+" local ValuePattern = "[%w]*[%.]?[%w]+$" @@ -119,7 +120,7 @@ do -- Tool data functions end local function IsValidValue(Value) - if not Value then return false end + if Value == nil then return false end return tostring(Value):match(ValuePattern) and true or false end @@ -131,13 +132,25 @@ do -- Tool data functions ToolData[Key] = Value - net.Start("ACF_ToolData") - net.WriteString(Key .. ":" .. Value) - net.SendToServer() - hook.Run("OnToolDataUpdate", Key, Value) - print("Sent", LocalPlayer(), Key, Value) + -- Allowing one network message per key per tick + if timer.Exists("ACF WriteValue " .. Key) then return end + + timer.Create("ACF WriteValue " .. Key, 0, 1, function() + local NewValue = tostring(ToolData[Key]) + + -- Preventing network message spam if value hasn't really changed + if LastSent[Key] == NewValue then return end + + LastSent[Key] = NewValue + + net.Start("ACF_ToolData") + net.WriteString(Key .. ":" .. NewValue) + net.SendToServer() + + print("Sent", LocalPlayer(), Key, NewValue) + end) end end From b8dafdb665032dbbd7517c52fc26d104c23531c4 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sun, 1 Mar 2020 05:27:19 -0300 Subject: [PATCH 025/279] Improved tool data panel functions - Now PANEL:SetDataVar and PANEL:TrackDataVar are capable of receiving a second argument to define which panel function to override. - Value functions will receive a second argument as true if the function was called for data var tracking. --- lua/acf/base/util/cl_util.lua | 62 +++++++++++++++++++++++------------ 1 file changed, 41 insertions(+), 21 deletions(-) diff --git a/lua/acf/base/util/cl_util.lua b/lua/acf/base/util/cl_util.lua index a7b7e631d..71578fa53 100644 --- a/lua/acf/base/util/cl_util.lua +++ b/lua/acf/base/util/cl_util.lua @@ -223,32 +223,42 @@ do -- Tool data functions end local function LoadFunctions(Panel) - if Panel.LegacyRemove then return end + if not Panel.LegacyRemove then + Panel.LegacyRemove = Panel.Remove - Panel.LegacySetValue = Panel.SetValue - Panel.LegacyRemove = Panel.Remove + function Panel:Remove() + ClearVariables(self) - function Panel:SetValue(Value) - if self.DataVar then - ACF.WriteValue(self.DataVar, Value) - return + self:LegacyRemove() end - - self:LegacySetValue(Value) end - function Panel:Remove() - ClearVariables(self) + if Panel.Hijack and Panel.Hijack ~= Panel.PrevHijack then + if Panel.PrevHijack then + Panel[Panel.PrevHijack] = Panel.OldSetFunc + end + + Panel.PrevHijack = Panel.Hijack + Panel.OldSetFunc = Panel[Panel.Hijack] + + function Panel:NewSetFunc(Value) + if self.DataVar then + ACF.WriteValue(self.DataVar, Value) + return + end + + self:OldSetFunc(Value) + end - self:LegacyRemove() + Panel[Panel.Hijack] = Panel.NewSetFunc end end - function PANEL:SetDataVar(Key) + function PANEL:SetDataVar(Key, Function) if not Key then return end - if not self.SetValue then return end self.DataVar = Key + self.Hijack = Function or self.Hijack or "SetValue" AddSetter(self, Key) LoadFunctions(self) @@ -258,7 +268,9 @@ do -- Tool data functions end end - function PANEL:TrackDataVar(Key) + function PANEL:TrackDataVar(Key, Function) + self.Hijack = Function or self.Hijack or "SetValue" + AddTracker(self, Key) LoadFunctions(self) end @@ -270,17 +282,25 @@ do -- Tool data functions self.ValueFunction = Function - self:LegacySetValue(self:ValueFunction()) + if self.Hijack then + self:NewSetFunc(self:ValueFunction()) + end end function PANEL:ClearDataVars() if self.LegacyRemove then - self.SetValue = self.LegacySetValue self.Remove = self.LegacyRemove - self.LegacySetValue = nil self.LegacyRemove = nil end + if self.Hijack then + self[self.Hijack] = self.OldSetFunc + self.OldSetFunc = nil + self.NewSetFunc = nil + self.PrevHijack = nil + self.Hijack = nil + end + self.ValueFunction = nil self.DataVar = nil @@ -300,7 +320,7 @@ do -- Tool data functions NewValue = Panel:ValueFunction() end - Panel:LegacySetValue(NewValue) + Panel:OldSetFunc(NewValue) end end @@ -309,9 +329,9 @@ do -- Tool data functions for Panel in pairs(TrackerPanels) do if not Panel.ValueFunction then continue end - Panel:LegacySetValue(Panel:ValueFunction()) + Panel:OldSetFunc(Panel:ValueFunction(true)) end end end) end -end \ No newline at end of file +end From 7e2ee3060b72fb4614967ca87785c34ef8cfb780 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sun, 1 Mar 2020 05:29:08 -0300 Subject: [PATCH 026/279] Improved ACF.RoundBaseGunpower - Simplified ACF.RoundBaseGunpower by moving the values that will get updated more constantly to a separate function. --- lua/acf/base/sh_round_functions.lua | 49 ++++++++++++++++++----------- 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/lua/acf/base/sh_round_functions.lua b/lua/acf/base/sh_round_functions.lua index 9968d5043..d7a7dcc88 100644 --- a/lua/acf/base/sh_round_functions.lua +++ b/lua/acf/base/sh_round_functions.lua @@ -1,38 +1,51 @@ function ACF.RoundBaseGunpowder(ToolData, Data) local ClassData = ACF.Classes.Weapons[ToolData.WeaponClass] local WeaponData = ClassData and ClassData.Lookup[ToolData.Weapon] + local GUIData = {} - if not WeaponData then return Data, {} end + if not WeaponData then return Data, GUIData end local RoundData = WeaponData.Round - local Projectile = ToolData.Projectile - local Propellant = ToolData.Propellant - local GUIData = {} Data.Caliber = WeaponData.Caliber Data.FrArea = 3.1416 * (Data.Caliber * 0.05) ^ 2 - Data.Tracer = ToolData.Tracer and math.min(50 / Data.Caliber, 2.5) or 0 - GUIData.MaxTotalLength = RoundData.MaxLength * (Data.LengthAdj or 1) + GUIData.MaxRoundLength = math.Round(RoundData.MaxLength * (Data.LengthAdj or 1), 2) + GUIData.MinPropLength = 0.01 + GUIData.MinProjLength = math.Round(Data.Caliber * 0.15, 2) - local PropMax = RoundData.PropMass * 1000 / ACF.PDensity / Data.FrArea --Current casing absolute max propellant capacity - local CurLength = Projectile + math.min(Propellant, PropMax) + Data.Tracer + local DesiredProp = math.Round(RoundData.PropMass * 1000 / ACF.PDensity / Data.FrArea, 2) + local AllowedProp = GUIData.MaxRoundLength - GUIData.MinProjLength - GUIData.MinPropLength = 0.01 - GUIData.MaxPropLength = math.max(math.min(GUIData.MaxTotalLength - CurLength + Propellant, PropMax), GUIData.MinPropLength) --Check if the desired prop lenght fits in the case and doesn't exceed the gun max - GUIData.MinProjLength = Data.Caliber * 0.15 - GUIData.MaxProjLength = math.max(GUIData.MaxTotalLength - CurLength + Projectile, GUIData.MinProjLength) --Check if the desired proj lenght fits in the case + GUIData.MaxPropLength = math.min(DesiredProp, AllowedProp) -- GUIData.MaxRoundLength - GUIData.MinProjLength + GUIData.MaxProjLength = GUIData.MaxRoundLength - GUIData.MinPropLength + + ACF.UpdateRoundSpecs(ToolData, Data, GUIData) + + return Data, GUIData +end + +function ACF.UpdateRoundSpecs(ToolData, Data, GUIData) + GUIData = GUIData or Data - local Ratio = math.min((GUIData.MaxTotalLength - Data.Tracer) / (Projectile + math.min(Propellant, PropMax)), 1) + Data.Priority = Data.Priority or "Projectile" + Data.Tracer = ToolData.Tracer and math.Round(Data.Caliber * 0.015, 2) or 0 - Data.ProjLength = math.Clamp(Projectile * Ratio, GUIData.MinProjLength, GUIData.MaxProjLength) - Data.PropLength = math.Clamp(Propellant * Ratio, GUIData.MinPropLength, GUIData.MaxPropLength) + local Projectile = math.Clamp(ToolData.Projectile + Data.Tracer, GUIData.MinProjLength, GUIData.MaxProjLength) + local Propellant = math.Clamp(ToolData.Propellant, GUIData.MinPropLength, GUIData.MaxPropLength) + + if Data.Priority == "Projectile" then + Propellant = math.min(Propellant, GUIData.MaxRoundLength - Projectile, GUIData.MaxPropLength) + elseif Data.Priority == "Propellant" then + Projectile = math.min(Projectile, GUIData.MaxRoundLength - Propellant, GUIData.MaxProjLength) + end + + Data.ProjLength = math.Round(Projectile, 2) - Data.Tracer + Data.PropLength = math.Round(Propellant, 2) Data.PropMass = Data.FrArea * (Data.PropLength * ACF.PDensity / 1000) --Volume of the case as a cylinder * Powder density converted from g to kg Data.RoundVolume = Data.FrArea * (Data.ProjLength + Data.PropLength) GUIData.ProjVolume = Data.FrArea * Data.ProjLength - - return Data, GUIData end local Classes = ACF.Classes @@ -99,5 +112,5 @@ function ACF.PenRanging(MuzzleVel, DragCoef, ProjMass, PenArea, LimitVel, Range) local Vel = (math.sqrt(V0) - ((Range * 39.37) / (2 * K1))) ^ 2 local Pen = ACF_Kinetic(Vel, ProjMass, LimitVel).Penetration / PenArea * ACF.KEtoRHA - return Vel * 0.0254, Pen + return math.Round(Vel * 0.0254, 2), math.Round(Pen, 2) end From 0ab18a449e1120110e178bf6968badf7054db007 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sun, 1 Mar 2020 05:30:01 -0300 Subject: [PATCH 027/279] Added Armor Piercing menu --- lua/acf/client/menu_items/weapons_menu.lua | 7 +- lua/acf/shared/ammo_types/ap.lua | 164 +++++++++++---------- 2 files changed, 88 insertions(+), 83 deletions(-) diff --git a/lua/acf/client/menu_items/weapons_menu.lua b/lua/acf/client/menu_items/weapons_menu.lua index 3fe9bea5d..8f350e50c 100644 --- a/lua/acf/client/menu_items/weapons_menu.lua +++ b/lua/acf/client/menu_items/weapons_menu.lua @@ -51,8 +51,8 @@ local function LoadSortedList(Panel, List, Member) end local function CreateMenu(Menu) - local EntText = "Mass: %s kg\nFirerate: %s rpm\nSpread: %s degrees%s" - local MagText = "\nRounds: %s rounds\nReload: %s seconds" + local EntText = "Mass : %s kg\nFirerate : %s rpm\nSpread : %s degrees%s" + local MagText = "\nRounds : %s rounds\nReload : %s seconds" local ClassList = Menu:AddComboBox() local EntList = Menu:AddComboBox() @@ -65,7 +65,8 @@ local function CreateMenu(Menu) local CrateList = Menu:AddComboBox() local AmmoList = Menu:AddComboBox() - ACF.WriteValue("Class", "acf_gun") + ACF.WriteValue("PrimaryClass", "acf_gun") + ACF.WriteValue("SecondaryClass", "acf_ammo") function ClassList:OnSelect(Index, _, Data) if self.Selected == Data then return end diff --git a/lua/acf/shared/ammo_types/ap.lua b/lua/acf/shared/ammo_types/ap.lua index 7e1d225cf..5ae8cfbda 100644 --- a/lua/acf/shared/ammo_types/ap.lua +++ b/lua/acf/shared/ammo_types/ap.lua @@ -159,50 +159,6 @@ function Ammo.RicochetEffect(_, Bullet) util.Effect("ACF_Ricochet", Effect) end -function Ammo.CreateMenu(Panel, Table) - acfmenupanel:AmmoSelect(Ammo.Blacklist) - - acfmenupanel:CPanelText("Desc", "") --Description (Name, Desc) - acfmenupanel:CPanelText("LengthDisplay", "") --Total round length (Name, Desc) - acfmenupanel:AmmoSlider("PropLength", 0, 0, 1000, 3, "Propellant Length", "") --Propellant Length Slider (Name, Value, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("ProjLength", 0, 0, 1000, 3, "Projectile Length", "") --Projectile Length Slider (Name, Value, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoCheckbox("Tracer", "Tracer", "") --Tracer checkbox (Name, Title, Desc) - acfmenupanel:CPanelText("VelocityDisplay", "") --Proj muzzle velocity (Name, Desc) - acfmenupanel:CPanelText("PenetrationDisplay", "") --Proj muzzle penetration (Name, Desc) - - Ammo.UpdateMenu(Panel, Table) -end - -function Ammo.UpdateMenu(Panel) - local PlayerData = { - Id = acfmenupanel.AmmoData.Data.id, --AmmoSelect GUI - Type = "AP", --Hardcoded, match ACFRoundTypes table index - PropLength = acfmenupanel.AmmoData.PropLength, --PropLength slider - ProjLength = acfmenupanel.AmmoData.ProjLength, --ProjLength slider - Data10 = acfmenupanel.AmmoData.Tracer and 1 or 0 - } - - local Data = Ammo.Convert(Panel, PlayerData) - - RunConsoleCommand("acfmenu_data1", acfmenupanel.AmmoData.Data.id) - RunConsoleCommand("acfmenu_data2", PlayerData.Type) - RunConsoleCommand("acfmenu_data3", Data.PropLength) --For Gun ammo, Data3 should always be Propellant - RunConsoleCommand("acfmenu_data4", Data.ProjLength) --And Data4 total round mass - RunConsoleCommand("acfmenu_data10", Data.Tracer) - - acfmenupanel:AmmoSlider("PropLength", Data.PropLength, Data.MinPropLength, Data.MaxTotalLength, 3, "Propellant Length", "Propellant Mass : " .. (math.floor(Data.PropMass * 1000)) .. " g") --Propellant Length Slider (Name, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("ProjLength", Data.ProjLength, Data.MinProjLength, Data.MaxTotalLength, 3, "Projectile Length", "Projectile Mass : " .. (math.floor(Data.ProjMass * 1000)) .. " g") --Projectile Length Slider (Name, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoCheckbox("Tracer", "Tracer : " .. (math.floor(Data.Tracer * 10) / 10) .. "cm\n", "") --Tracer checkbox (Name, Title, Desc) - acfmenupanel:CPanelText("Desc", Ammo.Description) --Description (Name, Desc) - acfmenupanel:CPanelText("LengthDisplay", "Round Length : " .. (math.floor((Data.PropLength + Data.ProjLength + Data.Tracer) * 100) / 100) .. "/" .. Data.MaxTotalLength .. " cm") --Total round length (Name, Desc) - acfmenupanel:CPanelText("VelocityDisplay", "Muzzle Velocity : " .. math.floor(Data.MuzzleVel * ACF.Scale) .. " m/s") --Proj muzzle velocity (Name, Desc) - - local R1V, R1P = ACF_PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 300) - local R2V, R2P = ACF_PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 800) - - acfmenupanel:CPanelText("PenetrationDisplay", "Maximum Penetration : " .. math.floor(Data.MaxPen) .. " mm RHA\n\n300m pen: " .. math.Round(R1P, 0) .. "mm @ " .. math.Round(R1V, 0) .. " m/s\n800m pen: " .. math.Round(R2P, 0) .. "mm @ " .. math.Round(R2V, 0) .. " m/s\n\nThe range data is an approximation and may not be entirely accurate.") --Proj muzzle penetration (Name, Desc) -end - function Ammo.MenuAction(Menu) local ToolData = { Weapon = ACF.ReadString("Weapon"), @@ -212,63 +168,111 @@ function Ammo.MenuAction(Menu) Tracer = ACF.ReadBool("Tracer"), } - local Data = Ammo.ClientConvert(Panel, ToolData) + local Data = Ammo.ClientConvert(Menu, ToolData) Menu:AddParagraph(Ammo.Description) - local Projectile = Menu:AddSlider("Projectile Length", Data.MinProjLength, Data.MaxProjLength, 2) - Projectile:SetDataVar("Projectile") + local RoundLength = Menu:AddParagraph() + RoundLength:TrackDataVar("Projectile", "SetText") + RoundLength:TrackDataVar("Propellant") + RoundLength:TrackDataVar("Tracer") + RoundLength:SetValueFunction(function() + local Text = "Round Length: %s / %s cm" + local CurLength = Data.ProjLength + Data.PropLength + Data.Tracer + local MaxLength = Data.MaxRoundLength + + return Text:format(CurLength, MaxLength) + end) + + local Projectile = Menu:AddSlider("Projectile Length", 0, Data.MaxRoundLength, 2) + Projectile:SetDataVar("Projectile", "OnValueChanged") Projectile:TrackDataVar("Propellant") Projectile:TrackDataVar("Tracer") + Projectile:SetValueFunction(function(Panel, IsTracked) + ToolData.Projectile = ACF.ReadNumber("Projectile") + + if not IsTracked then + Data.Priority = "Projectile" + end + + ACF.UpdateRoundSpecs(ToolData, Data) - local Propellant = Menu:AddSlider("Propellant Length", Data.MinPropLength, Data.MaxPropLength, 2) - Propellant:SetDataVar("Propellant") + ACF.WriteValue("Projectile", Data.ProjLength) + ACF.WriteValue("Propellant", Data.PropLength) + + Panel:SetValue(Data.ProjLength) + + return Data.ProjLength + end) + + local Propellant = Menu:AddSlider("Propellant Length", 0, Data.MaxRoundLength, 2) + Propellant:SetDataVar("Propellant", "OnValueChanged") Propellant:TrackDataVar("Projectile") Propellant:TrackDataVar("Tracer") + Propellant:SetValueFunction(function(Panel, IsTracked) + ToolData.Propellant = ACF.ReadNumber("Propellant") - local Tracer = Menu:AddCheckBox("Tracer") - Tracer:SetDataVar("Tracer") + if not IsTracked then + Data.Priority = "Propellant" + end + + ACF.UpdateRoundSpecs(ToolData, Data) + + ACF.WriteValue("Propellant", Data.PropLength) + ACF.WriteValue("Projectile", Data.ProjLength) - --[[ + Panel:SetValue(Data.PropLength) - local Test = Menu:AddComboBox() - Test:TrackDataVar("WeaponClass") - Test:TrackDataVar("Weapon") - Test:SetValueFunction(function() - return ACF.ReadString("WeaponClass") .. " - " .. ACF.ReadString("Weapon") + return Data.PropLength end) - local Test1 = Menu:AddSlider("Projectile", 0, 10, 2) - Test1:SetDataVar("Projectile") - Test1:TrackDataVar("Propellant") - Test1:SetValueFunction(function(Panel) - local Min, Max = Panel:GetMin(), Panel:GetMax() - local Projectile = math.Clamp(ACF.ReadNumber("Projectile"), Min, Max) - local Propellant = ACF.ReadNumber("Propellant") - local Difference = Max - Projectile + local Tracer = Menu:AddCheckBox("Tracer") + Tracer:SetDataVar("Tracer", "OnChange") + Tracer:SetValueFunction(function(Panel) + local NewValue = ACF.ReadBool("Tracer") + + ToolData.Tracer = NewValue + + ACF.UpdateRoundSpecs(ToolData, Data) + + ACF.WriteValue("Projectile", Data.ProjLength) + ACF.WriteValue("Propellant", Data.PropLength) - ACF.WriteValue("Projectile", Projectile) - ACF.WriteValue("Propellant", math.min(Propellant, Difference)) + Panel:SetText("Tracer : " .. (NewValue and Data.Tracer or 0) .. " cm") + Panel:SetValue(NewValue) - return Projectile + return NewValue end) - local Test2 = Menu:AddSlider("Propellant", 0, 10, 2) - Test2:SetDataVar("Propellant") - Test2:TrackDataVar("Projectile") - Test2:SetValueFunction(function(Panel) - local Min, Max = Panel:GetMin(), Panel:GetMax() - local Projectile = ACF.ReadNumber("Projectile") - local Propellant = math.Clamp(ACF.ReadNumber("Propellant"), Min, Max) - local Difference = Max - Propellant + local RoundStats = Menu:AddParagraph() + RoundStats:TrackDataVar("Projectile", "SetText") + RoundStats:TrackDataVar("Propellant") + RoundStats:TrackDataVar("Tracer") + RoundStats:SetValueFunction(function() + Data = Ammo.ClientConvert(_, ToolData) - ACF.WriteValue("Propellant", Propellant) - ACF.WriteValue("Projectile", math.min(Projectile, Difference)) + local Text = "Muzzle Velocity : %s m/s\nProjectile Mass : %s\nPropellant Mass : %s" + local MuzzleVel = math.Round(Data.MuzzleVel * ACF.Scale, 2) + local ProjMass = ACF.GetProperMass(Data.ProjMass * 1000) + local PropMass = ACF.GetProperMass(Data.PropMass * 1000) - return Propellant + return Text:format(MuzzleVel, ProjMass, PropMass) end) - ]]-- + local PenStats = Menu:AddParagraph() + PenStats:TrackDataVar("Projectile", "SetText") + PenStats:TrackDataVar("Propellant") + PenStats:TrackDataVar("Tracer") + PenStats:SetValueFunction(function() + Data = Ammo.ClientConvert(_, ToolData) + + local Text = "Penetration : %s mm RHA\nAt 300m : %s mm RHA @ %s m/s\nAt 800m : %s mm RHA @ %s m/s" + local MaxPen = math.Round(Data.MaxPen, 2) + local R1V, R1P = ACF.PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 300) + local R2V, R2P = ACF.PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 800) + + return Text:format(MaxPen, R1P, R1V, R2P, R2V) + end) end ACF.RegisterAmmoDecal("AP", "damage/ap_pen", "damage/ap_rico") From d2120691dfc315784eccc45b175a332ec8fb841c Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Mon, 2 Mar 2020 05:18:10 -0300 Subject: [PATCH 028/279] Updated ACF.GetProperMass to use kilograms - ACF.GetProperMass will now use kilograms instead of grams as their input unit --- lua/acf/base/util/sh_util.lua | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lua/acf/base/util/sh_util.lua b/lua/acf/base/util/sh_util.lua index 4c14c2a97..57b1299d4 100644 --- a/lua/acf/base/util/sh_util.lua +++ b/lua/acf/base/util/sh_util.lua @@ -132,15 +132,15 @@ do -- Unit conversion end end - function ACF.GetProperMass(Grams) - local Unit, Mult = "g", 1 + function ACF.GetProperMass(Kilograms) + local Unit, Mult = "g", 1000 - if Grams > 1000000 then - Unit, Mult = "t", 0.000001 - elseif Grams > 1000 then - Unit, Mult = "kg", 0.001 + if Kilograms >= 1000 then + Unit, Mult = "t", 0.001 + elseif Kilograms >= 1 then + Unit, Mult = "kg", 1 end - return math.Round(Grams * Mult, 2) .. " " .. Unit + return math.Round(Kilograms * Mult, 2) .. " " .. Unit end end From f68260e8bacdc1afef0d108e26c6e44a9a730041 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Mon, 2 Mar 2020 05:22:21 -0300 Subject: [PATCH 029/279] Added default menu items to the weapon's menu - The menu will now always create a paragraph with the ammo type's description. - The menu will create, if Ammo.SuppressDefaultMenu is false/nil, the round length paragraph along with the projectile and propellant sliders --- lua/acf/client/menu_items/weapons_menu.lua | 66 +++++++++++++++++++++- 1 file changed, 63 insertions(+), 3 deletions(-) diff --git a/lua/acf/client/menu_items/weapons_menu.lua b/lua/acf/client/menu_items/weapons_menu.lua index 8f350e50c..45047ede4 100644 --- a/lua/acf/client/menu_items/weapons_menu.lua +++ b/lua/acf/client/menu_items/weapons_menu.lua @@ -132,13 +132,73 @@ local function CreateMenu(Menu) function AmmoList:UpdateMenu() if not self.Selected then return end - local Data = self.Selected + local Ammo = self.Selected + local ToolData = Ammo.GetToolData() + local Data = Ammo.ClientConvert(Menu, ToolData) Menu:ClearTemporal(self) Menu:StartTemporal(self) - if Data.MenuAction then - Data.MenuAction(Menu) + Menu:AddParagraph(Ammo.Description) + + if not Ammo.SupressDefaultMenu then + local RoundLength = Menu:AddParagraph() + RoundLength:TrackDataVar("Projectile", "SetText") + RoundLength:TrackDataVar("Propellant") + RoundLength:TrackDataVar("Tracer") + RoundLength:SetValueFunction(function() + local Text = "Round Length: %s / %s cm" + local CurLength = Data.ProjLength + Data.PropLength + Data.Tracer + local MaxLength = Data.MaxRoundLength + + return Text:format(CurLength, MaxLength) + end) + + local Projectile = Menu:AddSlider("Projectile Length", 0, Data.MaxRoundLength, 2) + Projectile:SetDataVar("Projectile", "OnValueChanged") + Projectile:TrackDataVar("Propellant") + Projectile:TrackDataVar("Tracer") + Projectile:SetValueFunction(function(Panel, IsTracked) + ToolData.Projectile = ACF.ReadNumber("Projectile") + + if not IsTracked then + Data.Priority = "Projectile" + end + + Ammo.UpdateRoundData(ToolData, Data) + + ACF.WriteValue("Projectile", Data.ProjLength) + ACF.WriteValue("Propellant", Data.PropLength) + + Panel:SetValue(Data.ProjLength) + + return Data.ProjLength + end) + + local Propellant = Menu:AddSlider("Propellant Length", 0, Data.MaxRoundLength, 2) + Propellant:SetDataVar("Propellant", "OnValueChanged") + Propellant:TrackDataVar("Projectile") + Propellant:TrackDataVar("Tracer") + Propellant:SetValueFunction(function(Panel, IsTracked) + ToolData.Propellant = ACF.ReadNumber("Propellant") + + if not IsTracked then + Data.Priority = "Propellant" + end + + Ammo.UpdateRoundData(ToolData, Data) + + ACF.WriteValue("Propellant", Data.PropLength) + ACF.WriteValue("Projectile", Data.ProjLength) + + Panel:SetValue(Data.PropLength) + + return Data.PropLength + end) + end + + if Ammo.MenuAction then + Ammo.MenuAction(Menu, ToolData, Data) end Menu:EndTemporal(self) From fafd3cb8911b12bad8e5723aef6397d5d018ca64 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Mon, 2 Mar 2020 05:26:18 -0300 Subject: [PATCH 030/279] Improved ammo type definition standard - Ammo.MenuAction will now also receive ToolData and (Client)Data as arguments. - Added Ammo.GetToolData function to retrieve the tool data variables needed by the ammo type. - Added Ammo.UpdateRoundData to help optimize the round update process on panels by preventing constant table creation. --- lua/acf/shared/ammo_types/ap.lua | 121 ++++++++++--------------------- 1 file changed, 37 insertions(+), 84 deletions(-) diff --git a/lua/acf/shared/ammo_types/ap.lua b/lua/acf/shared/ammo_types/ap.lua index 5ae8cfbda..400d60dbd 100644 --- a/lua/acf/shared/ammo_types/ap.lua +++ b/lua/acf/shared/ammo_types/ap.lua @@ -17,21 +17,34 @@ function Ammo.Create(_, BulletData) ACF_CreateBullet(BulletData) end +function Ammo.UpdateRoundData(ToolData, Data, GUIData) + GUIData = GUIData or Data + + ACF.UpdateRoundSpecs(ToolData, Data, GUIData) + + Data.ProjMass = Data.FrArea * (Data.ProjLength * 7.9 / 1000) --Volume of the projectile as a cylinder * density of steel + Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass) + Data.DragCoef = ((Data.FrArea / 10000) / Data.ProjMass) + Data.BoomPower = Data.PropMass + + for K, V in pairs(Ammo.GetDisplayData(Data)) do + GUIData[K] = V + end +end + function Ammo.BaseConvert(_, ToolData) if not ToolData.Projectile then ToolData.Projectile = 0 end if not ToolData.Propellant then ToolData.Propellant = 0 end local Data, GUIData = ACF.RoundBaseGunpowder(ToolData, {}) - Data.ProjMass = Data.FrArea * (Data.ProjLength * 7.9 / 1000) --Volume of the projectile as a cylinder * density of steel - Data.ShovePower = 0.2 - Data.PenArea = Data.FrArea ^ ACF.PenAreaMod - Data.DragCoef = ((Data.FrArea / 10000) / Data.ProjMass) - Data.LimitVel = 800 --Most efficient penetration speed in m/s + Data.ShovePower = 0.2 + Data.PenArea = Data.FrArea ^ ACF.PenAreaMod + Data.LimitVel = 800 --Most efficient penetration speed in m/s Data.KETransfert = 0.1 --Kinetic energy transfert to the target for movement purposes - Data.Ricochet = 60 --Base ricochet angle - Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass, Data.Caliber) - Data.BoomPower = Data.PropMass + Data.Ricochet = 60 --Base ricochet angle + + Ammo.UpdateRoundData(ToolData, Data, GUIData) return Data, GUIData end @@ -43,10 +56,6 @@ function Ammo.ClientConvert(_, ToolData) Data[K] = V end - for K, V in pairs(Ammo.GetDisplayData(Data)) do - Data[K] = V - end - return Data end @@ -85,6 +94,16 @@ function Ammo.GetCrateText(BulletData) return Text:format(math.Round(BulletData.MuzzleVel, 2), math.floor(Data.MaxPen)) end +function Ammo.GetToolData() + return { + Weapon = ACF.ReadString("Weapon"), + WeaponClass = ACF.ReadString("WeaponClass"), + Projectile = ACF.ReadNumber("Projectile"), + Propellant = ACF.ReadNumber("Propellant"), + Tracer = ACF.ReadBool("Tracer"), + } +end + function Ammo.PropImpact(_, Bullet, Target, HitNormal, HitPos, Bone) if ACF_Check(Target) then local Speed = Bullet.Flight:Length() / ACF.Scale @@ -159,73 +178,7 @@ function Ammo.RicochetEffect(_, Bullet) util.Effect("ACF_Ricochet", Effect) end -function Ammo.MenuAction(Menu) - local ToolData = { - Weapon = ACF.ReadString("Weapon"), - WeaponClass = ACF.ReadString("WeaponClass"), - Projectile = ACF.ReadNumber("Projectile"), - Propellant = ACF.ReadNumber("Propellant"), - Tracer = ACF.ReadBool("Tracer"), - } - - local Data = Ammo.ClientConvert(Menu, ToolData) - - Menu:AddParagraph(Ammo.Description) - - local RoundLength = Menu:AddParagraph() - RoundLength:TrackDataVar("Projectile", "SetText") - RoundLength:TrackDataVar("Propellant") - RoundLength:TrackDataVar("Tracer") - RoundLength:SetValueFunction(function() - local Text = "Round Length: %s / %s cm" - local CurLength = Data.ProjLength + Data.PropLength + Data.Tracer - local MaxLength = Data.MaxRoundLength - - return Text:format(CurLength, MaxLength) - end) - - local Projectile = Menu:AddSlider("Projectile Length", 0, Data.MaxRoundLength, 2) - Projectile:SetDataVar("Projectile", "OnValueChanged") - Projectile:TrackDataVar("Propellant") - Projectile:TrackDataVar("Tracer") - Projectile:SetValueFunction(function(Panel, IsTracked) - ToolData.Projectile = ACF.ReadNumber("Projectile") - - if not IsTracked then - Data.Priority = "Projectile" - end - - ACF.UpdateRoundSpecs(ToolData, Data) - - ACF.WriteValue("Projectile", Data.ProjLength) - ACF.WriteValue("Propellant", Data.PropLength) - - Panel:SetValue(Data.ProjLength) - - return Data.ProjLength - end) - - local Propellant = Menu:AddSlider("Propellant Length", 0, Data.MaxRoundLength, 2) - Propellant:SetDataVar("Propellant", "OnValueChanged") - Propellant:TrackDataVar("Projectile") - Propellant:TrackDataVar("Tracer") - Propellant:SetValueFunction(function(Panel, IsTracked) - ToolData.Propellant = ACF.ReadNumber("Propellant") - - if not IsTracked then - Data.Priority = "Propellant" - end - - ACF.UpdateRoundSpecs(ToolData, Data) - - ACF.WriteValue("Propellant", Data.PropLength) - ACF.WriteValue("Projectile", Data.ProjLength) - - Panel:SetValue(Data.PropLength) - - return Data.PropLength - end) - +function Ammo.MenuAction(Menu, ToolData, Data) local Tracer = Menu:AddCheckBox("Tracer") Tracer:SetDataVar("Tracer", "OnChange") Tracer:SetValueFunction(function(Panel) @@ -233,7 +186,7 @@ function Ammo.MenuAction(Menu) ToolData.Tracer = NewValue - ACF.UpdateRoundSpecs(ToolData, Data) + Ammo.UpdateRoundData(ToolData, Data) ACF.WriteValue("Projectile", Data.ProjLength) ACF.WriteValue("Propellant", Data.PropLength) @@ -249,12 +202,12 @@ function Ammo.MenuAction(Menu) RoundStats:TrackDataVar("Propellant") RoundStats:TrackDataVar("Tracer") RoundStats:SetValueFunction(function() - Data = Ammo.ClientConvert(_, ToolData) + Ammo.UpdateRoundData(ToolData, Data) local Text = "Muzzle Velocity : %s m/s\nProjectile Mass : %s\nPropellant Mass : %s" local MuzzleVel = math.Round(Data.MuzzleVel * ACF.Scale, 2) - local ProjMass = ACF.GetProperMass(Data.ProjMass * 1000) - local PropMass = ACF.GetProperMass(Data.PropMass * 1000) + local ProjMass = ACF.GetProperMass(Data.ProjMass) + local PropMass = ACF.GetProperMass(Data.PropMass) return Text:format(MuzzleVel, ProjMass, PropMass) end) @@ -264,7 +217,7 @@ function Ammo.MenuAction(Menu) PenStats:TrackDataVar("Propellant") PenStats:TrackDataVar("Tracer") PenStats:SetValueFunction(function() - Data = Ammo.ClientConvert(_, ToolData) + Ammo.UpdateRoundData(ToolData, Data) local Text = "Penetration : %s mm RHA\nAt 300m : %s mm RHA @ %s m/s\nAt 800m : %s mm RHA @ %s m/s" local MaxPen = math.Round(Data.MaxPen, 2) From 80e472b129af5a7ae5509a6dfa2b70da68beb0d7 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Tue, 3 Mar 2020 04:49:17 -0300 Subject: [PATCH 031/279] Fixed erroneous class inheritance - Fixed classes receiving the wrong base class. - New class instances will use a copy of the class instead of the class table itself. --- lua/acf/base/sh_classes.lua | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/lua/acf/base/sh_classes.lua b/lua/acf/base/sh_classes.lua index a4cb0b3ad..eb5d09715 100644 --- a/lua/acf/base/sh_classes.lua +++ b/lua/acf/base/sh_classes.lua @@ -5,7 +5,7 @@ do -- Class registration function local function CreateInstance(Class) local New = {} - setmetatable(New, { __index = Class }) + setmetatable(New, { __index = table.Copy(Class) }) if New.OnCalled then New:OnCalled() @@ -22,7 +22,7 @@ do -- Class registration function end end - local function AttachMetaTable(Class, ID, Base) + local function AttachMetaTable(Class, Base) local OldMeta = getmetatable(Class) or {} if Base then @@ -32,7 +32,7 @@ do -- Class registration function Class.BaseClass = BaseClass OldMeta.__index = BaseClass else - QueueBaseClass(ID, Base) + QueueBaseClass(Class.ID, Base) end end @@ -57,15 +57,11 @@ do -- Class registration function local Class = Classes[ID] Class.ID = ID - AttachMetaTable(Class, ID, Base) + AttachMetaTable(Class, Base) if Queued[ID] then - local Current - for K in pairs(Queued[ID]) do - Current = Classes[K] - - AttachMetaTable(Current, Current.ID, ID) + AttachMetaTable(Classes[K], ID) end Queued[ID] = nil From cbcf7d20aff191d7f24cfdfda984f50fd58b6e2d Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sun, 8 Mar 2020 05:54:41 -0300 Subject: [PATCH 032/279] Changed text panel methods on ACF_Panel - PANEL:AddTitle has been replaced by PANEL:AddSubtitle, which doesn't exist anymore. - PANEL:AddParagraph has been renamed to ACF:AddLabel. - Same changes applies to the fonts related to these methods. --- lua/acf/base/util/cl_util.lua | 8 +------- lua/acf/client/cl_menu.lua | 10 ++++------ lua/acf/client/menu_items/weapons_menu.lua | 12 ++++++------ lua/acf/client/sk_menu.lua | 6 +++--- lua/vgui/acf_panel.lua | 14 ++++---------- 5 files changed, 18 insertions(+), 32 deletions(-) diff --git a/lua/acf/base/util/cl_util.lua b/lua/acf/base/util/cl_util.lua index 71578fa53..513ffaab1 100644 --- a/lua/acf/base/util/cl_util.lua +++ b/lua/acf/base/util/cl_util.lua @@ -49,18 +49,12 @@ end do -- Custom fonts surface.CreateFont("ACF_Title", { - font = "Roboto", - size = 22, - weight = 850, - }) - - surface.CreateFont("ACF_Subtitle", { font = "Roboto", size = 18, weight = 850, }) - surface.CreateFont("ACF_Paragraph", { + surface.CreateFont("ACF_Label", { font = "Roboto", size = 14, weight = 650, diff --git a/lua/acf/client/cl_menu.lua b/lua/acf/client/cl_menu.lua index d2c6484e8..3013befb2 100644 --- a/lua/acf/client/cl_menu.lua +++ b/lua/acf/client/cl_menu.lua @@ -5,7 +5,7 @@ local Count = 0 do -- Menu population functions local function DefaultAction(Panel) Panel:AddTitle("There's nothing here.") - Panel:AddParagraph("This option is either a work in progress or something isn't working as intended.") + Panel:AddLabel("This option is either a work in progress or something isn't working as intended.") end function ACF.AddOption(Name, Icon) @@ -129,12 +129,12 @@ do -- ACF Menu context panel local Menu = ACF.Menu if not IsValid(Menu) then - ACF.Menu = vgui.Create("ACF_Panel", Panel) - - Menu = ACF.Menu + Menu = vgui.Create("ACF_Panel") Menu.Panel = Panel Panel:AddItem(Menu) + + ACF.Menu = Menu else Menu:ClearAllTemporal() Menu:ClearAll() @@ -146,8 +146,6 @@ do -- ACF Menu context panel ACF.BuildContextPanel(Panel) end - Menu:AddTitle("Available Options") - local Tree = Menu:AddPanel("DTree") function Tree:OnNodeSelected(Node) if self.Selected == Node then return end diff --git a/lua/acf/client/menu_items/weapons_menu.lua b/lua/acf/client/menu_items/weapons_menu.lua index 45047ede4..b23300580 100644 --- a/lua/acf/client/menu_items/weapons_menu.lua +++ b/lua/acf/client/menu_items/weapons_menu.lua @@ -56,11 +56,11 @@ local function CreateMenu(Menu) local ClassList = Menu:AddComboBox() local EntList = Menu:AddComboBox() - local EntName = Menu:AddSubtitle() - local ClassDesc = Menu:AddParagraph() - local EntData = Menu:AddParagraph() + local EntName = Menu:AddTitle() + local ClassDesc = Menu:AddLabel() + local EntData = Menu:AddLabel() - Menu:AddSubtitle("Ammo Settings") + Menu:AddTitle("Ammo Settings") local CrateList = Menu:AddComboBox() local AmmoList = Menu:AddComboBox() @@ -139,10 +139,10 @@ local function CreateMenu(Menu) Menu:ClearTemporal(self) Menu:StartTemporal(self) - Menu:AddParagraph(Ammo.Description) + Menu:AddLabel(Ammo.Description) if not Ammo.SupressDefaultMenu then - local RoundLength = Menu:AddParagraph() + local RoundLength = Menu:AddLabel() RoundLength:TrackDataVar("Projectile", "SetText") RoundLength:TrackDataVar("Propellant") RoundLength:TrackDataVar("Tracer") diff --git a/lua/acf/client/sk_menu.lua b/lua/acf/client/sk_menu.lua index bcad7d297..8158de7a8 100644 --- a/lua/acf/client/sk_menu.lua +++ b/lua/acf/client/sk_menu.lua @@ -261,21 +261,21 @@ function ACFHomeGUICreate() CData.Header = vgui.Create("DLabel") CData.Header:SetText("ACF Version Status\n") - CData.Header:SetFont("ACF_Subtitle") + CData.Header:SetFont("ACF_Title") CData.Header:SetDark(true) CData.Header:SizeToContents() Display:AddItem(CData.Header) CData.ServerStatus = vgui.Create("DLabel") CData.ServerStatus:SetText(Text:format("Server", SVCode, SVHead, SVStatus)) - CData.ServerStatus:SetFont("ACF_Paragraph") + CData.ServerStatus:SetFont("ACF_Label") CData.ServerStatus:SetDark(true) CData.ServerStatus:SizeToContents() Display:AddItem(CData.ServerStatus) CData.ClientStatus = vgui.Create("DLabel") CData.ClientStatus:SetText(Text:format("Client", Repo.Code, Repo.Head, Repo.Status)) - CData.ClientStatus:SetFont("ACF_Paragraph") + CData.ClientStatus:SetFont("ACF_Label") CData.ClientStatus:SetDark(true) CData.ClientStatus:SizeToContents() Display:AddItem(CData.ClientStatus) diff --git a/lua/vgui/acf_panel.lua b/lua/vgui/acf_panel.lua index 2c6967fc4..7ef810098 100644 --- a/lua/vgui/acf_panel.lua +++ b/lua/vgui/acf_panel.lua @@ -115,23 +115,16 @@ function PANEL:AddTitle(Text) return Panel end -function PANEL:AddSubtitle(Text) +function PANEL:AddLabel(Text) local Panel = self:AddTitle(Text) - Panel:SetFont("ACF_Subtitle") - - return Panel -end - -function PANEL:AddParagraph(Text) - local Panel = self:AddTitle(Text) - Panel:SetFont("ACF_Paragraph") + Panel:SetFont("ACF_Label") return Panel end function PANEL:AddHelp(Text) local TextColor = self:GetSkin().Colours.Tree.Hover - local Panel = self:AddParagraph(Text) + local Panel = self:AddLabel(Text) Panel:DockMargin(32, 0, 32, 10) Panel:SetTextColor(TextColor) Panel:InvalidateLayout() @@ -151,6 +144,7 @@ end function PANEL:AddSlider(Title, Min, Max, Decimals) local Panel = self:AddPanel("DNumSlider") + Panel:DockMargin(0, 0, 0, 5) Panel:SetDecimals(Decimals or 0) Panel:SetText(Title or "") Panel:SetMinMax(Min, Max) From 5f00eb3c7976e46a0a82178228e6aa46cd916659 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sun, 8 Mar 2020 06:00:36 -0300 Subject: [PATCH 033/279] Updated all ammo types to the current standard - All methods inside ammo type definitions are now capable of using the self parameter to ease method inheritance. - All ammo types now have a proper menu creation method. - Changed human readable name of Short Cannons. - Fixed all cases of ACF_MuzzleVelocity receiving an unused third argument. --- lua/acf/client/menu_items/weapons_menu.lua | 16 +- lua/acf/shared/ammo_types/ap.lua | 113 ++--- lua/acf/shared/ammo_types/aphe.lua | 260 ++++++------ lua/acf/shared/ammo_types/fl.lua | 299 +++++++------ lua/acf/shared/ammo_types/he.lua | 226 +++++----- lua/acf/shared/ammo_types/heat.lua | 466 +++++++++++---------- lua/acf/shared/ammo_types/hp.lua | 241 ++++++----- lua/acf/shared/ammo_types/refill.lua | 81 ++-- lua/acf/shared/ammo_types/smoke.lua | 344 ++++++++------- lua/acf/shared/guns/shortcannon.lua | 2 +- lua/entities/acf_ammo/init.lua | 2 +- 11 files changed, 1077 insertions(+), 973 deletions(-) diff --git a/lua/acf/client/menu_items/weapons_menu.lua b/lua/acf/client/menu_items/weapons_menu.lua index b23300580..a70ffb1e9 100644 --- a/lua/acf/client/menu_items/weapons_menu.lua +++ b/lua/acf/client/menu_items/weapons_menu.lua @@ -133,8 +133,8 @@ local function CreateMenu(Menu) if not self.Selected then return end local Ammo = self.Selected - local ToolData = Ammo.GetToolData() - local Data = Ammo.ClientConvert(Menu, ToolData) + local ToolData = Ammo:GetToolData() + local Data = Ammo:ClientConvert(Menu, ToolData) Menu:ClearTemporal(self) Menu:StartTemporal(self) @@ -156,8 +156,6 @@ local function CreateMenu(Menu) local Projectile = Menu:AddSlider("Projectile Length", 0, Data.MaxRoundLength, 2) Projectile:SetDataVar("Projectile", "OnValueChanged") - Projectile:TrackDataVar("Propellant") - Projectile:TrackDataVar("Tracer") Projectile:SetValueFunction(function(Panel, IsTracked) ToolData.Projectile = ACF.ReadNumber("Projectile") @@ -165,9 +163,8 @@ local function CreateMenu(Menu) Data.Priority = "Projectile" end - Ammo.UpdateRoundData(ToolData, Data) + Ammo:UpdateRoundData(ToolData, Data) - ACF.WriteValue("Projectile", Data.ProjLength) ACF.WriteValue("Propellant", Data.PropLength) Panel:SetValue(Data.ProjLength) @@ -177,8 +174,6 @@ local function CreateMenu(Menu) local Propellant = Menu:AddSlider("Propellant Length", 0, Data.MaxRoundLength, 2) Propellant:SetDataVar("Propellant", "OnValueChanged") - Propellant:TrackDataVar("Projectile") - Propellant:TrackDataVar("Tracer") Propellant:SetValueFunction(function(Panel, IsTracked) ToolData.Propellant = ACF.ReadNumber("Propellant") @@ -186,9 +181,8 @@ local function CreateMenu(Menu) Data.Priority = "Propellant" end - Ammo.UpdateRoundData(ToolData, Data) + Ammo:UpdateRoundData(ToolData, Data) - ACF.WriteValue("Propellant", Data.PropLength) ACF.WriteValue("Projectile", Data.ProjLength) Panel:SetValue(Data.PropLength) @@ -198,7 +192,7 @@ local function CreateMenu(Menu) end if Ammo.MenuAction then - Ammo.MenuAction(Menu, ToolData, Data) + Ammo:MenuAction(Menu, ToolData, Data) end Menu:EndTemporal(self) diff --git a/lua/acf/shared/ammo_types/ap.lua b/lua/acf/shared/ammo_types/ap.lua index 400d60dbd..eb308f9e8 100644 --- a/lua/acf/shared/ammo_types/ap.lua +++ b/lua/acf/shared/ammo_types/ap.lua @@ -2,37 +2,36 @@ local Ammo = ACF.RegisterAmmoType("AP") local DecalIndex = ACF.GetAmmoDecalIndex function Ammo:OnLoaded() - self.Name = "Armor Piercing" - self.Type = "Ammo" - self.Model = "models/munitions/round_100mm_shot.mdl" + self.Name = "Armor Piercing" + self.Type = "Ammo" + self.Model = "models/munitions/round_100mm_shot.mdl" self.Description = "A shell made out of a solid piece of steel, meant to penetrate armor." self.Blacklist = { MO = true, - SL = true, SB = true, + SL = true, } end -function Ammo.Create(_, BulletData) +function Ammo:Create(_, BulletData) ACF_CreateBullet(BulletData) end -function Ammo.UpdateRoundData(ToolData, Data, GUIData) +function Ammo:UpdateRoundData(ToolData, Data, GUIData) GUIData = GUIData or Data ACF.UpdateRoundSpecs(ToolData, Data, GUIData) - Data.ProjMass = Data.FrArea * (Data.ProjLength * 7.9 / 1000) --Volume of the projectile as a cylinder * density of steel + Data.ProjMass = Data.FrArea * Data.ProjLength * 0.0079 --Volume of the projectile as a cylinder * density of steel Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass) - Data.DragCoef = ((Data.FrArea / 10000) / Data.ProjMass) - Data.BoomPower = Data.PropMass + Data.DragCoef = Data.FrArea * 0.0001 / Data.ProjMass - for K, V in pairs(Ammo.GetDisplayData(Data)) do + for K, V in pairs(self:GetDisplayData(Data)) do GUIData[K] = V end end -function Ammo.BaseConvert(_, ToolData) +function Ammo:BaseConvert(_, ToolData) if not ToolData.Projectile then ToolData.Projectile = 0 end if not ToolData.Propellant then ToolData.Propellant = 0 end @@ -44,23 +43,25 @@ function Ammo.BaseConvert(_, ToolData) Data.KETransfert = 0.1 --Kinetic energy transfert to the target for movement purposes Data.Ricochet = 60 --Base ricochet angle - Ammo.UpdateRoundData(ToolData, Data, GUIData) + self:UpdateRoundData(ToolData, Data, GUIData) return Data, GUIData end -function Ammo.ClientConvert(_, ToolData) - local Data, GUIData = Ammo.BaseConvert(_, ToolData) +function Ammo:ClientConvert(_, ToolData) + local Data, GUIData = self:BaseConvert(_, ToolData) - for K, V in pairs(GUIData) do - Data[K] = V + if GUIData then + for K, V in pairs(GUIData) do + Data[K] = V + end end return Data end -function Ammo.ServerConvert(_, ToolData) - local Data = Ammo.BaseConvert(_, ToolData) +function Ammo:ServerConvert(_, ToolData) + local Data = self:BaseConvert(_, ToolData) Data.Id = ToolData.Weapon Data.Type = ToolData.Ammo @@ -68,7 +69,7 @@ function Ammo.ServerConvert(_, ToolData) return Data end -function Ammo.Network(Crate, BulletData) +function Ammo:Network(Crate, BulletData) Crate:SetNW2String("AmmoType", "AP") Crate:SetNW2String("AmmoID", BulletData.Id) Crate:SetNW2Float("Caliber", BulletData.Caliber) @@ -79,7 +80,7 @@ function Ammo.Network(Crate, BulletData) Crate:SetNW2Float("Tracer", BulletData.Tracer) end -function Ammo.GetDisplayData(BulletData) +function Ammo:GetDisplayData(BulletData) local Energy = ACF_Kinetic(BulletData.MuzzleVel * 39.37, BulletData.ProjMass, BulletData.LimitVel) return { @@ -87,31 +88,33 @@ function Ammo.GetDisplayData(BulletData) } end -function Ammo.GetCrateText(BulletData) - local Data = Ammo.GetDisplayData(BulletData) +function Ammo:GetCrateText(BulletData) + local Data = self:GetDisplayData(BulletData) local Text = "Muzzle Velocity: %s m/s\nMax Penetration: %s mm" - return Text:format(math.Round(BulletData.MuzzleVel, 2), math.floor(Data.MaxPen)) + return Text:format(math.Round(BulletData.MuzzleVel, 2), math.Round(Data.MaxPen, 2)) end -function Ammo.GetToolData() +function Ammo:GetToolData() return { - Weapon = ACF.ReadString("Weapon"), - WeaponClass = ACF.ReadString("WeaponClass"), - Projectile = ACF.ReadNumber("Projectile"), - Propellant = ACF.ReadNumber("Propellant"), - Tracer = ACF.ReadBool("Tracer"), + Ammo = ACF.ReadString("Ammo"), + Weapon = ACF.ReadString("Weapon"), + WeaponClass = ACF.ReadString("WeaponClass"), + Projectile = ACF.ReadNumber("Projectile"), + Propellant = ACF.ReadNumber("Propellant"), + Tracer = ACF.ReadBool("Tracer"), } end -function Ammo.PropImpact(_, Bullet, Target, HitNormal, HitPos, Bone) +function Ammo:PropImpact(_, Bullet, Target, HitNormal, HitPos, Bone) if ACF_Check(Target) then - local Speed = Bullet.Flight:Length() / ACF.Scale + local Speed = Bullet.Flight:Length() / ACF.Scale local Energy = ACF_Kinetic(Speed, Bullet.ProjMass, Bullet.LimitVel) local HitRes = ACF_RoundImpact(Bullet, Speed, Energy, Target, HitPos, HitNormal, Bone) if HitRes.Overkill > 0 then table.insert(Bullet.Filter, Target) --"Penetrate" (Ingoring the prop for the retry trace) + Bullet.Flight = Bullet.Flight:GetNormalized() * (Energy.Kinetic * (1 - HitRes.Loss) * 2000 / Bullet.ProjMass) ^ 0.5 * 39.37 return "Penetrated" @@ -127,7 +130,7 @@ function Ammo.PropImpact(_, Bullet, Target, HitNormal, HitPos, Bone) end end -function Ammo.WorldImpact(_, Bullet, HitPos, HitNormal) +function Ammo:WorldImpact(_, Bullet, HitPos, HitNormal) local Energy = ACF_Kinetic(Bullet.Flight:Length() / ACF.Scale, Bullet.ProjMass, Bullet.LimitVel) local HitRes = ACF_PenetrateGround(Bullet, Energy, HitPos, HitNormal) @@ -140,11 +143,11 @@ function Ammo.WorldImpact(_, Bullet, HitPos, HitNormal) end end -function Ammo.OnFlightEnd(Index) +function Ammo:OnFlightEnd(Index) ACF_RemoveBullet(Index) end -function Ammo.ImpactEffect(_, Bullet) +function Ammo:ImpactEffect(_, Bullet) local Effect = EffectData() Effect:SetOrigin(Bullet.SimPos) Effect:SetNormal(Bullet.SimFlight:GetNormalized()) @@ -154,7 +157,7 @@ function Ammo.ImpactEffect(_, Bullet) util.Effect("ACF_Impact", Effect) end -function Ammo.PenetrationEffect(_, Bullet) +function Ammo:PenetrationEffect(_, Bullet) local Effect = EffectData() Effect:SetOrigin(Bullet.SimPos) Effect:SetNormal(Bullet.SimFlight:GetNormalized()) @@ -166,7 +169,7 @@ function Ammo.PenetrationEffect(_, Bullet) util.Effect("ACF_Penetration", Effect) end -function Ammo.RicochetEffect(_, Bullet) +function Ammo:RicochetEffect(_, Bullet) local Effect = EffectData() Effect:SetOrigin(Bullet.SimPos) Effect:SetNormal(Bullet.SimFlight:GetNormalized()) @@ -178,54 +181,52 @@ function Ammo.RicochetEffect(_, Bullet) util.Effect("ACF_Ricochet", Effect) end -function Ammo.MenuAction(Menu, ToolData, Data) +function Ammo:MenuAction(Menu, ToolData, Data) local Tracer = Menu:AddCheckBox("Tracer") Tracer:SetDataVar("Tracer", "OnChange") Tracer:SetValueFunction(function(Panel) - local NewValue = ACF.ReadBool("Tracer") - - ToolData.Tracer = NewValue + ToolData.Tracer = ACF.ReadBool("Tracer") - Ammo.UpdateRoundData(ToolData, Data) + self:UpdateRoundData(ToolData, Data) ACF.WriteValue("Projectile", Data.ProjLength) ACF.WriteValue("Propellant", Data.PropLength) - Panel:SetText("Tracer : " .. (NewValue and Data.Tracer or 0) .. " cm") - Panel:SetValue(NewValue) + Panel:SetText("Tracer : " .. Data.Tracer .. " cm") + Panel:SetValue(ToolData.Tracer) - return NewValue + return ToolData.Tracer end) - local RoundStats = Menu:AddParagraph() + local RoundStats = Menu:AddLabel() RoundStats:TrackDataVar("Projectile", "SetText") RoundStats:TrackDataVar("Propellant") - RoundStats:TrackDataVar("Tracer") RoundStats:SetValueFunction(function() - Ammo.UpdateRoundData(ToolData, Data) + self:UpdateRoundData(ToolData, Data) - local Text = "Muzzle Velocity : %s m/s\nProjectile Mass : %s\nPropellant Mass : %s" - local MuzzleVel = math.Round(Data.MuzzleVel * ACF.Scale, 2) - local ProjMass = ACF.GetProperMass(Data.ProjMass) - local PropMass = ACF.GetProperMass(Data.PropMass) + local Text = "Muzzle Velocity : %s m/s\nProjectile Mass : %s\nPropellant Mass : %s" + local MuzzleVel = math.Round(Data.MuzzleVel * ACF.Scale, 2) + local ProjMass = ACF.GetProperMass(Data.ProjMass) + local PropMass = ACF.GetProperMass(Data.PropMass) return Text:format(MuzzleVel, ProjMass, PropMass) end) - local PenStats = Menu:AddParagraph() + local PenStats = Menu:AddLabel() PenStats:TrackDataVar("Projectile", "SetText") PenStats:TrackDataVar("Propellant") - PenStats:TrackDataVar("Tracer") PenStats:SetValueFunction(function() - Ammo.UpdateRoundData(ToolData, Data) + self:UpdateRoundData(ToolData, Data) - local Text = "Penetration : %s mm RHA\nAt 300m : %s mm RHA @ %s m/s\nAt 800m : %s mm RHA @ %s m/s" - local MaxPen = math.Round(Data.MaxPen, 2) + local Text = "Penetration : %s mm RHA\nAt 300m : %s mm RHA @ %s m/s\nAt 800m : %s mm RHA @ %s m/s" + local MaxPen = math.Round(Data.MaxPen, 2) local R1V, R1P = ACF.PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 300) local R2V, R2P = ACF.PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 800) return Text:format(MaxPen, R1P, R1V, R2P, R2V) end) + + Menu:AddLabel("Note: The penetration range data is an approximation and may not be entirely accurate.") end ACF.RegisterAmmoDecal("AP", "damage/ap_pen", "damage/ap_rico") diff --git a/lua/acf/shared/ammo_types/aphe.lua b/lua/acf/shared/ammo_types/aphe.lua index a740c19cd..3b29fc571 100644 --- a/lua/acf/shared/ammo_types/aphe.lua +++ b/lua/acf/shared/ammo_types/aphe.lua @@ -3,110 +3,106 @@ local Ammo = ACF.RegisterAmmoType("APHE", "AP") function Ammo:OnLoaded() Ammo.BaseClass.OnLoaded(self) - self.Name = "Armor Piercing High Explosive" - self.Description = "An armor piercing round with a cavity for High explosives. Less capable of defeating armor than plain Armor Piercing, but will explode after penetration" + self.Name = "Armor Piercing High Explosive" + self.Description = "Less capable armor piercing round with an explosive charge inside." self.Blacklist = { - MO = true, MG = true, + MO = true, SL = true, RAC = true, } end -function Ammo.Convert(_, PlayerData) - local Data = {} - local ServerData = {} - local GUIData = {} +function Ammo:UpdateRoundData(ToolData, Data, GUIData) + GUIData = GUIData or Data - if not PlayerData.PropLength then - PlayerData.PropLength = 0 - end + ACF.UpdateRoundSpecs(ToolData, Data, GUIData) - if not PlayerData.ProjLength then - PlayerData.ProjLength = 0 - end + local HEDensity = ACF.HEDensity * 0.001 + --Volume of the projectile as a cylinder - Volume of the filler * density of steel + Volume of the filler * density of TNT + local ProjMass = math.max(GUIData.ProjVolume - ToolData.FillerMass, 0) * 0.0079 + math.min(ToolData.FillerMass, GUIData.ProjVolume) * HEDensity + local MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, ProjMass) + local Energy = ACF_Kinetic(MuzzleVel * 39.37, ProjMass, Data.LimitVel) + local MaxVol = ACF.RoundShellCapacity(Energy.Momentum, Data.FrArea, Data.Caliber, Data.ProjLength) - PlayerData.Data5 = math.max(PlayerData.Data5 or 0, 0) + GUIData.MaxFillerVol = math.Round(math.min(GUIData.ProjVolume, MaxVol * 0.9), 2) + GUIData.FillerVol = math.min(ToolData.FillerMass, GUIData.MaxFillerVol) - if not PlayerData.Data10 then - PlayerData.Data10 = 0 + Data.FillerMass = GUIData.FillerVol * HEDensity + Data.ProjMass = math.max(GUIData.ProjVolume - GUIData.FillerVol, 0) * 0.0079 + Data.FillerMass + Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass) + Data.DragCoef = Data.FrArea * 0.0001 / Data.ProjMass + + for K, V in pairs(self:GetDisplayData(Data)) do + GUIData[K] = V end +end - PlayerData, Data, ServerData, GUIData = ACF_RoundBaseGunpowder(PlayerData, Data, ServerData, GUIData) +function Ammo:BaseConvert(_, ToolData) + if not ToolData.Projectile then ToolData.Projectile = 0 end + if not ToolData.Propellant then ToolData.Propellant = 0 end + if not ToolData.FillerMass then ToolData.FillerMass = 0 end + + local Data, GUIData = ACF.RoundBaseGunpowder(ToolData, {}) - Data.ProjMass = math.max(GUIData.ProjVolume - PlayerData.Data5, 0) * 7.9 / 1000 + math.min(PlayerData.Data5, GUIData.ProjVolume) * ACF.HEDensity / 1000 --Volume of the projectile as a cylinder - Volume of the filler * density of steel + Volume of the filler * density of TNT - Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass, Data.Caliber) - local Energy = ACF_Kinetic(Data.MuzzleVel * 39.37, Data.ProjMass, Data.LimitVel) - local MaxVol = ACF_RoundShellCapacity(Energy.Momentum, Data.FrArea, Data.Caliber, Data.ProjLength) GUIData.MinFillerVol = 0 - GUIData.MaxFillerVol = math.min(GUIData.ProjVolume, MaxVol * 0.9) - GUIData.FillerVol = math.min(PlayerData.Data5, GUIData.MaxFillerVol) - Data.FillerMass = GUIData.FillerVol * ACF.HEDensity / 1000 - Data.ProjMass = math.max(GUIData.ProjVolume - GUIData.FillerVol, 0) * 7.9 / 1000 + Data.FillerMass - Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass, Data.Caliber) - Data.ShovePower = 0.1 - Data.PenArea = Data.FrArea ^ ACF.PenAreaMod - Data.DragCoef = ((Data.FrArea / 10000) / Data.ProjMass) - Data.LimitVel = 700 --Most efficient penetration speed in m/s - Data.KETransfert = 0.1 --Kinetic energy transfert to the target for movement purposes - Data.Ricochet = 65 --Base ricochet angle - Data.BoomPower = Data.PropMass + Data.FillerMass - - --Only the crates need this part - if SERVER then - ServerData.Id = PlayerData.Id - ServerData.Type = PlayerData.Type - - return table.Merge(Data, ServerData) - end + Data.ShovePower = 0.1 + Data.PenArea = Data.FrArea ^ ACF.PenAreaMod + Data.LimitVel = 700 --Most efficient penetration speed in m/s + Data.KETransfert = 0.1 --Kinetic energy transfert to the target for movement purposes + Data.Ricochet = 65 --Base ricochet angle - --Only the GUI needs this part - if CLIENT then - GUIData = table.Merge(GUIData, Ammo.GetDisplayData(Data)) + self:UpdateRoundData(ToolData, Data, GUIData) - return table.Merge(Data, GUIData) - end + return Data, GUIData end -function Ammo.Networkd(Crate, BulletData) - Crate:SetNWString("AmmoType", "APHE") - Crate:SetNWString("AmmoID", BulletData.Id) - Crate:SetNWFloat("Caliber", BulletData.Caliber) - Crate:SetNWFloat("ProjMass", BulletData.ProjMass) - Crate:SetNWFloat("FillerMass", BulletData.FillerMass) - Crate:SetNWFloat("PropMass", BulletData.PropMass) - Crate:SetNWFloat("DragCoef", BulletData.DragCoef) - Crate:SetNWFloat("MuzzleVel", BulletData.MuzzleVel) - Crate:SetNWFloat("Tracer", BulletData.Tracer) +function Ammo:Network(Crate, BulletData) + Crate:SetNW2String("AmmoType", "APHE") + Crate:SetNW2String("AmmoID", BulletData.Id) + Crate:SetNW2Float("Caliber", BulletData.Caliber) + Crate:SetNW2Float("ProjMass", BulletData.ProjMass) + Crate:SetNW2Float("FillerMass", BulletData.FillerMass) + Crate:SetNW2Float("PropMass", BulletData.PropMass) + Crate:SetNW2Float("DragCoef", BulletData.DragCoef) + Crate:SetNW2Float("MuzzleVel", BulletData.MuzzleVel) + Crate:SetNW2Float("Tracer", BulletData.Tracer) end -function Ammo.GetDisplayData(BulletData) - local Data = Ammo.BaseClass.GetDisplayData(BulletData) +function Ammo:GetDisplayData(BulletData) + local Data = Ammo.BaseClass.GetDisplayData(self, BulletData) local FragMass = BulletData.ProjMass - BulletData.FillerMass Data.BlastRadius = BulletData.FillerMass ^ 0.33 * 8 - Data.Fragments = math.max(math.floor((BulletData.FillerMass / FragMass) * ACF.HEFrag), 2) - Data.FragMass = FragMass / GUIData.Fragments - Data.FragVel = (BulletData.FillerMass * ACF.HEPower * 1000 / GUIData.FragMass / GUIData.Fragments) ^ 0.5 + Data.Fragments = math.max(math.floor((BulletData.FillerMass / FragMass) * ACF.HEFrag), 2) + Data.FragMass = FragMass / Data.Fragments + Data.FragVel = (BulletData.FillerMass * ACF.HEPower * 1000 / Data.FragMass / Data.Fragments) ^ 0.5 return Data end -function Ammo.GetCrateText(BulletData) - local Data = Ammo.GetDisplayData(BulletData) - local BaseText = Ammo.BaseClass.GetCrateText(BulletData) - local Text = BaseText .. "\nBlast Radius: %s m\nBlast Energy: %s KJ" +function Ammo:GetCrateText(BulletData) + local BaseText = Ammo.BaseClass.GetCrateText(self, BulletData) + local Text = BaseText .. "\nBlast Radius: %s m\nBlast Energy: %s KJ" + local Data = self:GetDisplayData(BulletData) + + return Text:format(math.Round(Data.BlastRadius, 2), math.Round(BulletData.FillerMass * ACF.HEPower, 2)) +end + +function Ammo:GetToolData() + local Data = Ammo.BaseClass.GetToolData(self) + Data.FillerMass = ACF.ReadNumber("FillerMass") - return Text:format(math.Round(Data.BlastRadius, 2), math.floor(BulletData.FillerMass * ACF.HEPower)) + return Data end -function Ammo.OnFlightEnd(Index, Bullet, HitPos) +function Ammo:OnFlightEnd(Index, Bullet, HitPos) ACF_HE(HitPos - Bullet.Flight:GetNormalized() * 3, Bullet.FillerMass, Bullet.ProjMass - Bullet.FillerMass, Bullet.Owner, nil, Bullet.Gun) - Ammo.BaseClass.OnFlightEnd(Index, Bullet, Hitpos) + Ammo.BaseClass.OnFlightEnd(self, Index, Bullet, Hitpos) end -function Ammo.ImpactEffect(_, Bullet) +function Ammo:ImpactEffect(_, Bullet) local Effect = EffectData() Effect:SetOrigin(Bullet.SimPos) Effect:SetNormal(Bullet.SimFlight:GetNormalized()) @@ -116,62 +112,82 @@ function Ammo.ImpactEffect(_, Bullet) util.Effect("ACF_Explosion", Effect) end -function Ammo.CreateMenu(Panel, Table) - acfmenupanel:AmmoSelect(Ammo.Blacklist) - - acfmenupanel:CPanelText("Desc", "") --Description (Name, Desc) - acfmenupanel:CPanelText("LengthDisplay", "") --Total round length (Name, Desc) - acfmenupanel:AmmoSlider("PropLength", 0, 0, 1000, 3, "Propellant Length", "") --Propellant Length Slider (Name, Value, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("ProjLength", 0, 0, 1000, 3, "Projectile Length", "") --Projectile Length Slider (Name, Value, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("FillerVol", 0, 0, 1000, 3, "HE Filler", "") --Hollow Point Cavity Slider (Name, Value, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoCheckbox("Tracer", "Tracer", "") --Tracer checkbox (Name, Title, Desc) - acfmenupanel:CPanelText("VelocityDisplay", "") --Proj muzzle velocity (Name, Desc) - acfmenupanel:CPanelText("PenetrationDisplay", "") --Proj muzzle penetration (Name, Desc) - acfmenupanel:CPanelText("BlastDisplay", "") --HE Blast data (Name, Desc) - acfmenupanel:CPanelText("FragDisplay", "") --HE Fragmentation data (Name, Desc) - acfmenupanel:CPanelText("PenetrationRanging", "") --penetration ranging (Name, Desc) - - Ammo.UpdateMenu(Panel, Table) -end +function Ammo:MenuAction(Menu, ToolData, Data) + local FillerMass = Menu:AddSlider("Filler Volume", 0, Data.MaxFillerVol, 2) + FillerMass:SetDataVar("FillerMass", "OnValueChanged") + FillerMass:TrackDataVar("Projectile") + FillerMass:SetValueFunction(function(Panel) + ToolData.FillerMass = math.Round(ACF.ReadNumber("FillerMass"), 2) -function Ammo.UpdateMenu(Panel) - local PlayerData = { - Id = acfmenupanel.AmmoData.Data.id, --AmmoSelect GUI - Type = "APHE", --Hardcoded, match ACFRoundTypes table index - PropLength = acfmenupanel.AmmoData.PropLength, --PropLength slider - ProjLength = acfmenupanel.AmmoData.ProjLength, --ProjLength slider - Data5 = acfmenupanel.AmmoData.FillerVol, - Data10 = acfmenupanel.AmmoData.Tracer and 1 or 0, - } + self:UpdateRoundData(ToolData, Data) - local Data = Ammo.Convert(Panel, PlayerData) - - RunConsoleCommand("acfmenu_data1", acfmenupanel.AmmoData.Data.id) - RunConsoleCommand("acfmenu_data2", PlayerData.Type) - RunConsoleCommand("acfmenu_data3", Data.PropLength) --For Gun ammo, Data3 should always be Propellant - RunConsoleCommand("acfmenu_data4", Data.ProjLength) --And Data4 total round mass - RunConsoleCommand("acfmenu_data5", Data.FillerVol) - RunConsoleCommand("acfmenu_data10", Data.Tracer) - - acfmenupanel:AmmoSlider("PropLength", Data.PropLength, Data.MinPropLength, Data.MaxTotalLength, 3, "Propellant Length", "Propellant Mass : " .. (math.floor(Data.PropMass * 1000)) .. " g") --Propellant Length Slider (Name, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("ProjLength", Data.ProjLength, Data.MinProjLength, Data.MaxTotalLength, 3, "Projectile Length", "Projectile Mass : " .. (math.floor(Data.ProjMass * 1000)) .. " g") --Projectile Length Slider (Name, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("FillerVol", Data.FillerVol, Data.MinFillerVol, Data.MaxFillerVol, 3, "HE Filler Volume", "HE Filler Mass : " .. (math.floor(Data.FillerMass * 1000)) .. " g") --HE Filler Slider (Name, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoCheckbox("Tracer", "Tracer : " .. (math.floor(Data.Tracer * 10) / 10) .. "cm\n", "") --Tracer checkbox (Name, Title, Desc) - acfmenupanel:CPanelText("Desc", Ammo.Description) --Description (Name, Desc) - acfmenupanel:CPanelText("LengthDisplay", "Round Length : " .. (math.floor((Data.PropLength + Data.ProjLength + Data.Tracer) * 100) / 100) .. "/" .. Data.MaxTotalLength .. " cm") --Total round length (Name, Desc) - acfmenupanel:CPanelText("VelocityDisplay", "Muzzle Velocity : " .. math.floor(Data.MuzzleVel * ACF.Scale) .. " m/s") --Proj muzzle velocity (Name, Desc) - acfmenupanel:CPanelText("PenetrationDisplay", "Maximum Penetration : " .. math.floor(Data.MaxPen) .. " mm RHA") --Proj muzzle penetration (Name, Desc) - acfmenupanel:CPanelText("BlastDisplay", "Blast Radius : " .. (math.floor(Data.BlastRadius * 100) / 100) .. " m") --Proj muzzle velocity (Name, Desc) - acfmenupanel:CPanelText("FragDisplay", "Fragments : " .. Data.Fragments .. "\n Average Fragment Weight : " .. (math.floor(Data.FragMass * 10000) / 10) .. " g \n Average Fragment Velocity : " .. math.floor(Data.FragVel) .. " m/s") --Proj muzzle penetration (Name, Desc) - - local R1V, R1P = ACF_PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 300) - local R2V, R2P = ACF_PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 800) - - acfmenupanel:CPanelText("PenetrationRanging", "\n300m pen: " .. math.Round(R1P, 0) .. "mm @ " .. math.Round(R1V, 0) .. " m/s\n800m pen: " .. math.Round(R2P, 0) .. "mm @ " .. math.Round(R2V, 0) .. " m/s\n\nThe range data is an approximation and may not be entirely accurate.") --Proj muzzle penetration (Name, Desc) -end + Panel:SetMax(Data.MaxFillerVol) + Panel:SetValue(Data.FillerVol) + + return Data.FillerVol + end) + + local Tracer = Menu:AddCheckBox("Tracer") + Tracer:SetDataVar("Tracer", "OnChange") + Tracer:SetValueFunction(function(Panel) + ToolData.Tracer = ACF.ReadBool("Tracer") + + self:UpdateRoundData(ToolData, Data) + + ACF.WriteValue("Projectile", Data.ProjLength) + ACF.WriteValue("Propellant", Data.PropLength) + + Panel:SetText("Tracer : " .. Data.Tracer .. " cm") + Panel:SetValue(ToolData.Tracer) + + return ToolData.Tracer + end) + + local RoundStats = Menu:AddLabel() + RoundStats:TrackDataVar("Projectile", "SetText") + RoundStats:TrackDataVar("Propellant") + RoundStats:TrackDataVar("FillerMass") + RoundStats:SetValueFunction(function() + self:UpdateRoundData(ToolData, Data) + + local Text = "Muzzle Velocity : %s m/s\nProjectile Mass : %s\nPropellant Mass : %s\nExplosive Mass : %s" + local MuzzleVel = math.Round(Data.MuzzleVel * ACF.Scale, 2) + local ProjMass = ACF.GetProperMass(Data.ProjMass) + local PropMass = ACF.GetProperMass(Data.PropMass) + local Filler = ACF.GetProperMass(Data.FillerMass) + + return Text:format(MuzzleVel, ProjMass, PropMass, Filler) + end) + + local FillerStats = Menu:AddLabel() + FillerStats:TrackDataVar("FillerMass", "SetText") + FillerStats:SetValueFunction(function() + self:UpdateRoundData(ToolData, Data) + + local Text = "Blast Radius : %s m\nFragments : %s\nFragment Mass : %s\nFragment Velocity : %s m/s" + local Blast = math.Round(Data.BlastRadius, 2) + local FragMass = ACF.GetProperMass(Data.FragMass) + local FragVel = math.Round(Data.FragVel, 2) + + return Text:format(Blast, Data.Fragments, FragMass, FragVel) + end) + + local PenStats = Menu:AddLabel() + PenStats:TrackDataVar("Projectile", "SetText") + PenStats:TrackDataVar("Propellant") + PenStats:TrackDataVar("FillerMass") + PenStats:SetValueFunction(function() + self:UpdateRoundData(ToolData, Data) + + local Text = "Penetration : %s mm RHA\nAt 300m : %s mm RHA @ %s m/s\nAt 800m : %s mm RHA @ %s m/s" + local MaxPen = math.Round(Data.MaxPen, 2) + local R1V, R1P = ACF.PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 300) + local R2V, R2P = ACF.PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 800) + + return Text:format(MaxPen, R1P, R1V, R2P, R2V) + end) -function Ammo.MenuAction(Menu) - Menu:AddParagraph("Testing APHE menu.") + Menu:AddLabel("Note: The penetration range data is an approximation and may not be entirely accurate.") end ACF.RegisterAmmoDecal("APHE", "damage/ap_pen", "damage/ap_rico") diff --git a/lua/acf/shared/ammo_types/fl.lua b/lua/acf/shared/ammo_types/fl.lua index a670b59a2..4194b9b69 100644 --- a/lua/acf/shared/ammo_types/fl.lua +++ b/lua/acf/shared/ammo_types/fl.lua @@ -3,20 +3,20 @@ local Ammo = ACF.RegisterAmmoType("FL", "AP") function Ammo:OnLoaded() Ammo.BaseClass.OnLoaded(self) - self.Name = "Flechette" - self.Model = "models/munitions/dart_100mm.mdl" - self.Description = "Flechette rounds contain several long thin steel spikes, functioning as a shotgun shell for cannons. While it seems like the spikes would penetrate well, they tend to tumble in flight and impact at less than ideal angles, causing only minor penetration and structural damage. They are best used against infantry or lightly armored mobile targets such as aircraft or light tanks, since flechettes trade brute damage for a better chance to hit." + self.Name = "Flechette" + self.Model = "models/munitions/dart_100mm.mdl" + self.Description = "Flechette shells contain several steel darts inside, functioning as a large shotgun round." self.Blacklist = { AC = true, - RAC = true, - MG = true, - HMG = true, GL = true, + MG = true, SL = true, + HMG = true, + RAC = true, } end -function Ammo.Create(Gun, BulletData) +function Ammo:Create(Gun, BulletData) local FlechetteData = { Caliber = math.Round(BulletData.FlechetteRadius * 0.2, 2), Id = BulletData.Id, @@ -49,15 +49,16 @@ function Ammo.Create(Gun, BulletData) end else local BaseInaccuracy = math.tan(math.rad(Gun:GetSpread())) - local AddInaccuracy = math.tan(math.rad(BulletData.FlechetteSpread)) - local MuzzleVec = Gun:GetForward() + local AddInaccuracy = math.tan(math.rad(BulletData.FlechetteSpread)) + local MuzzleVec = Gun:GetForward() for _ = 1, BulletData.Flechettes do - local BaseInaccuracyMult = (math.random() ^ (1 / math.Clamp(ACF.GunInaccuracyBias, 0.5, 4))) * (Gun:GetUp() * (2 * math.random() - 1) + Gun:GetRight() * (2 * math.random() - 1)):GetNormalized() - local AddSpreadMult = (math.random() ^ (1 / math.Clamp(ACF.GunInaccuracyBias, 0.5, 4))) * (Gun:GetUp() * (2 * math.random() - 1) + Gun:GetRight() * (2 * math.random() - 1)):GetNormalized() + local GunUp, GunRight = Gun:GetUp(), Gun:GetRight() + local BaseInaccuracyMult = math.random() ^ (1 / math.Clamp(ACF.GunInaccuracyBias, 0.5, 4)) * (GunUp * (2 * math.random() - 1) + GunRight * (2 * math.random() - 1)):GetNormalized() + local AddSpreadMult = math.random() ^ (1 / math.Clamp(ACF.GunInaccuracyBias, 0.5, 4)) * (GunUp * (2 * math.random() - 1) + GunRight * (2 * math.random() - 1)):GetNormalized() BaseSpread = BaseInaccuracy * BaseInaccuracyMult - AddSpread = AddInaccuracy * AddSpreadMult + AddSpread = AddInaccuracy * AddSpreadMult FlechetteData.Flight = (MuzzleVec + BaseSpread + AddSpread):GetNormalized() * BulletData.MuzzleVel * 39.37 + Gun:GetVelocity() @@ -66,106 +67,78 @@ function Ammo.Create(Gun, BulletData) end end -function Ammo.Convert(_, PlayerData) - local ServerData = {} - local GUIData = {} - local Data = { - LengthAdj = 0.5 - } - - if not PlayerData.PropLength then - PlayerData.PropLength = 0 - end - - if not PlayerData.ProjLength then - PlayerData.ProjLength = 0 - end - - --flechette count - if not PlayerData.Data5 then - PlayerData.Data5 = 3 - end - - --flechette spread - if not PlayerData.Data6 then - PlayerData.Data6 = 5 - end - - --tracer - if not PlayerData.Data10 then - PlayerData.Data10 = 0 +function Ammo:UpdateRoundData(ToolData, Data, GUIData) + GUIData = GUIData or Data + + ACF.UpdateRoundSpecs(ToolData, Data, GUIData) + + local PenAdj = 0.8 --higher means lower pen, but more structure (hp) damage (old: 2.35, 2.85) + local RadiusAdj = 1.0 -- lower means less structure (hp) damage, but higher pen (old: 1.0, 0.8) + local Flechettes = math.Clamp(ToolData.Flechettes, Data.MinFlechettes, Data.MaxFlechettes) + local PackRatio = 0.0025 * Flechettes + 0.69 --how efficiently flechettes are packed into shell + + Data.Flechettes = Flechettes + Data.FlechetteSpread = math.Clamp(ToolData.Spread, Data.MinSpread, Data.MaxSpread) + Data.FlechetteRadius = (((PackRatio * RadiusAdj * Data.Caliber * 0.05) ^ 2) / Data.Flechettes) ^ 0.5 + Data.FlechetteArea = 3.1416 * Data.FlechetteRadius ^ 2 -- area of a single flechette + Data.FlechetteMass = Data.FlechetteArea * (Data.ProjLength * 7.9 / 1000) -- volume of single flechette * density of steel + Data.FlechettePenArea = (PenAdj * Data.FlechetteArea) ^ ACF.PenAreaMod + Data.FlechetteDragCoef = Data.FlechetteArea * 0.0001 / Data.FlechetteMass + Data.ProjMass = Data.Flechettes * Data.FlechetteMass -- total mass of all flechettes + Data.DragCoef = Data.FrArea * 0.0001 / Data.ProjMass + Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass) + + for K, V in pairs(self:GetDisplayData(Data)) do + GUIData[K] = V end +end - PlayerData, Data, ServerData, GUIData = ACF_RoundBaseGunpowder(PlayerData, Data, ServerData, GUIData) +function Ammo:BaseConvert(_, ToolData) + if not ToolData.Projectile then ToolData.Projectile = 0 end + if not ToolData.Propellant then ToolData.Propellant = 0 end + if not ToolData.Flechettes then ToolData.Flechettes = 3 end + if not ToolData.Spread then ToolData.Spread = 5 end - local GunClass = ACF.Weapons.Guns[Data.Id or PlayerData.Id].gunclass + local Data, GUIData = ACF.RoundBaseGunpowder(ToolData, { LengthAdj = 0.5 }) + local GunClass = ToolData.WeaponClass if GunClass == "SA" then - Data.MaxFlechettes = math.Clamp(math.floor(Data.Caliber * 3 - 4.5), 1, 32) + Data.MaxFlechettes = math.Clamp(math.floor(Data.Caliber * 0.3 - 4.5), 1, 32) elseif GunClass == "MO" then - Data.MaxFlechettes = math.Clamp(math.floor(Data.Caliber * 4) - 12, 1, 32) + Data.MaxFlechettes = math.Clamp(math.floor(Data.Caliber * 0.4) - 12, 1, 32) elseif GunClass == "HW" then - Data.MaxFlechettes = math.Clamp(math.floor(Data.Caliber * 4) - 10, 1, 32) + Data.MaxFlechettes = math.Clamp(math.floor(Data.Caliber * 0.4) - 10, 1, 32) else - Data.MaxFlechettes = math.Clamp(math.floor(Data.Caliber * 4) - 8, 1, 32) + Data.MaxFlechettes = math.Clamp(math.floor(Data.Caliber * 0.4) - 8, 1, 32) end - local PenAdj = 0.8 --higher means lower pen, but more structure (hp) damage (old: 2.35, 2.85) - local RadiusAdj = 1.0 -- lower means less structure (hp) damage, but higher pen (old: 1.0, 0.8) - Data.MinFlechettes = math.min(6, Data.MaxFlechettes) --force bigger guns to have higher min count - Data.Flechettes = math.Clamp(math.floor(PlayerData.Data5), Data.MinFlechettes, Data.MaxFlechettes) --number of flechettes - Data.MinSpread = 0.25 - Data.MaxSpread = 30 - Data.FlechetteSpread = math.Clamp(tonumber(PlayerData.Data6), Data.MinSpread, Data.MaxSpread) - - local PackRatio = 0.0025 * Data.Flechettes + 0.69 --how efficiently flechettes are packed into shell - - Data.FlechetteRadius = math.sqrt(((PackRatio * RadiusAdj * Data.Caliber * 0.5) ^ 2) / Data.Flechettes) -- max radius flechette can be, to fit number of flechettes in a shell - Data.FlechetteArea = 3.1416 * Data.FlechetteRadius ^ 2 -- area of a single flechette - Data.FlechetteMass = Data.FlechetteArea * (Data.ProjLength * 7.9 / 1000) -- volume of single flechette * density of steel - Data.FlechettePenArea = (PenAdj * Data.FlechetteArea) ^ ACF.PenAreaMod - Data.FlechetteDragCoef = (Data.FlechetteArea / 10000) / Data.FlechetteMass - Data.ProjMass = Data.Flechettes * Data.FlechetteMass -- total mass of all flechettes - Data.PropMass = Data.PropMass - Data.ShovePower = 0.2 - Data.PenArea = Data.FrArea ^ ACF.PenAreaMod - Data.DragCoef = ((Data.FrArea / 10000) / Data.ProjMass) - Data.LimitVel = 500 --Most efficient penetration speed in m/s - Data.KETransfert = 0.1 --Kinetic energy transfert to the target for movement purposes - Data.Ricochet = 75 --Base ricochet angle - Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass, Data.Caliber) - Data.BoomPower = Data.PropMass - - --Only the crates need this part - if SERVER then - ServerData.Id = PlayerData.Id - ServerData.Type = PlayerData.Type - - return table.Merge(Data, ServerData) - end + Data.MinSpread = 0.25 + Data.MaxSpread = 30 + Data.ShovePower = 0.2 + Data.PenArea = Data.FrArea ^ ACF.PenAreaMod + Data.LimitVel = 500 --Most efficient penetration speed in m/s + Data.KETransfert = 0.1 --Kinetic energy transfert to the target for movement purposes + Data.Ricochet = 75 --Base ricochet angle - --Only the GUI needs this part - if CLIENT then - GUIData = table.Merge(GUIData, Ammo.GetDisplayData(Data)) + self:UpdateRoundData(ToolData, Data, GUIData) - return table.Merge(Data, GUIData) - end + return Data, GUIData end -function Ammo.Network(Crate, BulletData) - Crate:SetNWString("AmmoType", "FL") - Crate:SetNWString("AmmoID", BulletData.Id) - Crate:SetNWFloat("PropMass", BulletData.PropMass) - Crate:SetNWFloat("MuzzleVel", BulletData.MuzzleVel) - Crate:SetNWFloat("Tracer", BulletData.Tracer) - Crate:SetNWFloat("Caliber", math.Round(BulletData.FlechetteRadius * 0.2, 2)) - Crate:SetNWFloat("ProjMass", BulletData.FlechetteMass) - Crate:SetNWFloat("DragCoef", BulletData.FlechetteDragCoef) - Crate:SetNWFloat("FillerMass", 0) +function Ammo:Network(Crate, BulletData) + Crate:SetNW2String("AmmoType", "FL") + Crate:SetNW2String("AmmoID", BulletData.Id) + Crate:SetNW2Float("PropMass", BulletData.PropMass) + Crate:SetNW2Float("MuzzleVel", BulletData.MuzzleVel) + Crate:SetNW2Float("Tracer", BulletData.Tracer) + Crate:SetNW2Float("Caliber", math.Round(BulletData.FlechetteRadius * 0.2, 2)) + Crate:SetNW2Float("ProjMass", BulletData.FlechetteMass) + Crate:SetNW2Float("DragCoef", BulletData.FlechetteDragCoef) + Crate:SetNW2Float("FillerMass", 0) end -function Ammo.GetDisplayData(BulletData) +function Ammo:GetDisplayData(BulletData) local Energy = ACF_Kinetic(BulletData.MuzzleVel * 39.37, BulletData.FlechetteMass, BulletData.LimitVel) return { @@ -173,11 +146,10 @@ function Ammo.GetDisplayData(BulletData) } end - -function Ammo.GetCrateText(BulletData) - local Text = "Muzzle Velocity: %s m/s\nMax Penetration: %s mm\nMax Spread: %s degrees" - local Data = Ammo.GetDisplayData(BulletData) - local Gun = ACF.Weapons.Guns[BulletData.Id] +function Ammo:GetCrateText(BulletData) + local Text = "Muzzle Velocity: %s m/s\nMax Penetration: %s mm\nMax Spread: %s degrees" + local Data = self:GetDisplayData(BulletData) + local Gun = ACF.Weapons.Guns[BulletData.Id] local Spread = 0 if Gun then @@ -186,63 +158,90 @@ function Ammo.GetCrateText(BulletData) Spread = GunClass and (GunClass.spread * ACF.GunInaccuracyScale) or 0 end - return Text:format(math.Round(BulletData.MuzzleVel, 2), math.floor(Data.MaxPen), math.ceil((BulletData.FlechetteSpread + Spread) * 10) * 0.1) + return Text:format(math.Round(BulletData.MuzzleVel, 2), math.Round(Data.MaxPen, 2), math.Round(BulletData.FlechetteSpread + Spread, 2)) end -function Ammo.CreateMenu(Panel, Table) - acfmenupanel:AmmoSelect(Ammo.Blacklist) +function Ammo:GetToolData() + local Data = Ammo.BaseClass.GetToolData(self) + Data.Flechettes = ACF.ReadNumber("Flechettes") + Data.Spread = ACF.ReadNumber("Spread") - acfmenupanel:CPanelText("Desc", "") --Description (Name, Desc) - acfmenupanel:CPanelText("LengthDisplay", "") --Total round length (Name, Desc) - acfmenupanel:AmmoSlider("PropLength", 0, 0, 1000, 3, "Propellant Length", "") --Propellant Length Slider (Name, Value, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("ProjLength", 0, 0, 1000, 3, "Projectile Length", "") --Projectile Length Slider (Name, Value, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("Flechettes", 3, 3, 32, 0, "Flechettes", "") --flechette count Slider (Name, Value, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("FlechetteSpread", 10, 5, 60, 1, "Flechette Spread", "") --flechette spread Slider (Name, Value, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoCheckbox("Tracer", "Tracer", "") --Tracer checkbox (Name, Title, Desc) - acfmenupanel:CPanelText("VelocityDisplay", "") --Proj muzzle velocity (Name, Desc) - acfmenupanel:CPanelText("PenetrationDisplay", "") --Proj muzzle penetration (Name, Desc) - - Ammo.UpdateMenu(Panel, Table) + return Data end -function Ammo.UpdateMenu(Panel) - local PlayerData = { - Id = acfmenupanel.AmmoData.Data.id, --AmmoSelect GUI - Type = "FL", --Hardcoded, match ACFRoundTypes table index - PropLength = acfmenupanel.AmmoData.PropLength, --PropLength slider - ProjLength = acfmenupanel.AmmoData.ProjLength, --ProjLength slider - Data5 = acfmenupanel.AmmoData.Flechettes, --Flechette count slider - Data6 = acfmenupanel.AmmoData.FlechetteSpread, --flechette spread slider - Data10 = acfmenupanel.AmmoData.Tracer and 1 or 0 -- Tracer - } +function Ammo:MenuAction(Menu, ToolData, Data) + local Flechettes = Menu:AddSlider("Flechette Amount", Data.MinFlechettes, Data.MaxFlechettes) + Flechettes:SetDataVar("Flechettes", "OnValueChanged") + Flechettes:SetValueFunction(function(Panel) + ToolData.Flechettes = math.floor(ACF.ReadNumber("Flechettes")) - local Data = Ammo.Convert(Panel, PlayerData) - - RunConsoleCommand("acfmenu_data1", acfmenupanel.AmmoData.Data.id) - RunConsoleCommand("acfmenu_data2", PlayerData.Type) - RunConsoleCommand("acfmenu_data3", Data.PropLength) --For Gun ammo, Data3 should always be Propellant - RunConsoleCommand("acfmenu_data4", Data.ProjLength) --And Data4 total round mass - RunConsoleCommand("acfmenu_data5", Data.Flechettes) - RunConsoleCommand("acfmenu_data6", Data.FlechetteSpread) - RunConsoleCommand("acfmenu_data10", Data.Tracer) - - acfmenupanel:AmmoSlider("PropLength", Data.PropLength, Data.MinPropLength, Data.MaxTotalLength, 3, "Propellant Length", "Propellant Mass : " .. (math.floor(Data.PropMass * 1000)) .. " g") --Propellant Length Slider (Name, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("ProjLength", Data.ProjLength, Data.MinProjLength, Data.MaxTotalLength, 3, "Projectile Length", "Projectile Mass : " .. (math.floor(Data.ProjMass * 1000)) .. " g") --Projectile Length Slider (Name, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("Flechettes", Data.Flechettes, Data.MinFlechettes, Data.MaxFlechettes, 0, "Flechettes", "Flechette Radius: " .. math.Round(Data.FlechetteRadius * 10, 2) .. " mm") - acfmenupanel:AmmoSlider("FlechetteSpread", Data.FlechetteSpread, Data.MinSpread, Data.MaxSpread, 1, "Flechette Spread", "") - acfmenupanel:AmmoCheckbox("Tracer", "Tracer : " .. (math.floor(Data.Tracer * 10) / 10) .. "cm\n", "") --Tracer checkbox (Name, Title, Desc) - acfmenupanel:CPanelText("Desc", Ammo.Description) --Description (Name, Desc) - acfmenupanel:CPanelText("LengthDisplay", "Round Length : " .. (math.floor((Data.PropLength + Data.ProjLength + Data.Tracer) * 100) / 100) .. "/" .. Data.MaxTotalLength .. " cm") --Total round length (Name, Desc) - acfmenupanel:CPanelText("VelocityDisplay", "Muzzle Velocity : " .. math.floor(Data.MuzzleVel * ACF.Scale) .. " m/s") --Proj muzzle velocity (Name, Desc) - - local R1V, R1P = ACF_PenRanging(Data.MuzzleVel, Data.FlechetteDragCoef, Data.FlechetteMass, Data.FlechettePenArea, Data.LimitVel, 300) - local R2V, R2P = ACF_PenRanging(Data.MuzzleVel, Data.FlechetteDragCoef, Data.FlechetteMass, Data.FlechettePenArea, Data.LimitVel, 800) - - acfmenupanel:CPanelText("PenetrationDisplay", "Maximum Penetration : " .. math.floor(Data.MaxPen) .. " mm RHA\n\n300m pen: " .. math.Round(R1P, 0) .. "mm @ " .. math.Round(R1V, 0) .. " m\\s\n800m pen: " .. math.Round(R2P, 0) .. "mm @ " .. math.Round(R2V, 0) .. " m\\s\n\nThe range data is an approximation and may not be entirely accurate.") --Proj muzzle penetration (Name, Desc) -end + Ammo:UpdateRoundData(ToolData, Data) + + Panel:SetValue(Data.Flechettes) + + return Data.Flechettes + end) + + local Spread = Menu:AddSlider("Flechette Spread", Data.MinSpread, Data.MaxSpread, 2) + Spread:SetDataVar("Spread", "OnValueChanged") + Spread:SetValueFunction(function(Panel) + ToolData.Spread = ACF.ReadNumber("Spread") + + Ammo:UpdateRoundData(ToolData, Data) + + Panel:SetValue(Data.FlechetteSpread) + + return Data.FlechetteSpread + end) + + local Tracer = Menu:AddCheckBox("Tracer") + Tracer:SetDataVar("Tracer", "OnChange") + Tracer:SetValueFunction(function(Panel) + ToolData.Tracer = ACF.ReadBool("Tracer") + + self:UpdateRoundData(ToolData, Data) + + ACF.WriteValue("Projectile", Data.ProjLength) + ACF.WriteValue("Propellant", Data.PropLength) + + Panel:SetText("Tracer : " .. Data.Tracer .. " cm") + Panel:SetValue(ToolData.Tracer) + + return ToolData.Tracer + end) + + local RoundStats = Menu:AddLabel() + RoundStats:TrackDataVar("Projectile", "SetText") + RoundStats:TrackDataVar("Propellant") + RoundStats:TrackDataVar("Flechettes") + RoundStats:SetValueFunction(function() + self:UpdateRoundData(ToolData, Data) + + local Text = "Muzzle Velocity : %s m/s\nProjectile Mass : %s\nPropellant Mass : %s\nFlechette Mass : %s" + local MuzzleVel = math.Round(Data.MuzzleVel * ACF.Scale, 2) + local ProjMass = ACF.GetProperMass(Data.ProjMass) + local PropMass = ACF.GetProperMass(Data.PropMass) + local FLMass = ACF.GetProperMass(Data.FlechetteMass) + + return Text:format(MuzzleVel, ProjMass, PropMass, FLMass) + end) + + local PenStats = Menu:AddLabel() + PenStats:TrackDataVar("Projectile", "SetText") + PenStats:TrackDataVar("Propellant") + PenStats:TrackDataVar("Flechettes") + PenStats:SetValueFunction(function() + self:UpdateRoundData(ToolData, Data) + + local Text = "Penetration : %s mm RHA\nAt 300m : %s mm RHA @ %s m/s\nAt 800m : %s mm RHA @ %s m/s" + local MaxPen = math.Round(Data.MaxPen, 2) + local R1V, R1P = ACF.PenRanging(Data.MuzzleVel, Data.FlechetteDragCoef, Data.FlechetteMass, Data.FlechettePenArea, Data.LimitVel, 300) + local R2V, R2P = ACF.PenRanging(Data.MuzzleVel, Data.FlechetteDragCoef, Data.FlechetteMass, Data.FlechettePenArea, Data.LimitVel, 800) + + return Text:format(MaxPen, R1P, R1V, R2P, R2V) + end) -function Ammo.MenuAction(Menu) - Menu:AddParagraph("Testing FL menu.") + Menu:AddLabel("Note: The penetration range data is an approximation and may not be entirely accurate.") end ACF.RegisterAmmoDecal("FL", "damage/ap_pen", "damage/ap_rico") \ No newline at end of file diff --git a/lua/acf/shared/ammo_types/he.lua b/lua/acf/shared/ammo_types/he.lua index 3737c9eab..ec025c1a5 100644 --- a/lua/acf/shared/ammo_types/he.lua +++ b/lua/acf/shared/ammo_types/he.lua @@ -3,106 +3,95 @@ local Ammo = ACF.RegisterAmmoType("HE", "APHE") function Ammo:OnLoaded() Ammo.BaseClass.OnLoaded(self) - self.Name = "High Explosive" - self.Description = "A shell filled with explosives, detonating on impact." + self.Name = "High Explosive" + self.Description = "A shell filled with explosives, detonates on impact." self.Blacklist = { MG = true, RAC = true, } end -function Ammo.Convert(_, PlayerData) - local Data = {} - local ServerData = {} - local GUIData = {} +function Ammo:UpdateRoundData(ToolData, Data, GUIData) + GUIData = GUIData or Data - if not PlayerData.PropLength then - PlayerData.PropLength = 0 - end + ACF.UpdateRoundSpecs(ToolData, Data, GUIData) - if not PlayerData.ProjLength then - PlayerData.ProjLength = 0 - end + local HEDensity = ACF.HEDensity * 0.001 + -- Volume of the projectile as a cylinder - Volume of the filler * density of steel + Volume of the filler * density of TNT + local ProjMass = math.max(GUIData.ProjVolume - ToolData.FillerMass, 0) * 0.0079 + math.min(ToolData.FillerMass, GUIData.ProjVolume) * HEDensity + local MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, ProjMass) + local Energy = ACF_Kinetic(MuzzleVel * 39.37, ProjMass, Data.LimitVel) + local MaxVol = ACF.RoundShellCapacity(Energy.Momentum, Data.FrArea, Data.Caliber, Data.ProjLength) + + GUIData.MaxFillerVol = math.min(GUIData.ProjVolume, MaxVol) + GUIData.FillerVol = math.min(ToolData.FillerMass, GUIData.MaxFillerVol) - PlayerData.Data5 = math.max(PlayerData.Data5 or 0, 0) + Data.FillerMass = GUIData.FillerVol * HEDensity + Data.ProjMass = math.max(GUIData.ProjVolume - GUIData.FillerVol, 0) * 0.0079 + Data.FillerMass + Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass) + Data.DragCoef = Data.FrArea * 0.0001 / Data.ProjMass - if not PlayerData.Data10 then - PlayerData.Data10 = 0 + for K, V in pairs(self:GetDisplayData(Data)) do + GUIData[K] = V end +end - PlayerData, Data, ServerData, GUIData = ACF_RoundBaseGunpowder(PlayerData, Data, ServerData, GUIData) - - Data.ProjMass = math.max(GUIData.ProjVolume - PlayerData.Data5, 0) * 7.9 / 1000 + math.min(PlayerData.Data5, GUIData.ProjVolume) * ACF.HEDensity / 1000 --Volume of the projectile as a cylinder - Volume of the filler * density of steel + Volume of the filler * density of TNT - Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass, Data.Caliber) +function Ammo:BaseConvert(_, ToolData) + if not ToolData.Projectile then ToolData.Projectile = 0 end + if not ToolData.Propellant then ToolData.Propellant = 0 end + if not ToolData.FillerMass then ToolData.FillerMass = 0 end - local Energy = ACF_Kinetic(Data.MuzzleVel * 39.37, Data.ProjMass, Data.LimitVel) - local MaxVol = ACF_RoundShellCapacity(Energy.Momentum, Data.FrArea, Data.Caliber, Data.ProjLength) + local Data, GUIData = ACF.RoundBaseGunpowder(ToolData, {}) GUIData.MinFillerVol = 0 - GUIData.MaxFillerVol = math.min(GUIData.ProjVolume, MaxVol) - GUIData.FillerVol = math.min(PlayerData.Data5, GUIData.MaxFillerVol) - Data.FillerMass = GUIData.FillerVol * ACF.HEDensity / 1000 - Data.ProjMass = math.max(GUIData.ProjVolume - GUIData.FillerVol, 0) * 7.9 / 1000 + Data.FillerMass - Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass, Data.Caliber) - Data.ShovePower = 0.1 - Data.PenArea = Data.FrArea ^ ACF.PenAreaMod - Data.DragCoef = ((Data.FrArea / 10000) / Data.ProjMass) - Data.LimitVel = 100 --Most efficient penetration speed in m/s - Data.KETransfert = 0.1 --Kinetic energy transfert to the target for movement purposes - Data.Ricochet = 60 --Base ricochet angle - Data.DetonatorAngle = 80 - Data.BoomPower = Data.PropMass + Data.FillerMass - Data.CanFuze = Data.Caliber > 2 -- Can fuze on calibers > 20mm - - --Only the crates need this part - if SERVER then - ServerData.Id = PlayerData.Id - ServerData.Type = PlayerData.Type - - return table.Merge(Data, ServerData) - end - --Only the GUI needs this part - if CLIENT then - GUIData = table.Merge(GUIData, Ammo.GetDisplayData(Data)) + Data.ShovePower = 0.1 + Data.PenArea = Data.FrArea ^ ACF.PenAreaMod + Data.LimitVel = 100 --Most efficient penetration speed in m/s + Data.KETransfert = 0.1 --Kinetic energy transfert to the target for movement purposes + Data.Ricochet = 60 --Base ricochet angle + Data.DetonatorAngle = 80 + Data.CanFuze = Data.Caliber > 20 -- Can fuze on calibers > 20mm - return table.Merge(Data, GUIData) - end + self:UpdateRoundData(ToolData, Data, GUIData) + + return Data, GUIData end -function Ammo.Network(Crate, BulletData) - Crate:SetNWString("AmmoType", "HE") - Crate:SetNWString("AmmoID", BulletData.Id) - Crate:SetNWFloat("Caliber", BulletData.Caliber) - Crate:SetNWFloat("ProjMass", BulletData.ProjMass) - Crate:SetNWFloat("FillerMass", BulletData.FillerMass) - Crate:SetNWFloat("PropMass", BulletData.PropMass) - Crate:SetNWFloat("DragCoef", BulletData.DragCoef) - Crate:SetNWFloat("MuzzleVel", BulletData.MuzzleVel) - Crate:SetNWFloat("Tracer", BulletData.Tracer) +function Ammo:Network(Crate, BulletData) + Crate:SetNW2String("AmmoType", "HE") + Crate:SetNW2String("AmmoID", BulletData.Id) + Crate:SetNW2Float("Caliber", BulletData.Caliber) + Crate:SetNW2Float("ProjMass", BulletData.ProjMass) + Crate:SetNW2Float("FillerMass", BulletData.FillerMass) + Crate:SetNW2Float("PropMass", BulletData.PropMass) + Crate:SetNW2Float("DragCoef", BulletData.DragCoef) + Crate:SetNW2Float("MuzzleVel", BulletData.MuzzleVel) + Crate:SetNW2Float("Tracer", BulletData.Tracer) end -function Ammo.GetDisplayData(Data) - local FragMass = Data.ProjMass - Data.FillerMass +function Ammo:GetDisplayData(Data) + local FragMass = Data.ProjMass - Data.FillerMass + local Fragments = math.max(math.floor((Data.FillerMass / FragMass) * ACF.HEFrag), 2) return { - BlastRadius = Data.FillerMass ^ 0.33 * 8, - Fragments = math.max(math.floor((Data.FillerMass / FragMass) * ACF.HEFrag), 2), - FragMass = FragMass / GUIData.Fragments, - FragVel = (Data.FillerMass * ACF.HEPower * 1000 / GUIData.FragMass / GUIData.Fragments) ^ 0.5, + BlastRadius = Data.FillerMass ^ 0.33 * 8, + Fragments = Fragments, + FragMass = FragMass / Fragments, + FragVel = (Data.FillerMass * ACF.HEPower * 1000 / FragMass / Fragments / Fragments) ^ 0.5, } end -function Ammo.GetCrateText(BulletData) +function Ammo:GetCrateText(BulletData) local Text = "Muzzle Velocity: %s m/s\nBlast Radius: %s m\nBlast Energy: %s KJ" - local Data = Ammo.GetDisplayData(BulletData) + local Data = self:GetDisplayData(BulletData) - return Text:format(math.Round(BulletData.MuzzleVel, 2), math.Round(Data.BlastRadius, 2), math.floor(BulletData.FillerMass * ACF.HEPower)) + return Text:format(math.Round(BulletData.MuzzleVel, 2), math.Round(Data.BlastRadius, 2), math.Round(BulletData.FillerMass * ACF.HEPower, 2)) end -function Ammo.PropImpact(_, Bullet, Target, HitNormal, HitPos, Bone) +function Ammo:PropImpact(_, Bullet, Target, HitNormal, HitPos, Bone) if ACF_Check(Target) then - local Speed = Bullet.Flight:Length() / ACF.Scale + local Speed = Bullet.Flight:Length() / ACF.Scale local Energy = ACF_Kinetic(Speed, Bullet.ProjMass - Bullet.FillerMass, Bullet.LimitVel) local HitRes = ACF_RoundImpact(Bullet, Speed, Energy, Target, HitPos, HitNormal, Bone) @@ -112,58 +101,69 @@ function Ammo.PropImpact(_, Bullet, Target, HitNormal, HitPos, Bone) return false end -function Ammo.WorldImpact() +function Ammo:WorldImpact() return false end -function Ammo.CreateMenu(Panel, Table) - acfmenupanel:AmmoSelect(Ammo.Blacklist) +function Ammo:MenuAction(Menu, ToolData, Data) + local FillerMass = Menu:AddSlider("Filler Volume", 0, Data.MaxFillerVol, 2) + FillerMass:SetDataVar("FillerMass", "OnValueChanged") + FillerMass:TrackDataVar("Projectile") + FillerMass:SetValueFunction(function(Panel) + ToolData.FillerMass = math.Round(ACF.ReadNumber("FillerMass"), 2) - acfmenupanel:CPanelText("Desc", "") --Description (Name, Desc) - acfmenupanel:CPanelText("LengthDisplay", "") --Total round length (Name, Desc) - acfmenupanel:AmmoSlider("PropLength", 0, 0, 1000, 3, "Propellant Length", "") --Slider (Name, Value, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("ProjLength", 0, 0, 1000, 3, "Projectile Length", "") --Slider (Name, Value, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("FillerVol", 0, 0, 1000, 3, "HE Filler", "") --Slider (Name, Value, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoCheckbox("Tracer", "Tracer", "") --Tracer checkbox (Name, Title, Desc) - acfmenupanel:CPanelText("VelocityDisplay", "") --Proj muzzle velocity (Name, Desc) - acfmenupanel:CPanelText("BlastDisplay", "") --HE Blast data (Name, Desc) - acfmenupanel:CPanelText("FragDisplay", "") --HE Fragmentation data (Name, Desc) + self:UpdateRoundData(ToolData, Data) - Ammo.UpdateMenu(Panel, Table) -end + Panel:SetMax(Data.MaxFillerVol) + Panel:SetValue(Data.FillerVol) -function Ammo.UpdateMenu(Panel) - local PlayerData = { - Id = acfmenupanel.AmmoData.Data.id, --AmmoSelect GUI - Type = "HE", --Hardcoded, match ACFRoundTypes table index - PropLength = acfmenupanel.AmmoData.PropLength, --PropLength slider - ProjLength = acfmenupanel.AmmoData.ProjLength, --ProjLength slider - Data5 = acfmenupanel.AmmoData.FillerVol, - Data10 = acfmenupanel.AmmoData.Tracer and 1 or 0, --Tracer - } + return Data.FillerVol + end) - local Data = Ammo.Convert(Panel, PlayerData) - - RunConsoleCommand("acfmenu_data1", acfmenupanel.AmmoData.Data.id) - RunConsoleCommand("acfmenu_data2", PlayerData.Type) - RunConsoleCommand("acfmenu_data3", Data.PropLength) --For Gun ammo, Data3 should always be Propellant - RunConsoleCommand("acfmenu_data4", Data.ProjLength) --And Data4 total round mass - RunConsoleCommand("acfmenu_data5", Data.FillerVol) - RunConsoleCommand("acfmenu_data10", Data.Tracer) - - acfmenupanel:AmmoSlider("PropLength", Data.PropLength, Data.MinPropLength, Data.MaxTotalLength, 3, "Propellant Length", "Propellant Mass : " .. (math.floor(Data.PropMass * 1000)) .. " g") --Propellant Length Slider (Name, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("ProjLength", Data.ProjLength, Data.MinProjLength, Data.MaxTotalLength, 3, "Projectile Length", "Projectile Mass : " .. (math.floor(Data.ProjMass * 1000)) .. " g") --Projectile Length Slider (Name, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("FillerVol", Data.FillerVol, Data.MinFillerVol, Data.MaxFillerVol, 3, "HE Filler Volume", "HE Filler Mass : " .. (math.floor(Data.FillerMass * 1000)) .. " g") --HE Filler Slider (Name, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoCheckbox("Tracer", "Tracer : " .. (math.floor(Data.Tracer * 10) / 10) .. "cm\n", "") --Tracer checkbox (Name, Title, Desc) - acfmenupanel:CPanelText("Desc", Ammo.Description) --Description (Name, Desc) - acfmenupanel:CPanelText("LengthDisplay", "Round Length : " .. (math.floor((Data.PropLength + Data.ProjLength + Data.Tracer) * 100) / 100) .. "/" .. Data.MaxTotalLength .. " cm") --Total round length (Name, Desc) - acfmenupanel:CPanelText("VelocityDisplay", "Muzzle Velocity : " .. math.floor(Data.MuzzleVel * ACF.Scale) .. " m/s") --Proj muzzle velocity (Name, Desc) - acfmenupanel:CPanelText("BlastDisplay", "Blast Radius : " .. (math.floor(Data.BlastRadius * 100) / 100) .. " m") --Proj muzzle velocity (Name, Desc) - acfmenupanel:CPanelText("FragDisplay", "Fragments : " .. Data.Fragments .. "\n Average Fragment Weight : " .. (math.floor(Data.FragMass * 10000) / 10) .. " g \n Average Fragment Velocity : " .. math.floor(Data.FragVel) .. " m/s") --Proj muzzle penetration (Name, Desc) -end + local Tracer = Menu:AddCheckBox("Tracer") + Tracer:SetDataVar("Tracer", "OnChange") + Tracer:SetValueFunction(function(Panel) + ToolData.Tracer = ACF.ReadBool("Tracer") + + self:UpdateRoundData(ToolData, Data) + + ACF.WriteValue("Projectile", Data.ProjLength) + ACF.WriteValue("Propellant", Data.PropLength) + + Panel:SetText("Tracer : " .. Data.Tracer .. " cm") + Panel:SetValue(ToolData.Tracer) + + return ToolData.Tracer + end) + + local RoundStats = Menu:AddLabel() + RoundStats:TrackDataVar("Projectile", "SetText") + RoundStats:TrackDataVar("Propellant") + RoundStats:TrackDataVar("FillerMass") + RoundStats:SetValueFunction(function() + self:UpdateRoundData(ToolData, Data) + + local Text = "Muzzle Velocity : %s m/s\nProjectile Mass : %s\nPropellant Mass : %s\nExplosive Mass : %s" + local MuzzleVel = math.Round(Data.MuzzleVel * ACF.Scale, 2) + local ProjMass = ACF.GetProperMass(Data.ProjMass) + local PropMass = ACF.GetProperMass(Data.PropMass) + local Filler = ACF.GetProperMass(Data.FillerMass) + + return Text:format(MuzzleVel, ProjMass, PropMass, Filler) + end) + + local FillerStats = Menu:AddLabel() + FillerStats:TrackDataVar("FillerMass", "SetText") + FillerStats:SetValueFunction(function() + self:UpdateRoundData(ToolData, Data) + + local Text = "Blast Radius : %s m\nFragments : %s\nFragment Mass : %s\nFragment Velocity : %s m/s" + local Blast = math.Round(Data.BlastRadius, 2) + local FragMass = ACF.GetProperMass(Data.FragMass) + local FragVel = math.Round(Data.FragVel, 2) -function Ammo.MenuAction(Menu) - Menu:AddParagraph("Testing HE menu.") + return Text:format(Blast, Data.Fragments, FragMass, FragVel) + end) end ACF.RegisterAmmoDecal("HE", "damage/he_pen", "damage/he_rico") diff --git a/lua/acf/shared/ammo_types/heat.lua b/lua/acf/shared/ammo_types/heat.lua index 0e45e03e6..eeb86e580 100644 --- a/lua/acf/shared/ammo_types/heat.lua +++ b/lua/acf/shared/ammo_types/heat.lua @@ -4,22 +4,22 @@ local DecalIndex = ACF.GetAmmoDecalIndex function Ammo:OnLoaded() Ammo.BaseClass.OnLoaded(self) - self.Name = "High Explosive Anti-Tank" - self.Description = "A shell with a shaped charge. When the round detonates, the explosive energy is focused into driving a small molten metal penetrator into the victim with extreme force, though this results in reduced damage from the explosion itself. Multiple layers of armor will dissipate the penetrator quickly." + self.Name = "High Explosive Anti-Tank" + self.Description = "A round with a shaped charge inside. Fires a high-velocity jet on detonation." self.Blacklist = { + AC = true, MG = true, + SB = true, + SL = true, HMG = true, RAC = true, - AC = true, - SL = true, - SB = true, } end -function Ammo.ConeCalc(ConeAngle, Radius) +function Ammo:ConeCalc(ConeAngle, Radius) local ConeLength = math.tan(math.rad(ConeAngle)) * Radius local ConeArea = 3.1416 * Radius * (Radius ^ 2 + ConeLength ^ 2) ^ 0.5 - local ConeVol = (3.1416 * Radius ^ 2 * ConeLength) / 3 + local ConeVol = (3.1416 * Radius ^ 2 * ConeLength) * 0.33 return ConeLength, ConeArea, ConeVol end @@ -27,7 +27,7 @@ end -- calculates conversion of filler from powering HEAT jet to raw HE based on crush vel -- above a threshold vel, HEAT jet doesn't have time to form properly, converting to raw HE proportionally -- Vel needs to be in m/s (gmu*0.0254) -function Ammo.CrushCalc(Vel, FillerMass) +function Ammo:CrushCalc(Vel, FillerMass) local Crushed = math.Clamp((Vel - ACF.HEATMinCrush) / (ACF.HEATMaxCrush - ACF.HEATMinCrush), 0, 1) local HE_Filler = Lerp(Crushed, FillerMass * ACF.HEATBoomConvert, FillerMass) local HEAT_Filler = Lerp(Crushed, FillerMass, 0) @@ -36,192 +36,166 @@ function Ammo.CrushCalc(Vel, FillerMass) end -- coneang now required for slug recalculation at detonation, defaults to 55 if not present -function Ammo.CalcSlugMV(Data, HEATFillerMass) +function Ammo:CalcSlugMV(Data, HEATFillerMass) --keep fillermass/2 so that penetrator stays the same. - return (HEATFillerMass / 2 * ACF.HEPower * math.sin(math.rad(10 + (Data.ConeAng or 55)) / 2) / Data.SlugMass) ^ ACF.HEATMVScale + return (HEATFillerMass * 0.5 * ACF.HEPower * math.sin(math.rad(10 + (Data.ConeAng or 55)) * 0.5) / Data.SlugMass) ^ ACF.HEATMVScale end -function Ammo.Convert(_, PlayerData) - local Data = {} - local ServerData = {} - local GUIData = {} - - if not PlayerData.PropLength then - PlayerData.PropLength = 0 - end - - if not PlayerData.ProjLength then - PlayerData.ProjLength = 0 - end - - PlayerData.Data5 = math.max(PlayerData.Data5 or 0, 0) - - if not PlayerData.Data6 then - PlayerData.Data6 = 0 - end - - if not PlayerData.Data7 then - PlayerData.Data7 = 0 - end - - if not PlayerData.Data10 then - PlayerData.Data10 = 0 +function Ammo:UpdateRoundData(ToolData, Data, GUIData) + GUIData = GUIData or Data + + ACF.UpdateRoundSpecs(ToolData, Data, GUIData) + + local MaxConeAng = math.deg(math.atan((Data.ProjLength - Data.Caliber * 0.002) / (Data.Caliber * 0.05))) + local LinerAngle = math.Clamp(ToolData.LinerAngle, GUIData.MinConeAng, MaxConeAng) + local _, ConeArea, AirVol = self:ConeCalc(LinerAngle, Data.Caliber * 0.05) + + local LinerRad = math.rad(LinerAngle * 0.5) + local SlugCaliber = Data.Caliber * 0.1 - Data.Caliber * (math.sin(LinerRad) * 0.5 + math.cos(LinerRad) * 1.5) * 0.05 + local SlugFrArea = 3.1416 * (SlugCaliber * 0.5) ^ 2 + local ConeVol = ConeArea * Data.Caliber * 0.002 + local ProjMass = math.max(GUIData.ProjVolume - ToolData.FillerMass, 0) * 0.0079 + math.min(ToolData.FillerMass, GUIData.ProjVolume) * ACF.HEDensity * 0.001 + ConeVol * 0.0079 --Volume of the projectile as a cylinder - Volume of the filler - Volume of the crush cone * density of steel + Volume of the filler * density of TNT + Area of the cone * thickness * density of steel + local MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, ProjMass) + local Energy = ACF_Kinetic(MuzzleVel * 39.37, ProjMass, Data.LimitVel) + local MaxVol = ACF.RoundShellCapacity(Energy.Momentum, Data.FrArea, Data.Caliber, Data.ProjLength) + + GUIData.MaxConeAng = MaxConeAng + GUIData.MaxFillerVol = math.max(math.Round(MaxVol - AirVol - ConeVol, 2), GUIData.MinFillerVol) + GUIData.FillerVol = math.Clamp(ToolData.FillerMass, GUIData.MinFillerVol, GUIData.MaxFillerVol) + + Data.ConeAng = LinerAngle + Data.FillerMass = GUIData.FillerVol * ACF.HEDensity * 0.00069 + Data.ProjMass = math.max(GUIData.ProjVolume - GUIData.FillerVol - AirVol - ConeVol, 0) * 0.0079 + Data.FillerMass + ConeVol * 0.0079 + Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass) + Data.SlugMass = ConeVol * 0.0079 + Data.SlugCaliber = SlugCaliber + Data.SlugPenArea = SlugFrArea ^ ACF.PenAreaMod + Data.SlugDragCoef = SlugFrArea * 0.0001 / Data.SlugMass + + local _, HEATFiller, BoomFiller = self:CrushCalc(Data.MuzzleVel, Data.FillerMass) + + Data.BoomFillerMass = BoomFiller + Data.SlugMV = self:CalcSlugMV(Data, HEATFiller) + Data.CasingMass = Data.ProjMass - Data.FillerMass - ConeVol * 0.0079 + Data.DragCoef = Data.FrArea * 0.0001 / Data.ProjMass + + for K, V in pairs(self:GetDisplayData(Data)) do + GUIData[K] = V end +end - PlayerData, Data, ServerData, GUIData = ACF_RoundBaseGunpowder(PlayerData, Data, ServerData, GUIData) - - local _, ConeArea, AirVol = Ammo.ConeCalc(PlayerData.Data6, Data.Caliber / 2, PlayerData.ProjLength) - local ConeThick = Data.Caliber / 50 - - Data.ProjMass = math.max(GUIData.ProjVolume - PlayerData.Data5, 0) * 7.9 / 1000 + math.min(PlayerData.Data5, GUIData.ProjVolume) * ACF.HEDensity / 1000 + ConeArea * ConeThick * 7.9 / 1000 --Volume of the projectile as a cylinder - Volume of the filler - Volume of the crush cone * density of steel + Volume of the filler * density of TNT + Area of the cone * thickness * density of steel - Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass, Data.Caliber) - - local Energy = ACF_Kinetic(Data.MuzzleVel * 39.37, Data.ProjMass, Data.LimitVel) - local MaxVol = ACF_RoundShellCapacity(Energy.Momentum, Data.FrArea, Data.Caliber, Data.ProjLength) - - GUIData.MinConeAng = 0 - GUIData.MaxConeAng = math.deg(math.atan((Data.ProjLength - ConeThick) / (Data.Caliber * 0.5))) - - Data.ConeAng = math.Clamp(PlayerData.Data6 * 1, GUIData.MinConeAng, GUIData.MaxConeAng) - - _, ConeArea, AirVol = Ammo.ConeCalc(Data.ConeAng, Data.Caliber / 2, Data.ProjLength) +function Ammo:BaseConvert(_, ToolData) + if not ToolData.Projectile then ToolData.Projectile = 0 end + if not ToolData.Propellant then ToolData.Propellant = 0 end + if not ToolData.FillerMass then ToolData.FillerMass = 0 end + if not ToolData.LinerAngle then ToolData.LinerAngle = 0 end - local ConeVol = ConeArea * ConeThick + local Data, GUIData = ACF.RoundBaseGunpowder(ToolData, {}) + GUIData.MinConeAng = 0 GUIData.MinFillerVol = 0 - GUIData.MaxFillerVol = math.max(MaxVol - AirVol - ConeVol, GUIData.MinFillerVol) - GUIData.FillerVol = math.Clamp(PlayerData.Data5 * 1, GUIData.MinFillerVol, GUIData.MaxFillerVol) - - -- fillermass used for shell mass calcs - -- heatfillermass is how much fillermass is used to power heat jet - -- boomfillermass is how much fillermass creates HE damage on detonation. technically get 1/3 extra fillermass free as HE with no crushing, but screw trying to rebalance heat pen to properly use 1/3 of filler for HE and 2/3 for jet - -- distribution of heat and boom fillermass is calculated at detonation, or for GUI stuff - Data.FillerMass = GUIData.FillerVol * ACF.HEDensity / 1450 - Data.ProjMass = math.max(GUIData.ProjVolume - GUIData.FillerVol - AirVol - ConeVol, 0) * 7.9 / 1000 + Data.FillerMass + ConeVol * 7.9 / 1000 - Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass, Data.Caliber) - - --Let's calculate the actual HEAT slug - local Rad = math.rad(Data.ConeAng / 2) - - Data.SlugMass = ConeVol * 7.9 / 1000 - Data.SlugCaliber = Data.Caliber - Data.Caliber * (math.sin(Rad) * 0.5 + math.cos(Rad) * 1.5) * 0.5 - - local SlugFrArea = 3.1416 * (Data.SlugCaliber * 0.5) ^ 2 - - Data.SlugPenArea = SlugFrArea ^ ACF.PenAreaMod - Data.SlugDragCoef = ((SlugFrArea / 10000) / Data.SlugMass) - Data.SlugRicochet = 500 --Base ricochet angle (The HEAT slug shouldn't ricochet at all) - - -- these are only for compatibility with other stuff. it's recalculated when the round is detonated - local _, HEATFiller, BoomFiller = Ammo.CrushCalc(Data.MuzzleVel, Data.FillerMass) - - Data.BoomFillerMass = BoomFiller - Data.SlugMV = Ammo.CalcSlugMV(Data, HEATFiller) - Data.CasingMass = Data.ProjMass - Data.FillerMass - ConeVol * 7.9 / 1000 - Data.ShovePower = 0.1 - Data.PenArea = Data.FrArea ^ ACF.PenAreaMod - Data.DragCoef = ((Data.FrArea / 10000) / Data.ProjMass) - Data.LimitVel = 100 --Most efficient penetration speed in m/s - Data.KETransfert = 0.1 --Kinetic energy transfert to the target for movement purposes - Data.Ricochet = 60 --Base ricochet angle - Data.DetonatorAngle = 75 - Data.Detonated = false - Data.NotFirstPen = false - Data.CanFuze = Data.Caliber > 2 -- Can fuze on calibers > 20mm - - --Only the crates need this part - if SERVER then - ServerData.Id = PlayerData.Id - ServerData.Type = PlayerData.Type - - return table.Merge(Data, ServerData) - end - --Only the GUI needs this part - if CLIENT then - GUIData = table.Merge(GUIData, Ammo.GetDisplayData(Data)) + Data.SlugRicochet = 500 -- Base ricochet angle (The HEAT slug shouldn't ricochet at all) + Data.ShovePower = 0.1 + Data.PenArea = Data.FrArea ^ ACF.PenAreaMod + Data.LimitVel = 100 -- Most efficient penetration speed in m/s + Data.KETransfert = 0.1 -- Kinetic energy transfert to the target for movement purposes + Data.Ricochet = 60 -- Base ricochet angle + Data.DetonatorAngle = 75 + Data.Detonated = false + Data.NotFirstPen = false + Data.CanFuze = Data.Caliber > 20 -- Can fuze on calibers > 20mm - return table.Merge(Data, GUIData) - end + self:UpdateRoundData(ToolData, Data, GUIData) + + return Data, GUIData end -function Ammo.Network(Crate, BulletData) - Crate:SetNWString("AmmoType", "HEAT") - Crate:SetNWString("AmmoID", BulletData.Id) - Crate:SetNWFloat("Caliber", BulletData.Caliber) - Crate:SetNWFloat("ProjMass", BulletData.ProjMass) - Crate:SetNWFloat("FillerMass", BulletData.FillerMass) - Crate:SetNWFloat("PropMass", BulletData.PropMass) - Crate:SetNWFloat("DragCoef", BulletData.DragCoef) - Crate:SetNWFloat("SlugMass", BulletData.SlugMass) - Crate:SetNWFloat("SlugCaliber", BulletData.SlugCaliber) - Crate:SetNWFloat("SlugDragCoef", BulletData.SlugDragCoef) - Crate:SetNWFloat("MuzzleVel", BulletData.MuzzleVel) - Crate:SetNWFloat("Tracer", BulletData.Tracer) +function Ammo:Network(Crate, BulletData) + Crate:SetNW2String("AmmoType", "HEAT") + Crate:SetNW2String("AmmoID", BulletData.Id) + Crate:SetNW2Float("Caliber", BulletData.Caliber) + Crate:SetNW2Float("ProjMass", BulletData.ProjMass) + Crate:SetNW2Float("FillerMass", BulletData.FillerMass) + Crate:SetNW2Float("PropMass", BulletData.PropMass) + Crate:SetNW2Float("DragCoef", BulletData.DragCoef) + Crate:SetNW2Float("SlugMass", BulletData.SlugMass) + Crate:SetNW2Float("SlugCaliber", BulletData.SlugCaliber) + Crate:SetNW2Float("SlugDragCoef", BulletData.SlugDragCoef) + Crate:SetNW2Float("MuzzleVel", BulletData.MuzzleVel) + Crate:SetNW2Float("Tracer", BulletData.Tracer) end -function Ammo.GetDisplayData(Data) - local Crushed, HEATFiller, BoomFiller = Ammo.CrushCalc(Data.MuzzleVel, Data.FillerMass) - local SlugMV = Ammo.CalcSlugMV(Data, HEATFiller) * (Data.SlugPenMul or 1) - local MassUsed = Data.SlugMass * (1 - Crushed) - local Energy = ACF_Kinetic(Data.MuzzleVel * 39.37 + SlugMV * 39.37, MassUsed, 999999) - local FragMass = Data.CasingMass + Data.SlugMass * Crushed - local Fragments = math.max(math.floor((BoomFiller / FragMass) * ACF.HEFrag), 2) +function Ammo:GetDisplayData(Data) + local Crushed, HEATFiller, BoomFiller = self:CrushCalc(Data.MuzzleVel, Data.FillerMass) + local SlugMV = self:CalcSlugMV(Data, HEATFiller) * (Data.SlugPenMul or 1) + local MassUsed = Data.SlugMass * (1 - Crushed) + local Energy = ACF_Kinetic(Data.MuzzleVel * 39.37 + SlugMV * 39.37, MassUsed, 999999) + local FragMass = Data.CasingMass + Data.SlugMass * Crushed + local Fragments = math.max(math.floor((BoomFiller / FragMass) * ACF.HEFrag), 2) return { - Crushed = Crushed, + Crushed = Crushed, HEATFillerMass = HEATFiller, BoomFillerMass = BoomFiller, - SlugMV = SlugMV, - SlugMassUsed = MassUsed, - MaxPen = (Energy.Penetration / Data.SlugPenArea) * ACF.KEtoRHA, - TotalFragMass = FragMass, - BlastRadius = BoomFiller ^ 0.33 * 8, - Fragments = Fragments, - FragMass = FragMass / Fragments, - FragVel = (BoomFiller * ACF.HEPower * 1000 / FragMass) ^ 0.5, + SlugMV = SlugMV, + SlugMassUsed = MassUsed, + MaxPen = (Energy.Penetration / Data.SlugPenArea) * ACF.KEtoRHA, + TotalFragMass = FragMass, + BlastRadius = BoomFiller ^ 0.33 * 8, + Fragments = Fragments, + FragMass = FragMass / Fragments, + FragVel = (BoomFiller * ACF.HEPower * 1000 / FragMass) ^ 0.5, } end -function Ammo.GetCrateText(BulletData) +function Ammo:GetCrateText(BulletData) local Text = "Muzzle Velocity: %s m/s\nMax Penetration: %s mm\nBlast Radius: %s m\n", "Blast Energy: %s KJ" - local Data = Ammo.GetDisplayData(BulletData) + local Data = self:GetDisplayData(BulletData) - return Text:format(math.Round(BulletData.MuzzleVel, 2), math.floor(Data.MaxPen), math.Round(Data.BlastRadius, 2), math.floor(Data.BoomFillerMass * ACF.HEPower)) + return Text:format(math.Round(BulletData.MuzzleVel, 2), math.Round(Data.MaxPen, 2), math.Round(Data.BlastRadius, 2), math.Round(Data.BoomFillerMass * ACF.HEPower, 2)) end -function Ammo.Detonate(_, Bullet, HitPos) - local Crushed, HEATFillerMass, BoomFillerMass = Ammo.CrushCalc(Bullet.Flight:Length() * 0.0254, Bullet.FillerMass) +function Ammo:GetToolData() + local Data = Ammo.BaseClass.GetToolData(self) + Data.FillerMass = ACF.ReadNumber("FillerMass") + Data.LinerAngle = ACF.ReadNumber("LinerAngle") + + return Data +end + +function Ammo:Detonate(Bullet, HitPos) + local Crushed, HEATFillerMass, BoomFillerMass = self:CrushCalc(Bullet.Flight:Length() * 0.0254, Bullet.FillerMass) ACF_HE(HitPos - Bullet.Flight:GetNormalized() * 3, BoomFillerMass, Bullet.CasingMass + Bullet.SlugMass * Crushed, Bullet.Owner, nil, Bullet.Gun) if Crushed == 1 then return false end -- no HEAT jet to fire off, it was all converted to HE - Bullet.Detonated = true - Bullet.InitTime = ACF.CurTime - Bullet.Flight = Bullet.Flight + Bullet.Flight:GetNormalized() * Ammo.CalcSlugMV(Bullet, HEATFillerMass) * 39.37 - Bullet.FuseLength = 0.005 + 40 / (Bullet.Flight:Length() * 0.0254) - Bullet.Pos = HitPos - Bullet.DragCoef = Bullet.SlugDragCoef - Bullet.ProjMass = Bullet.SlugMass * (1 - Crushed) - Bullet.Caliber = Bullet.SlugCaliber - Bullet.PenArea = Bullet.SlugPenArea - Bullet.Ricochet = Bullet.SlugRicochet - local DeltaTime = ACF.CurTime - Bullet.LastThink + Bullet.Detonated = true + Bullet.InitTime = ACF.CurTime + Bullet.Flight = Bullet.Flight + Bullet.Flight:GetNormalized() * self:CalcSlugMV(Bullet, HEATFillerMass) * 39.37 + Bullet.FuseLength = 0.005 + 40 / (Bullet.Flight:Length() * 0.0254) + Bullet.Pos = HitPos + Bullet.DragCoef = Bullet.SlugDragCoef + Bullet.ProjMass = Bullet.SlugMass * (1 - Crushed) + Bullet.Caliber = Bullet.SlugCaliber + Bullet.PenArea = Bullet.SlugPenArea + Bullet.Ricochet = Bullet.SlugRicochet Bullet.StartTrace = Bullet.Pos - Bullet.Flight:GetNormalized() * math.min(ACF.PhysMaxVel * DeltaTime, Bullet.FlightTime * Bullet.Flight:Length()) - Bullet.NextPos = Bullet.Pos + (Bullet.Flight * ACF.Scale * DeltaTime) --Calculates the next shell position + Bullet.NextPos = Bullet.Pos + (Bullet.Flight * ACF.Scale * DeltaTime) --Calculates the next shell position return true end -function Ammo.PropImpact(Index, Bullet, Target, HitNormal, HitPos, Bone) +function Ammo:PropImpact(_, Bullet, Target, HitNormal, HitPos, Bone) if ACF_Check(Target) then + local Speed = Bullet.Flight:Length() / ACF.Scale + if Bullet.Detonated then Bullet.NotFirstPen = true - local Speed = Bullet.Flight:Length() / ACF.Scale local Energy = ACF_Kinetic(Speed, Bullet.ProjMass, 999999) local HitRes = ACF_RoundImpact(Bullet, Speed, Energy, Target, HitPos, HitNormal, Bone) @@ -235,14 +209,13 @@ function Ammo.PropImpact(Index, Bullet, Target, HitNormal, HitPos, Bone) return false end else - local Speed = Bullet.Flight:Length() / ACF.Scale local Energy = ACF_Kinetic(Speed, Bullet.ProjMass - Bullet.FillerMass, Bullet.LimitVel) local HitRes = ACF_RoundImpact(Bullet, Speed, Energy, Target, HitPos, HitNormal, Bone) if HitRes.Ricochet then return "Ricochet" else - if Ammo.Detonate(Index, Bullet, HitPos, HitNormal) then + if self:Detonate(Bullet, HitPos, HitNormal) then return "Penetrated" else return false @@ -258,9 +231,9 @@ function Ammo.PropImpact(Index, Bullet, Target, HitNormal, HitPos, Bone) return false end -function Ammo.WorldImpact(Index, Bullet, HitPos, HitNormal) +function Ammo:WorldImpact(_, Bullet, HitPos, HitNormal) if not Bullet.Detonated then - if Ammo.Detonate(Index, Bullet, HitPos, HitNormal) then + if self:Detonate(Bullet, HitPos, HitNormal) then return "Penetrated" else return false @@ -277,7 +250,7 @@ function Ammo.WorldImpact(Index, Bullet, HitPos, HitNormal) end end -function Ammo.PenetrationEffect(Effect, Bullet) +function Ammo:PenetrationEffect(Effect, Bullet) if Bullet.Detonated then local Data = EffectData() Data:SetOrigin(Bullet.SimPos) @@ -289,7 +262,7 @@ function Ammo.PenetrationEffect(Effect, Bullet) util.Effect("ACF_Penetration", Data) else - local _, _, BoomFillerMass = Ammo.CrushCalc(Bullet.SimFlight:Length() * 0.0254, Bullet.FillerMass) + local _, _, BoomFillerMass = self:CrushCalc(Bullet.SimFlight:Length() * 0.0254, Bullet.FillerMass) local Data = EffectData() Data:SetOrigin(Bullet.SimPos) Data:SetNormal(Bullet.SimFlight:GetNormalized()) @@ -303,7 +276,7 @@ function Ammo.PenetrationEffect(Effect, Bullet) end end -function Ammo.RicochetEffect(_, Bullet) +function Ammo:RicochetEffect(_, Bullet) local Detonated = Bullet.Detonated local Effect = EffectData() Effect:SetOrigin(Bullet.SimPos) @@ -316,66 +289,119 @@ function Ammo.RicochetEffect(_, Bullet) util.Effect("ACF_Ricochet", Effect) end -function Ammo.CreateMenu(Panel, Table) - acfmenupanel:AmmoSelect(Ammo.Blacklist) - - acfmenupanel:CPanelText("Desc", "") --Description (Name, Desc) - acfmenupanel:CPanelText("LengthDisplay", "") --Total round length (Name, Desc) - acfmenupanel:AmmoSlider("PropLength", 0, 0, 1000, 3, "Propellant Length", "") - acfmenupanel:AmmoSlider("ProjLength", 0, 0, 1000, 3, "Projectile Length", "") - acfmenupanel:AmmoSlider("ConeAng", 0, 0, 1000, 3, "HEAT Cone Angle", "") - acfmenupanel:AmmoSlider("FillerVol", 0, 0, 1000, 3, "Total HEAT Warhead volume", "") - acfmenupanel:AmmoCheckbox("Tracer", "Tracer", "") --Tracer checkbox (Name, Title, Desc) - acfmenupanel:CPanelText("VelocityDisplay", "") --Proj muzzle velocity (Name, Desc) - acfmenupanel:CPanelText("BlastDisplay", "") --HE Blast data (Name, Desc) - acfmenupanel:CPanelText("FragDisplay", "") --HE Fragmentation data (Name, Desc) - acfmenupanel:CPanelText("SlugDisplay", "") --HEAT Slug data (Name, Desc) - - Ammo.UpdateMenu(Panel, Table) -end - -function Ammo.UpdateMenu(Panel) - local PlayerData = { - Id = acfmenupanel.AmmoData.Data.id, --AmmoSelect GUI - Type = "HEAT", --Hardcoded, match ACFRoundTypes table index - PropLength = acfmenupanel.AmmoData.PropLength, --PropLength slider - ProjLength = acfmenupanel.AmmoData.ProjLength, --ProjLength slider - Data5 = acfmenupanel.AmmoData.FillerVol, - Data6 = acfmenupanel.AmmoData.ConeAng, - Data10 = acfmenupanel.AmmoData.Tracer and 1 or 0, - } - - local Data = Ammo.Convert(Panel, PlayerData) - - RunConsoleCommand("acfmenu_data1", acfmenupanel.AmmoData.Data.id) - RunConsoleCommand("acfmenu_data2", PlayerData.Type) - RunConsoleCommand("acfmenu_data3", Data.PropLength) --For Gun ammo, Data3 should always be Propellant - RunConsoleCommand("acfmenu_data4", Data.ProjLength) - RunConsoleCommand("acfmenu_data5", Data.FillerVol) - RunConsoleCommand("acfmenu_data6", Data.ConeAng) - RunConsoleCommand("acfmenu_data10", Data.Tracer) - - acfmenupanel:AmmoSlider("PropLength", Data.PropLength, Data.MinPropLength, Data.MaxTotalLength, 3, "Propellant Length", "Propellant Mass : " .. (math.floor(Data.PropMass * 1000)) .. " g") --Propellant Length Slider (Name, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("ProjLength", Data.ProjLength, Data.MinProjLength, Data.MaxTotalLength, 3, "Projectile Length", "Projectile Mass : " .. (math.floor(Data.ProjMass * 1000)) .. " g") --Projectile Length Slider (Name, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("ConeAng", Data.ConeAng, Data.MinConeAng, Data.MaxConeAng, 0, "Crush Cone Angle", "") --HE Filler Slider (Name, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("FillerVol", Data.FillerVol, Data.MinFillerVol, Data.MaxFillerVol, 3, "HE Filler Volume", "HE Filler Mass : " .. (math.floor(Data.FillerMass * 1000)) .. " g") --HE Filler Slider (Name, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoCheckbox("Tracer", "Tracer : " .. (math.floor(Data.Tracer * 10) / 10) .. "cm\n", "") --Tracer checkbox (Name, Title, Desc) - acfmenupanel:CPanelText("Desc", Ammo.Description) --Description (Name, Desc) - acfmenupanel:CPanelText("LengthDisplay", "Round Length : " .. (math.floor((Data.PropLength + Data.ProjLength + Data.Tracer) * 100) / 100) .. "/" .. Data.MaxTotalLength .. " cm") --Total round length (Name, Desc) - acfmenupanel:CPanelText("VelocityDisplay", "Muzzle Velocity : " .. math.floor(Data.MuzzleVel * ACF.Scale) .. " m/s") --Proj muzzle velocity (Name, Desc) - acfmenupanel:CPanelText("BlastDisplay", "Blast Radius : " .. (math.floor(Data.BlastRadius * 100) / 100) .. " m") --Proj muzzle velocity (Name, Desc) - acfmenupanel:CPanelText("FragDisplay", "Fragments : " .. Data.Fragments .. "\n Average Fragment Weight : " .. (math.floor(Data.FragMass * 10000) / 10) .. " g \n Average Fragment Velocity : " .. math.floor(Data.FragVel) .. " m/s") --Proj muzzle penetration (Name, Desc) - - local R1V, R1P = ACF_PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 300) - R1P = (ACF_Kinetic((R1V + Data.SlugMV) * 39.37, Data.SlugMassUsed, 999999).Penetration / Data.SlugPenArea) * ACF.KEtoRHA - local R2V, R2P = ACF_PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 800) - R2P = (ACF_Kinetic((R2V + Data.SlugMV) * 39.37, Data.SlugMassUsed, 999999).Penetration / Data.SlugPenArea) * ACF.KEtoRHA - - acfmenupanel:CPanelText("SlugDisplay", "Penetrator Mass : " .. (math.floor(Data.SlugMassUsed * 10000) / 10) .. " g \n Penetrator Caliber : " .. (math.floor(Data.SlugCaliber * 100) / 10) .. " mm \n Penetrator Velocity : " .. math.floor(Data.MuzzleVel + Data.SlugMV) .. " m/s \n Penetrator Maximum Penetration : " .. math.floor(Data.MaxPen) .. " mm RHA\n\n300m pen: " .. math.Round(R1P, 0) .. "mm @ " .. math.Round(R1V, 0) .. " m\\s\n800m pen: " .. math.Round(R2P, 0) .. "mm @ " .. math.Round(R2V, 0) .. " m\\s\n\nThe range data is an approximation and may not be entirely accurate.") --Proj muzzle penetration (Name, Desc) -end - -function Ammo.MenuAction(Menu) - Menu:AddParagraph("Testing HEAT menu.") +function Ammo:MenuAction(Menu, ToolData, Data) + local LinerAngle = Menu:AddSlider("Liner Angle", Data.MinConeAng, Data.MaxConeAng, 2) + LinerAngle:SetDataVar("LinerAngle", "OnValueChanged") + LinerAngle:TrackDataVar("Projectile") + LinerAngle:SetValueFunction(function(Panel) + ToolData.LinerAngle = math.Round(ACF.ReadNumber("LinerAngle"), 2) + + self:UpdateRoundData(ToolData, Data) + + Panel:SetMax(Data.MaxConeAng) + Panel:SetValue(Data.ConeAng) + + return Data.ConeAng + end) + + local FillerMass = Menu:AddSlider("Filler Volume", 0, Data.MaxFillerVol, 2) + FillerMass:SetDataVar("FillerMass", "OnValueChanged") + FillerMass:TrackDataVar("Projectile") + FillerMass:TrackDataVar("LinerAngle") + FillerMass:SetValueFunction(function(Panel) + ToolData.FillerMass = math.Round(ACF.ReadNumber("FillerMass"), 2) + + self:UpdateRoundData(ToolData, Data) + + Panel:SetMax(Data.MaxFillerVol) + Panel:SetValue(Data.FillerVol) + + return Data.FillerVol + end) + + local Tracer = Menu:AddCheckBox("Tracer") + Tracer:SetDataVar("Tracer", "OnChange") + Tracer:SetValueFunction(function(Panel) + ToolData.Tracer = ACF.ReadBool("Tracer") + + self:UpdateRoundData(ToolData, Data) + + ACF.WriteValue("Projectile", Data.ProjLength) + ACF.WriteValue("Propellant", Data.PropLength) + + Panel:SetText("Tracer : " .. Data.Tracer .. " cm") + Panel:SetValue(ToolData.Tracer) + + return ToolData.Tracer + end) + + local RoundStats = Menu:AddLabel() + RoundStats:TrackDataVar("Projectile", "SetText") + RoundStats:TrackDataVar("Propellant") + RoundStats:TrackDataVar("FillerMass") + RoundStats:TrackDataVar("LinerAngle") + RoundStats:SetValueFunction(function() + self:UpdateRoundData(ToolData, Data) + + local Text = "Muzzle Velocity : %s m/s\nProjectile Mass : %s\nPropellant Mass : %s\nExplosive Mass : %s" + local MuzzleVel = math.Round(Data.MuzzleVel * ACF.Scale, 2) + local ProjMass = ACF.GetProperMass(Data.ProjMass) + local PropMass = ACF.GetProperMass(Data.PropMass) + local Filler = ACF.GetProperMass(Data.FillerMass) + + return Text:format(MuzzleVel, ProjMass, PropMass, Filler) + end) + + local FillerStats = Menu:AddLabel() + FillerStats:TrackDataVar("FillerMass", "SetText") + FillerStats:TrackDataVar("LinerAngle") + FillerStats:SetValueFunction(function() + self:UpdateRoundData(ToolData, Data) + + local Text = "Blast Radius : %s m\nFragments : %s\nFragment Mass : %s\nFragment Velocity : %s m/s" + local Blast = math.Round(Data.BlastRadius, 2) + local FragMass = ACF.GetProperMass(Data.FragMass) + local FragVel = math.Round(Data.FragVel, 2) + + return Text:format(Blast, Data.Fragments, FragMass, FragVel) + end) + + local Penetrator = Menu:AddLabel() + Penetrator:TrackDataVar("Projectile", "SetText") + Penetrator:TrackDataVar("Propellant") + Penetrator:TrackDataVar("FillerMass") + Penetrator:TrackDataVar("LinerAngle") + Penetrator:SetValueFunction(function() + self:UpdateRoundData(ToolData, Data) + + local Text = "Penetrator Caliber : %s mm\nPenetrator Mass : %s\nPenetrator Velocity : %s m/s" + local Caliber = math.Round(Data.SlugCaliber * 10, 2) + local Mass = ACF.GetProperMass(Data.SlugMassUsed) + local Velocity = math.Round(Data.MuzzleVel + Data.SlugMV, 2) + + return Text:format(Caliber, Mass, Velocity) + end) + + local PenStats = Menu:AddLabel() + PenStats:TrackDataVar("Projectile", "SetText") + PenStats:TrackDataVar("Propellant") + PenStats:TrackDataVar("FillerMass") + PenStats:TrackDataVar("LinerAngle") + PenStats:SetValueFunction(function() + self:UpdateRoundData(ToolData, Data) + + local Text = "Penetration : %s mm RHA\nAt 300m : %s mm RHA @ %s m/s\nAt 800m : %s mm RHA @ %s m/s" + local MaxPen = math.Round(Data.MaxPen, 2) + local R1V, R1P = ACF.PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 300) + local R2V, R2P = ACF.PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 800) + + R1P = math.Round((ACF_Kinetic((R1V + Data.SlugMV) * 39.37, Data.SlugMassUsed, 999999).Penetration / Data.SlugPenArea) * ACF.KEtoRHA, 2) + R2P = math.Round((ACF_Kinetic((R2V + Data.SlugMV) * 39.37, Data.SlugMassUsed, 999999).Penetration / Data.SlugPenArea) * ACF.KEtoRHA, 2) + + return Text:format(MaxPen, R1P, R1V, R2P, R2V) + end) + + Menu:AddLabel("Note: The penetration range data is an approximation and may not be entirely accurate.") end ACF.RegisterAmmoDecal("HEAT", "damage/heat_pen", "damage/heat_rico", function(Caliber) return Caliber * 0.1667 end) diff --git a/lua/acf/shared/ammo_types/hp.lua b/lua/acf/shared/ammo_types/hp.lua index a0a08fe4e..ea55506cf 100644 --- a/lua/acf/shared/ammo_types/hp.lua +++ b/lua/acf/shared/ammo_types/hp.lua @@ -3,143 +3,168 @@ local Ammo = ACF.RegisterAmmoType("HP", "AP") function Ammo:OnLoaded() Ammo.BaseClass.OnLoaded(self) - self.Name = "Hollow Point" - self.Description = "A solid shell with a soft point, meant to flatten against armor." + self.Name = "Hollow Point" + self.Description = "A round with a hollow cavity, meant to flatten against surfaces on impact." end -function Ammo.Convert(_, PlayerData) - local Data = {} - local ServerData = {} - local GUIData = {} +function Ammo:UpdateRoundData(ToolData, Data, GUIData) + GUIData = GUIData or Data - if not PlayerData.PropLength then - PlayerData.PropLength = 0 - end + ACF.UpdateRoundSpecs(ToolData, Data, GUIData) - if not PlayerData.ProjLength then - PlayerData.ProjLength = 0 - end + local ProjMass = math.max(GUIData.ProjVolume * 0.5, 0) * 0.0079 --(Volume of the projectile as a cylinder - Volume of the cavity) * density of steel + local MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, ProjMass) + local Energy = ACF_Kinetic(MuzzleVel * 39.37, ProjMass, Data.LimitVel) + local MaxVol = ACF.RoundShellCapacity(Energy.Momentum, Data.FrArea, Data.Caliber, Data.ProjLength) + local MaxCavity = math.min(GUIData.ProjVolume, MaxVol) + local HollowCavity = math.Clamp(ToolData.HollowCavity, GUIData.MinCavVol, MaxCavity) + local ExpRatio = HollowCavity / GUIData.ProjVolume - PlayerData.Data5 = math.max(PlayerData.Data5 or 0, 0) + GUIData.MaxCavVol = MaxCavity - if not PlayerData.Data10 then - PlayerData.Data10 = 0 - end + Data.CavVol = HollowCavity + Data.ProjMass = (Data.FrArea * Data.ProjLength - HollowCavity) * 0.0079 --Volume of the projectile as a cylinder * fraction missing due to hollow point (Data5) * density of steel + Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass) + Data.ShovePower = 0.2 + ExpRatio * 0.5 + Data.ExpCaliber = Data.Caliber * 0.1 + ExpRatio * Data.ProjLength + Data.PenArea = (3.1416 * Data.ExpCaliber * 0.5) ^ 2 ^ ACF.PenAreaMod + Data.DragCoef = Data.FrArea * 0.0001 / Data.ProjMass - PlayerData, Data, ServerData, GUIData = ACF_RoundBaseGunpowder(PlayerData, Data, ServerData, GUIData) + for K, V in pairs(self:GetDisplayData(Data)) do + GUIData[K] = V + end +end - Data.ProjMass = math.max(GUIData.ProjVolume * 0.5, 0) * 7.9 / 1000 --(Volume of the projectile as a cylinder - Volume of the cavity) * density of steel - Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass, Data.Caliber) +function Ammo:BaseConvert(_, ToolData) + if not ToolData.Projectile then ToolData.Projectile = 0 end + if not ToolData.Propellant then ToolData.Propellant = 0 end + if not ToolData.HollowCavity then ToolData.HollowCavity = 0 end - local Energy = ACF_Kinetic(Data.MuzzleVel * 39.37, Data.ProjMass, Data.LimitVel) - local MaxVol = ACF_RoundShellCapacity(Energy.Momentum, Data.FrArea, Data.Caliber, Data.ProjLength) + local Data, GUIData = ACF.RoundBaseGunpowder(ToolData, {}) GUIData.MinCavVol = 0 - GUIData.MaxCavVol = math.min(GUIData.ProjVolume, MaxVol) - Data.CavVol = math.Clamp(PlayerData.Data5, GUIData.MinCavVol, GUIData.MaxCavVol) - Data.ProjMass = ((Data.FrArea * Data.ProjLength) - Data.CavVol) * 7.9 / 1000 --Volume of the projectile as a cylinder * fraction missing due to hollow point (Data5) * density of steel - Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass, Data.Caliber) + Data.LimitVel = 400 --Most efficient penetration speed in m/s + Data.KETransfert = 0.1 --Kinetic energy transfert to the target for movement purposes + Data.Ricochet = 90 --Base ricochet angle - local ExpRatio = (Data.CavVol / GUIData.ProjVolume) + self:UpdateRoundData(ToolData, Data, GUIData) - Data.ShovePower = 0.2 + ExpRatio / 2 - Data.ExpCaliber = Data.Caliber + ExpRatio * Data.ProjLength - Data.PenArea = (3.1416 * Data.ExpCaliber / 2) ^ 2 ^ ACF.PenAreaMod - Data.DragCoef = ((Data.FrArea / 10000) / Data.ProjMass) - Data.LimitVel = 400 --Most efficient penetration speed in m/s - Data.KETransfert = 0.1 --Kinetic energy transfert to the target for movement purposes - Data.Ricochet = 90 --Base ricochet angle - Data.BoomPower = Data.PropMass + return Data, GUIData +end - --Only the crates need this part - if SERVER then - ServerData.Id = PlayerData.Id - ServerData.Type = PlayerData.Type +function Ammo:Network(Crate, BulletData) + Crate:SetNW2String("AmmoType", "HP") + Crate:SetNW2String("AmmoID", BulletData.Id) + Crate:SetNW2Float("Caliber", BulletData.Caliber) + Crate:SetNW2Float("ProjMass", BulletData.ProjMass) + Crate:SetNW2Float("PropMass", BulletData.PropMass) + Crate:SetNW2Float("ExpCaliber", BulletData.ExpCaliber) + Crate:SetNW2Float("DragCoef", BulletData.DragCoef) + Crate:SetNW2Float("MuzzleVel", BulletData.MuzzleVel) + Crate:SetNW2Float("Tracer", BulletData.Tracer) +end - return table.Merge(Data, ServerData) - end +function Ammo:GetDisplayData(BulletData) + local Data = Ammo.BaseClass.GetDisplayData(self, BulletData) + local Energy = ACF_Kinetic(BulletData.MuzzleVel * 39.37, BulletData.ProjMass, BulletData.LimitVel) - --Only tthe GUI needs this part - if CLIENT then - GUIData = table.Merge(GUIData, Ammo.GetDisplayData(Data)) + Data.MaxKETransfert = Energy.Kinetic * BulletData.ShovePower - return table.Merge(Data, GUIData) - end + return Data end -function Ammo.Network(Crate, BulletData) - Crate:SetNWString("AmmoType", "HP") - Crate:SetNWString("AmmoID", BulletData.Id) - Crate:SetNWFloat("Caliber", BulletData.Caliber) - Crate:SetNWFloat("ProjMass", BulletData.ProjMass) - Crate:SetNWFloat("PropMass", BulletData.PropMass) - Crate:SetNWFloat("ExpCaliber", BulletData.ExpCaliber) - Crate:SetNWFloat("DragCoef", BulletData.DragCoef) - Crate:SetNWFloat("MuzzleVel", BulletData.MuzzleVel) - Crate:SetNWFloat("Tracer", BulletData.Tracer) +function Ammo:GetCrateText(BulletData) + local BaseText = Ammo.BaseClass.GetCrateText(self, BulletData) + local Data = self:GetDisplayData(BulletData) + local Text = BaseText .. "\nExpanded Caliber: %s mm\nImparted Energy: %s KJ" + + return Text:format(math.Round(BulletData.ExpCaliber * 10, 2), math.Round(Data.MaxKETransfert, 2)) end -function Ammo.GetCrateText(BulletData) - local Data = Ammo.GetDisplayData(BulletData) - local BaseText = Ammo.BaseClass.GetCrateText(BulletData) - local Text = BaseText .. "\nExpanded Caliber: %s mm\nImparted Energy: %s KJ" +function Ammo:GetToolData() + local Data = Ammo.BaseClass.GetToolData(self) + Data.HollowCavity = ACF.ReadNumber("HollowCavity") - return Text:format(math.floor(BulletData.ExpCaliber * 10), math.floor(Data.MaxKETransfert)) + return Data end -function Ammo.CreateMenu(Panel) - acfmenupanel:AmmoSelect(Ammo.Blacklist) +function Ammo:MenuAction(Menu, ToolData, Data) + local HollowCavity = Menu:AddSlider("Cavity Volume", Data.MinCavVol, Data.MaxCavVol, 2) + HollowCavity:SetDataVar("HollowCavity", "OnValueChanged") + HollowCavity:TrackDataVar("Projectile") + HollowCavity:SetValueFunction(function(Panel) + ToolData.HollowCavity = math.Round(ACF.ReadNumber("HollowCavity"), 2) - acfmenupanel:CPanelText("Desc", "") --Description (Name, Desc) - acfmenupanel:CPanelText("LengthDisplay", "") --Total round length (Name, Desc) - acfmenupanel:AmmoSlider("PropLength", 0, 0, 1000, 3, "Propellant Length", "") --Propellant Length Slider (Name, Value, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("ProjLength", 0, 0, 1000, 3, "Projectile Length", "") --Projectile Length Slider (Name, Value, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("CavVol", 0, 0, 1000, 2, "Hollow Point Length", "") --Hollow Point Cavity Slider (Name, Value, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoCheckbox("Tracer", "Tracer", "") --Tracer checkbox (Name, Title, Desc) - acfmenupanel:CPanelText("VelocityDisplay", "") --Proj muzzle velocity (Name, Desc) - acfmenupanel:CPanelText("KEDisplay", "") --Proj muzzle KE (Name, Desc) - acfmenupanel:CPanelText("PenetrationDisplay", "") --Proj muzzle penetration (Name, Desc) + self:UpdateRoundData(ToolData, Data) - Ammo.UpdateMenu(Panel) -end + Panel:SetMax(Data.MaxCavVol) + Panel:SetValue(Data.CavVol) -function Ammo.CreateMenu(Panel) - local PlayerData = { - Id = acfmenupanel.AmmoData.Data.id, --AmmoSelect GUI - Type = "HP", --Hardcoded, match ACFRoundTypes table index - PropLength = acfmenupanel.AmmoData.PropLength, --PropLength slider - ProjLength = acfmenupanel.AmmoData.ProjLength, --ProjLength slider - Data5 = acfmenupanel.AmmoData.CavVol, - Data10 = acfmenupanel.AmmoData.Tracer and 1 or 0, - } - - local Data = Ammo.Convert(Panel, PlayerData) - - RunConsoleCommand("acfmenu_data1", acfmenupanel.AmmoData.Data.id) - RunConsoleCommand("acfmenu_data2", PlayerData.Type) - RunConsoleCommand("acfmenu_data3", Data.PropLength) --For Gun ammo, Data3 should always be Propellant - RunConsoleCommand("acfmenu_data4", Data.ProjLength) --And Data4 total round mass - RunConsoleCommand("acfmenu_data5", Data.CavVol) - RunConsoleCommand("acfmenu_data10", Data.Tracer) - - acfmenupanel:AmmoSlider("PropLength", Data.PropLength, Data.MinPropLength, Data.MaxTotalLength, 3, "Propellant Length", "Propellant Mass : " .. (math.floor(Data.PropMass * 1000)) .. " g") --Propellant Length Slider (Name, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("ProjLength", Data.ProjLength, Data.MinProjLength, Data.MaxTotalLength, 3, "Projectile Length", "Projectile Mass : " .. (math.floor(Data.ProjMass * 1000)) .. " g") --Projectile Length Slider (Name, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("CavVol", Data.CavVol, Data.MinCavVol, Data.MaxCavVol, 2, "Hollow Point cavity Volume", "Expanded caliber : " .. (math.floor(Data.ExpCaliber * 10)) .. " mm") --Hollow Point Cavity Slider (Name, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoCheckbox("Tracer", "Tracer : " .. (math.floor(Data.Tracer * 10) / 10) .. "cm\n", "") --Tracer checkbox (Name, Title, Desc) - acfmenupanel:CPanelText("Desc", Ammo.Description) --Description (Name, Desc) - acfmenupanel:CPanelText("LengthDisplay", "Round Length : " .. (math.floor((Data.PropLength + Data.ProjLength + Data.Tracer) * 100) / 100) .. "/" .. Data.MaxTotalLength .. " cm") --Total round length (Name, Desc) - acfmenupanel:CPanelText("VelocityDisplay", "Muzzle Velocity : " .. math.floor(Data.MuzzleVel * ACF.Scale) .. " m/s") --Proj muzzle velocity (Name, Desc) - acfmenupanel:CPanelText("KEDisplay", "Kinetic Energy Transfered : " .. math.floor(Data.MaxKETransfert) .. " KJ") --Proj muzzle KE (Name, Desc) - - local R1V, R1P = ACF_PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 300) - local R2V, R2P = ACF_PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 800) - - acfmenupanel:CPanelText("PenetrationDisplay", "Maximum Penetration : " .. math.floor(Data.MaxPen) .. " mm RHA\n\n300m pen: " .. math.Round(R1P, 0) .. "mm @ " .. math.Round(R1V, 0) .. " m\\s\n800m pen: " .. math.Round(R2P, 0) .. "mm @ " .. math.Round(R2V, 0) .. " m\\s\n\nThe range data is an approximation and may not be entirely accurate.") --Proj muzzle penetration (Name, Desc) -end + return Data.CavVol + end) + + local Tracer = Menu:AddCheckBox("Tracer") + Tracer:SetDataVar("Tracer", "OnChange") + Tracer:SetValueFunction(function(Panel) + ToolData.Tracer = ACF.ReadBool("Tracer") + + self:UpdateRoundData(ToolData, Data) + + ACF.WriteValue("Projectile", Data.ProjLength) + ACF.WriteValue("Propellant", Data.PropLength) + + Panel:SetText("Tracer : " .. Data.Tracer .. " cm") + Panel:SetValue(ToolData.Tracer) + + return ToolData.Tracer + end) + + local RoundStats = Menu:AddLabel() + RoundStats:TrackDataVar("Projectile", "SetText") + RoundStats:TrackDataVar("Propellant") + RoundStats:TrackDataVar("HollowCavity") + RoundStats:SetValueFunction(function() + self:UpdateRoundData(ToolData, Data) + + local Text = "Muzzle Velocity : %s m/s\nProjectile Mass : %s\nPropellant Mass : %s" + local MuzzleVel = math.Round(Data.MuzzleVel * ACF.Scale, 2) + local ProjMass = ACF.GetProperMass(Data.ProjMass) + local PropMass = ACF.GetProperMass(Data.PropMass) + + return Text:format(MuzzleVel, ProjMass, PropMass) + end) + + local HollowStats = Menu:AddLabel() + HollowStats:TrackDataVar("Projectile", "SetText") + HollowStats:TrackDataVar("Propellant") + HollowStats:TrackDataVar("HollowCavity") + HollowStats:SetValueFunction(function() + self:UpdateRoundData(ToolData, Data) + + local Text = "Expanded Caliber : %s mm\nTransfered Energy : %s KJ" + local Caliber = math.Round(Data.ExpCaliber * 10, 2) + local Energy = math.Round(Data.MaxKETransfert, 2) + + return Text:format(Caliber, Energy) + end) + + local PenStats = Menu:AddLabel() + PenStats:TrackDataVar("Projectile", "SetText") + PenStats:TrackDataVar("Propellant") + PenStats:TrackDataVar("HollowCavity") + PenStats:SetValueFunction(function() + self:UpdateRoundData(ToolData, Data) + + local Text = "Penetration : %s mm RHA\nAt 300m : %s mm RHA @ %s m/s\nAt 800m : %s mm RHA @ %s m/s" + local MaxPen = math.Round(Data.MaxPen, 2) + local R1V, R1P = ACF.PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 300) + local R2V, R2P = ACF.PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 800) + + return Text:format(MaxPen, R1P, R1V, R2P, R2V) + end) -function Ammo.MenuAction(Menu) - Menu:AddParagraph("Testing HP menu.") + Menu:AddLabel("Note: The penetration range data is an approximation and may not be entirely accurate.") end ACF.RegisterAmmoDecal("HP", "damage/ap_pen", "damage/ap_rico") diff --git a/lua/acf/shared/ammo_types/refill.lua b/lua/acf/shared/ammo_types/refill.lua index fda435cbf..9ee7f8f2a 100644 --- a/lua/acf/shared/ammo_types/refill.lua +++ b/lua/acf/shared/ammo_types/refill.lua @@ -1,64 +1,57 @@ local Ammo = ACF.RegisterAmmoType("Refill", "AP") function Ammo:OnLoaded() - self.Name = "Refill" - self.Description = "Ammunition refilling station." - self.Unlistable = true - self.Blacklist = {} + self.Name = "Refill" + self.Description = "Provides supplies to other ammo crates." + self.Blacklist = {} + self.SupressDefaultMenu = true end -function Ammo.Convert(_, PlayerData) +function Ammo:BaseConvert(_, ToolData) + local Class = ACF.Classes.Weapons[ToolData.WeaponClass] + local Weapon = Class and Class.Items[ToolData.Weapon] + return { - Id = PlayerData.Id, - Type = PlayerData.Type, - Caliber = ACF.Weapons.Guns[PlayerData.Id].caliber, - ProjMass = 6 * 7.9 / 100, --Volume of the projectile as a cylinder * streamline factor (Data5) * density of steel - PropMass = 6 * ACF.PDensity / 1000, --Volume of the case as a cylinder * Powder density converted from g to kg - FillerMass = 0, - DragCoef = 0, - Tracer = 0, - MuzzleVel = 0, - RoundVolume = 36, + Id = ToolData.Weapon, + Type = ToolData.Ammo, + Caliber = Weapon and Weapon.Caliber or 12.7, + ProjMass = 6 * 0.079, --Volume of the projectile as a cylinder * streamline factor (Data5) * density of steel + PropMass = 6 * ACF.PDensity * 0.001, --Volume of the case as a cylinder * Powder density converted from g to kg + FillerMass = 0, + DragCoef = 0, + Tracer = 0, + MuzzleVel = 0, + RoundVolume = 36, } end -function Ammo.Network(Crate, BulletData) - Crate:SetNWString("AmmoType", "Refill") - Crate:SetNWString("AmmoID", BulletData.Id) - Crate:SetNWFloat("Caliber", BulletData.Caliber) - Crate:SetNWFloat("ProjMass", BulletData.ProjMass) - Crate:SetNWFloat("FillerMass", BulletData.FillerMass) - Crate:SetNWFloat("PropMass", BulletData.PropMass) - Crate:SetNWFloat("DragCoef", BulletData.DragCoef) - Crate:SetNWFloat("MuzzleVel", BulletData.MuzzleVel) - Crate:SetNWFloat("Tracer", BulletData.Tracer) +function Ammo:Network(Crate, BulletData) + Crate:SetNW2String("AmmoType", "Refill") + Crate:SetNW2String("AmmoID", BulletData.Id) + Crate:SetNW2Float("Caliber", BulletData.Caliber) + Crate:SetNW2Float("ProjMass", BulletData.ProjMass) + Crate:SetNW2Float("FillerMass", BulletData.FillerMass) + Crate:SetNW2Float("PropMass", BulletData.PropMass) + Crate:SetNW2Float("DragCoef", BulletData.DragCoef) + Crate:SetNW2Float("MuzzleVel", BulletData.MuzzleVel) + Crate:SetNW2Float("Tracer", BulletData.Tracer) end -function Ammo.GetDisplayData() +function Ammo:GetDisplayData() return {} end -function Ammo.GetCrateText() +function Ammo:GetCrateText() return "" end -function Ammo.CreateMenu(Panel, Table) - acfmenupanel:AmmoSelect() - - acfmenupanel:CPanelText("Desc", "") --Description (Name, Desc) - - Ammo.UpdateMenu(Panel, Table) -end - -function Ammo.UpdateMenu() - RunConsoleCommand("acfmenu_data1", acfmenupanel.CData.AmmoId or "12.7mmMG") - RunConsoleCommand("acfmenu_data2", "Refill") - - acfmenupanel:CPanelText("Desc", Ammo.Description) - - acfmenupanel.CustomDisplay:PerformLayout() +function Ammo:GetToolData() + return { + Ammo = ACF.ReadString("Ammo"), + Weapon = ACF.ReadString("Weapon"), + WeaponClass = ACF.ReadString("WeaponClass"), + } end -function Ammo.MenuAction(Menu) - Menu:AddParagraph("Testing Refill menu.") +function Ammo:MenuAction() end diff --git a/lua/acf/shared/ammo_types/smoke.lua b/lua/acf/shared/ammo_types/smoke.lua index 4c72fc069..3a4a911bb 100644 --- a/lua/acf/shared/ammo_types/smoke.lua +++ b/lua/acf/shared/ammo_types/smoke.lua @@ -1,131 +1,117 @@ local Ammo = ACF.RegisterAmmoType("SM", "AP") function Ammo:OnLoaded() - self.Name = "Smoke" + self.Name = "Smoke" self.Description = "A shell filled white phosporous, detonating on impact. Smoke filler produces a long lasting cloud but takes a while to be effective, whereas WP filler quickly creates a cloud that also dissipates quickly." self.Blacklist = { - MG = true, C = true, - GL = true, - HMG = true, - AL = true, AC = true, - RAC = true, + AL = true, + GL = true, + MG = true, SA = true, SC = true, + HMG = true, + RAC = true, } end -function Ammo.Convert(_, PlayerData) - local Data = {} - local ServerData = {} - local GUIData = {} +function Ammo:UpdateRoundData(ToolData, Data, GUIData) + GUIData = GUIData or Data - if not PlayerData.PropLength then - PlayerData.PropLength = 0 - end + ACF.UpdateRoundSpecs(ToolData, Data, GUIData) - if not PlayerData.ProjLength then - PlayerData.ProjLength = 0 - end + Data.FillerPriority = Data.FillerPriority or "Smoke" - PlayerData.Data5 = math.max(PlayerData.Data5 or 0, 0) - PlayerData.Data6 = math.max(PlayerData.Data6 or 0, 0) - PlayerData.Data7 = tonumber(PlayerData.Data7) or 0 --catching some possible errors with string data in legacy dupes + -- Volume of the projectile as a cylinder - Volume of the filler * density of steel + Volume of the filler * density of TNT + local ProjMass = math.max(GUIData.ProjVolume - ToolData.SmokeFiller, 0) * 0.0079 + math.min(ToolData.SmokeFiller, GUIData.ProjVolume) * ACF.HEDensity * 0.0005 + local MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, ProjMass) + local Energy = ACF_Kinetic(MuzzleVel * 39.37, ProjMass, Data.LimitVel) + local MaxCapacity = ACF.RoundShellCapacity(Energy.Momentum, Data.FrArea, Data.Caliber, Data.ProjLength) + local MaxVolume = math.Round(math.min(GUIData.ProjVolume, MaxCapacity), 2) + local SmokeFiller = math.Clamp(ToolData.SmokeFiller, GUIData.MinFillerVol, MaxVolume) + local WPFiller = math.Clamp(ToolData.WPFiller, GUIData.MinFillerVol, MaxVolume) - if not PlayerData.Data10 then - PlayerData.Data10 = 0 + if Data.FillerPriority == "Smoke" then + WPFiller = math.Clamp(WPFiller, 0, MaxVolume - SmokeFiller) + elseif Data.FillerPriority == "WP" then + SmokeFiller = math.Clamp(SmokeFiller, 0, MaxVolume - WPFiller) end - PlayerData, Data, ServerData, GUIData = ACF_RoundBaseGunpowder(PlayerData, Data, ServerData, GUIData) - - Data.ProjMass = math.max(GUIData.ProjVolume - PlayerData.Data5, 0) * 7.9 / 1000 + math.min(PlayerData.Data5, GUIData.ProjVolume) * ACF.HEDensity / 2000 --Volume of the projectile as a cylinder - Volume of the filler * density of steel + Volume of the filler * density of TNT - Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass, Data.Caliber) + GUIData.MaxFillerVol = MaxVolume + GUIData.FillerVol = math.Round(SmokeFiller, 2) + GUIData.WPVol = math.Round(WPFiller, 2) - local Energy = ACF_Kinetic(Data.MuzzleVel * 39.37, Data.ProjMass, Data.LimitVel) - local MaxVol = ACF_RoundShellCapacity(Energy.Momentum, Data.FrArea, Data.Caliber, Data.ProjLength) + Data.FuseLength = math.Clamp(ToolData.FuzeLength, GUIData.MinFuzeTime, GUIData.MaxFuzeTime) + Data.FillerMass = GUIData.FillerVol * ACF.HEDensity * 0.0005 + Data.WPMass = GUIData.WPVol * ACF.HEDensity * 0.0005 + Data.ProjMass = math.max(GUIData.ProjVolume - (GUIData.FillerVol + GUIData.WPVol), 0) * 0.0079 + Data.FillerMass + Data.WPMass + Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass) + Data.DragCoef = Data.FrArea * 0.0001 / Data.ProjMass - GUIData.MinFillerVol = 0 - GUIData.MaxFillerVol = math.min(GUIData.ProjVolume, MaxVol) - GUIData.MaxSmokeVol = math.max(GUIData.MaxFillerVol - PlayerData.Data6, GUIData.MinFillerVol) - GUIData.MaxWPVol = math.max(GUIData.MaxFillerVol - PlayerData.Data5, GUIData.MinFillerVol) - - local Ratio = math.min(GUIData.MaxFillerVol / (PlayerData.Data5 + PlayerData.Data6), 1) - - GUIData.FillerVol = math.min(PlayerData.Data5 * Ratio, GUIData.MaxSmokeVol) - GUIData.WPVol = math.min(PlayerData.Data6 * Ratio, GUIData.MaxWPVol) - - Data.FillerMass = GUIData.FillerVol * ACF.HEDensity / 2000 - Data.WPMass = GUIData.WPVol * ACF.HEDensity / 2000 - Data.ProjMass = math.max(GUIData.ProjVolume - (GUIData.FillerVol + GUIData.WPVol), 0) * 7.9 / 1000 + Data.FillerMass + Data.WPMass - Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass, Data.Caliber) - Data.ShovePower = 0.1 - Data.PenArea = Data.FrArea ^ ACF.PenAreaMod - Data.DragCoef = ((Data.FrArea / 10000) / Data.ProjMass) - Data.LimitVel = 100 --Most efficient penetration speed in m/s - Data.KETransfert = 0.1 --Kinetic energy transfert to the target for movement purposes - Data.Ricochet = 60 --Base ricochet angle - Data.DetonatorAngle = 80 - Data.CanFuze = Data.Caliber > 2 -- Can fuze on calibers > 20mm - - if PlayerData.Data7 < 0.5 then - PlayerData.Data7 = 0 - Data.FuseLength = PlayerData.Data7 - else - PlayerData.Data7 = math.max(math.Round(PlayerData.Data7, 1), 0.5) - Data.FuseLength = PlayerData.Data7 + for K, V in pairs(self:GetDisplayData(Data)) do + GUIData[K] = V end +end - Data.BoomPower = Data.PropMass + Data.FillerMass + Data.WPMass +function Ammo:BaseConvert(_, ToolData) + if not ToolData.Projectile then ToolData.Projectile = 0 end + if not ToolData.Propellant then ToolData.Propellant = 0 end + if not ToolData.SmokeFiller then ToolData.SmokeFiller = 0 end + if not ToolData.WPFiller then ToolData.WPFiller = 0 end + if not ToolData.FuzeLength then ToolData.FuzeLength = 0 end - --Only the crates need this part - if SERVER then - ServerData.Id = PlayerData.Id - ServerData.Type = PlayerData.Type + local Data, GUIData = ACF.RoundBaseGunpowder(ToolData, {}) - return table.Merge(Data, ServerData) - end + GUIData.MinFuzeTime = 0 + GUIData.MaxFuzeTime = 1 + GUIData.MinFillerVol = 0 - --Only tthe GUI needs this part - if CLIENT then - GUIData = table.Merge(GUIData, Ammo.GetDisplayData(Data)) + Data.ShovePower = 0.1 + Data.PenArea = Data.FrArea ^ ACF.PenAreaMod + Data.LimitVel = 100 --Most efficient penetration speed in m/s + Data.KETransfert = 0.1 --Kinetic energy transfert to the target for movement purposes + Data.Ricochet = 60 --Base ricochet angle + Data.DetonatorAngle = 80 + Data.CanFuze = Data.Caliber > 20 -- Can fuze on calibers > 20mm - return table.Merge(Data, GUIData) - end + self:UpdateRoundData(ToolData, Data, GUIData) + + return Data, GUIData end -function Ammo.Network(Crate, BulletData) - Crate:SetNWString("AmmoType", "SM") - Crate:SetNWString("AmmoID", BulletData.Id) - Crate:SetNWFloat("Caliber", BulletData.Caliber) - Crate:SetNWFloat("ProjMass", BulletData.ProjMass) - Crate:SetNWFloat("FillerMass", BulletData.FillerMass) - Crate:SetNWFloat("WPMass", BulletData.WPMass) - Crate:SetNWFloat("PropMass", BulletData.PropMass) - Crate:SetNWFloat("DragCoef", BulletData.DragCoef) - Crate:SetNWFloat("MuzzleVel", BulletData.MuzzleVel) - Crate:SetNWFloat("Tracer", BulletData.Tracer) +function Ammo:Network(Crate, BulletData) + Crate:SetNW2String("AmmoType", "SM") + Crate:SetNW2String("AmmoID", BulletData.Id) + Crate:SetNW2Float("Caliber", BulletData.Caliber) + Crate:SetNW2Float("ProjMass", BulletData.ProjMass) + Crate:SetNW2Float("FillerMass", BulletData.FillerMass) + Crate:SetNW2Float("WPMass", BulletData.WPMass) + Crate:SetNW2Float("PropMass", BulletData.PropMass) + Crate:SetNW2Float("DragCoef", BulletData.DragCoef) + Crate:SetNW2Float("MuzzleVel", BulletData.MuzzleVel) + Crate:SetNW2Float("Tracer", BulletData.Tracer) end -function Ammo.GetDisplayData(Data) - local SMFiller = math.min(math.log(1 + Data.FillerMass * 8 * 39.37) / 0.02303, 350) - local WPFiller = math.min(math.log(1 + Data.WPMass * 8 * 39.37) / 0.02303, 350) +function Ammo:GetDisplayData(Data) + local SMFiller = math.min(math.log(1 + Data.FillerMass * 8 * 39.37) * 43.4216, 350) + local WPFiller = math.min(math.log(1 + Data.WPMass * 8 * 39.37) * 43.4216, 350) return { - SMFiller = SMFiller, --smoke filler - SMLife = math.Round(20 + SMFiller * 0.25, 1), - SMRadiusMin = math.Round(SMFiller * 1.25 * 0.15 * 0.0254, 1), - SMRadiusMax = math.Round(SMFiller * 1.25 * 2 * 0.0254, 1), - WPFiller = WPFiller, --wp filler - WPLife = math.Round(6 + WPFiller * 0.1, 1), - WPRadiusMin = math.Round(WPFiller * 1.25 * 0.0254, 1), - WPRadiusMax = math.Round(WPFiller * 1.25 * 2 * 0.0254, 1), + SMFiller = SMFiller, + SMLife = math.Round(20 + SMFiller * 0.25, 2), + SMRadiusMin = math.Round(SMFiller * 1.25 * 0.15 * 0.0254, 2), + SMRadiusMax = math.Round(SMFiller * 1.25 * 2 * 0.0254, 2), + WPFiller = WPFiller, + WPLife = math.Round(6 + WPFiller * 0.1, 2), + WPRadiusMin = math.Round(WPFiller * 1.25 * 0.0254, 2), + WPRadiusMax = math.Round(WPFiller * 1.25 * 2 * 0.0254, 2), } end -function Ammo.GetCrateText(BulletData) +function Ammo:GetCrateText(BulletData) local Text = "Muzzle Velocity: %s m/s%s%s" - local Data = Ammo.GetDisplayData(BulletData) + local Data = self:GetDisplayData(BulletData) local WPText, SMText = "", "" @@ -144,9 +130,18 @@ function Ammo.GetCrateText(BulletData) return Text:format(math.Round(BulletData.MuzzleVel, 2), WPText, SMText) end -function Ammo.PropImpact(_, Bullet, Target, HitNormal, HitPos, Bone) +function Ammo:GetToolData() + local Data = Ammo.BaseClass.GetToolData(self) + Data.SmokeFiller = ACF.ReadNumber("SmokeFiller") + Data.WPFiller = ACF.ReadNumber("WPFiller") + Data.FuzeLength = ACF.ReadNumber("FuzeLength") + + return Data +end + +function Ammo:PropImpact(_, Bullet, Target, HitNormal, HitPos, Bone) if ACF_Check(Target) then - local Speed = Bullet.Flight:Length() / ACF.Scale + local Speed = Bullet.Flight:Length() / ACF.Scale local Energy = ACF_Kinetic(Speed, Bullet.ProjMass - (Bullet.FillerMass + Bullet.WPMass), Bullet.LimitVel) local HitRes = ACF_RoundImpact(Bullet, Speed, Energy, Target, HitPos, HitNormal, Bone) @@ -156,11 +151,11 @@ function Ammo.PropImpact(_, Bullet, Target, HitNormal, HitPos, Bone) return false end -function Ammo.WorldImpact() +function Ammo:WorldImpact() return false end -function Ammo.ImpactEffect(_, Bullet) +function Ammo:ImpactEffect(_, Bullet) local Crate = Bullet.Crate local Color = IsValid(Crate) and Crate:GetColor() or Color(255, 255, 255) @@ -175,60 +170,115 @@ function Ammo.ImpactEffect(_, Bullet) util.Effect("ACF_Smoke", Effect) end -function Ammo.CreateMenu(Panel, Table) - acfmenupanel:AmmoSelect(Ammo.Blacklist) - - acfmenupanel:CPanelText("Desc", "") --Description (Name, Desc) - acfmenupanel:CPanelText("LengthDisplay", "") --Total round length (Name, Desc) - acfmenupanel:AmmoSlider("PropLength", 0, 0, 1000, 3, "Propellant Length", "") --Slider (Name, Value, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("ProjLength", 0, 0, 1000, 3, "Projectile Length", "") --Slider (Name, Value, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("FillerVol", 0, 0, 1000, 3, "Smoke Filler", "") --Slider (Name, Value, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("WPVol", 0, 0, 1000, 3, "WP Filler", "") --Slider (Name, Value, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("FuseLength", 0, 0, 1000, 3, "Timed Fuse", "") - acfmenupanel:AmmoCheckbox("Tracer", "Tracer", "") --Tracer checkbox (Name, Title, Desc) - acfmenupanel:CPanelText("VelocityDisplay", "") --Proj muzzle velocity (Name, Desc) - acfmenupanel:CPanelText("BlastDisplay", "") --HE Blast data (Name, Desc) - acfmenupanel:CPanelText("FragDisplay", "") --HE Fragmentation data (Name, Desc) - - Ammo.UpdateMenu(Panel, Table) -end +function Ammo:MenuAction(Menu, ToolData, Data) + local SmokeFiller = Menu:AddSlider("Smoke Filler", Data.MinFillerVol, Data.MaxFillerVol, 2) + SmokeFiller:SetDataVar("SmokeFiller", "OnValueChanged") + SmokeFiller:TrackDataVar("Projectile") + SmokeFiller:TrackDataVar("WPFiller") + SmokeFiller:SetValueFunction(function(Panel, IsTracked) + ToolData.SmokeFiller = math.Round(ACF.ReadNumber("SmokeFiller"), 2) -function Ammo.UpdateMenu(Panel) - local PlayerData = { - Id = acfmenupanel.AmmoData.Data.id, --AmmoSelect GUI - Type = "SM", --Hardcoded, match ACFRoundTypes table index - PropLength = acfmenupanel.AmmoData.PropLength, --PropLength slider - ProjLength = acfmenupanel.AmmoData.ProjLength, --ProjLength slider - Data5 = acfmenupanel.AmmoData.FillerVol, - Data6 = acfmenupanel.AmmoData.WPVol, - Data7 = acfmenupanel.AmmoData.FuseLength, - Data10 = acfmenupanel.AmmoData.Tracer and 1 or 0, - } + if not IsTracked then + Data.FillerPriority = "Smoke" + end - local Data = Ammo.Convert(Panel, PlayerData) - - RunConsoleCommand("acfmenu_data1", acfmenupanel.AmmoData.Data.id) - RunConsoleCommand("acfmenu_data2", PlayerData.Type) - RunConsoleCommand("acfmenu_data3", Data.PropLength) --For Gun ammo, Data3 should always be Propellant - RunConsoleCommand("acfmenu_data4", Data.ProjLength) --And Data4 total round mass - RunConsoleCommand("acfmenu_data5", Data.FillerVol) - RunConsoleCommand("acfmenu_data6", Data.WPVol) - RunConsoleCommand("acfmenu_data7", Data.FuseLength) - RunConsoleCommand("acfmenu_data10", Data.Tracer) - - acfmenupanel:AmmoSlider("PropLength", Data.PropLength, Data.MinPropLength, Data.MaxTotalLength, 3, "Propellant Length", "Propellant Mass : " .. (math.floor(Data.PropMass * 1000)) .. " g") --Propellant Length Slider (Name, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("ProjLength", Data.ProjLength, Data.MinProjLength, Data.MaxTotalLength, 3, "Projectile Length", "Projectile Mass : " .. (math.floor(Data.ProjMass * 1000)) .. " g") --Projectile Length Slider (Name, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("FillerVol", Data.FillerVol, Data.MinFillerVol, Data.MaxFillerVol, 3, "Smoke Filler Volume", "Smoke Filler Mass : " .. (math.floor(Data.FillerMass * 1000)) .. " g") --HE Filler Slider (Name, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("WPVol", Data.WPVol, Data.MinFillerVol, Data.MaxFillerVol, 3, "WP Filler Volume", "WP Filler Mass : " .. (math.floor(Data.WPMass * 1000)) .. " g") --HE Filler Slider (Name, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("FuseLength", Data.FuseLength, 0, 10, 1, "Fuse Time", Data.FuseLength .. " s") - acfmenupanel:AmmoCheckbox("Tracer", "Tracer : " .. (math.floor(Data.Tracer * 10) / 10) .. "cm\n", "") --Tracer checkbox (Name, Title, Desc) - acfmenupanel:CPanelText("Desc", Ammo.Description) --Description (Name, Desc) - acfmenupanel:CPanelText("LengthDisplay", "Round Length : " .. (math.floor((Data.PropLength + Data.ProjLength + Data.Tracer) * 100) / 100) .. "/" .. Data.MaxTotalLength .. " cm") --Total round length (Name, Desc) - acfmenupanel:CPanelText("VelocityDisplay", "Muzzle Velocity : " .. math.floor(Data.MuzzleVel * ACF.Scale) .. " m/s") --Proj muzzle velocity (Name, Desc) -end + self:UpdateRoundData(ToolData, Data) + + Panel:SetMax(Data.MaxFillerVol) + Panel:SetValue(Data.FillerVol) + + return Data.FillerVol + end) + + local WPFiller = Menu:AddSlider("WP Filler", Data.MinFillerVol, Data.MaxFillerVol, 2) + WPFiller:SetDataVar("WPFiller", "OnValueChanged") + WPFiller:TrackDataVar("SmokeFiller") + WPFiller:TrackDataVar("Projectile") + WPFiller:SetValueFunction(function(Panel, IsTracked) + ToolData.WPFiller = math.Round(ACF.ReadNumber("WPFiller"), 2) + + if not IsTracked then + Data.FillerPriority = "WP" + end + + self:UpdateRoundData(ToolData, Data) + + Panel:SetMax(Data.MaxFillerVol) + Panel:SetValue(Data.WPVol) + + return Data.WPVol + end) + + local FuzeLength = Menu:AddSlider("Fuze Delay", Data.MinFuzeTime, Data.MaxFuzeTime, 2) + FuzeLength:SetDataVar("FuzeLength", "OnValueChanged") + FuzeLength:SetValueFunction(function(Panel) + ToolData.FuzeLength = math.Round(ACF.ReadNumber("FuzeLength"), 2) + + self:UpdateRoundData(ToolData, Data) + + Panel:SetValue(Data.FuseLength) + + return Data.FuseLength + end) + + local Tracer = Menu:AddCheckBox("Tracer") + Tracer:SetDataVar("Tracer", "OnChange") + Tracer:SetValueFunction(function(Panel) + ToolData.Tracer = ACF.ReadBool("Tracer") + + self:UpdateRoundData(ToolData, Data) + + ACF.WriteValue("Projectile", Data.ProjLength) + ACF.WriteValue("Propellant", Data.PropLength) + + Panel:SetText("Tracer : " .. Data.Tracer .. " cm") + Panel:SetValue(ToolData.Tracer) + + return ToolData.Tracer + end) + + local RoundStats = Menu:AddLabel() + RoundStats:TrackDataVar("Projectile", "SetText") + RoundStats:TrackDataVar("Propellant") + RoundStats:TrackDataVar("SmokeFiller") + RoundStats:TrackDataVar("WPFiller") + RoundStats:SetValueFunction(function() + self:UpdateRoundData(ToolData, Data) + + local Text = "Muzzle Velocity : %s m/s\nProjectile Mass : %s\nPropellant Mass : %s" + local MuzzleVel = math.Round(Data.MuzzleVel * ACF.Scale, 2) + local ProjMass = ACF.GetProperMass(Data.ProjMass) + local PropMass = ACF.GetProperMass(Data.PropMass) + + return Text:format(MuzzleVel, ProjMass, PropMass) + end) + + local SmokeStats = Menu:AddLabel() + SmokeStats:TrackDataVar("SmokeFiller", "SetText") + SmokeStats:TrackDataVar("WPFiller") + SmokeStats:SetValueFunction(function() + self:UpdateRoundData(ToolData, Data) + + local SMText, WPText = "", "" + + if Data.FillerMass > 0 then + local Text = "Smoke Filler Mass : %s\nSmoke Filler Radius : %s m\nSmoke Filler Life : %s s\n" + local SmokeMass = ACF.GetProperMass(Data.FillerMass) + local SmokeRadius = (Data.SMRadiusMin + Data.SMRadiusMax) * 0.5 + + SMText = Text:format(SmokeMass, SmokeRadius, Data.SMLife) + end + + if Data.WPMass > 0 then + local Text = "WP Filler Mass : %s\nWP Filler Radius : %s m\nWP Filler Life : %s s" + local WPMass = ACF.GetProperMass(Data.WPMass) + local WPRadius = (Data.WPRadiusMin + Data.WPRadiusMax) * 0.5 + + WPText = Text:format(WPMass, WPRadius, Data.WPLife) + end -function Ammo.MenuAction(Menu) - Menu:AddParagraph("Testing SM menu.") + return SMText .. WPText + end) end ACF.RegisterAmmoDecal("SM", "damage/he_pen", "damage/he_rico") diff --git a/lua/acf/shared/guns/shortcannon.lua b/lua/acf/shared/guns/shortcannon.lua index 4779098ee..95af09d21 100644 --- a/lua/acf/shared/guns/shortcannon.lua +++ b/lua/acf/shared/guns/shortcannon.lua @@ -100,7 +100,7 @@ ACF_defineGun("140mmSC", { } ) ACF.RegisterWeaponClass("SC", { - Name = "Short-Barrel Cannon", + Name = "Short-Barrelled Cannon", Description = "Short cannons trade muzzle velocity and accuracy for lighter weight and smaller size, with more penetration than howitzers and lighter than cannons.", MuzzleFlash = "cannon_muzzleflash_noscale", ROFMod = 1.7, diff --git a/lua/entities/acf_ammo/init.lua b/lua/entities/acf_ammo/init.lua index 5db3f950e..3069a914b 100644 --- a/lua/entities/acf_ammo/init.lua +++ b/lua/entities/acf_ammo/init.lua @@ -413,7 +413,7 @@ do -- Metamethods ------------------------------- local AmmoRoll = math.Rand(0, 1) < Entity.Ammo / math.max(Entity.Capacity, 1) if VolumeRoll and AmmoRoll then - local Speed = ACF_MuzzleVelocity(Entity.BulletData.PropMass, Entity.BulletData.ProjMass / 2, Entity.Caliber) + local Speed = ACF_MuzzleVelocity(Entity.BulletData.PropMass, Entity.BulletData.ProjMass / 2) Entity:EmitSound("ambient/explosions/explode_4.wav", 350, math.max(255 - Entity.BulletData.PropMass * 100,60)) From c28d3841b7dfabe2801088746ec6586a55df204b Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Mon, 9 Mar 2020 05:12:22 -0300 Subject: [PATCH 034/279] Applied reload mechanic changes to new weapon registrations --- lua/acf/client/menu_items/weapons_menu.lua | 2 +- lua/acf/shared/guns/autocannon.lua | 24 ++++++++++-------- lua/acf/shared/guns/autoloader.lua | 4 +++ lua/acf/shared/guns/grenadelauncher.lua | 3 ++- lua/acf/shared/guns/heavymachinegun.lua | 6 ++++- lua/acf/shared/guns/machinegun.lua | 3 +++ lua/acf/shared/guns/rotaryautocannon.lua | 11 ++++---- lua/acf/shared/guns/semiauto.lua | 29 +++++++++++++--------- lua/acf/shared/guns/smokelauncher.lua | 4 +++ 9 files changed, 56 insertions(+), 30 deletions(-) diff --git a/lua/acf/client/menu_items/weapons_menu.lua b/lua/acf/client/menu_items/weapons_menu.lua index a70ffb1e9..8d0c05797 100644 --- a/lua/acf/client/menu_items/weapons_menu.lua +++ b/lua/acf/client/menu_items/weapons_menu.lua @@ -91,7 +91,7 @@ local function CreateMenu(Menu) local ClassData = ClassList.Selected local RoundVolume = 3.1416 * (Data.Caliber * 0.05) ^ 2 * Data.Round.MaxLength - local Firerate = 60 / (((RoundVolume * 0.002) ^ 0.6) * ClassData.ROFMod * (Data.ROFMod or 1)) + local Firerate = Data.Cyclic or 60 / (((RoundVolume * 0.002) ^ 0.6) * ClassData.ROFMod * (Data.ROFMod or 1)) local Magazine = Data.MagSize and MagText:format(Data.MagSize, Data.MagReload) or "" local Choices = Sorted[ClassData.Items] diff --git a/lua/acf/shared/guns/autocannon.lua b/lua/acf/shared/guns/autocannon.lua index c73b32f9d..e1b689454 100644 --- a/lua/acf/shared/guns/autocannon.lua +++ b/lua/acf/shared/guns/autocannon.lua @@ -89,7 +89,7 @@ ACF.RegisterWeaponClass("AC", { Description = "Autocannons have a rather high weight and bulk for the ammo they fire, but they can fire it extremely fast.", MuzzleFlash = "auto_muzzleflash_noscale", ROFMod = 0.85, - Spread = 0.12, + Spread = 0.25, Sound = "weapons/ACF_Gun/ac_fire4.mp3", Caliber = { Min = 20, @@ -102,11 +102,12 @@ ACF.RegisterWeapon("20mmAC", "AC", { Description = "The 20mm autocannon is the smallest of the family; having a good rate of fire but a tiny shell.", Model = "models/autocannon/autocannon_20mm.mdl", Caliber = 20, - Mass = 225, + Mass = 500, Year = 1930, ROFMod = 0.7, MagSize = 100, - MagReload = 3, + MagReload = 15, + Cyclic = 250, Round = { MaxLength = 32, PropMass = 0.13, @@ -118,11 +119,12 @@ ACF.RegisterWeapon("30mmAC", "AC", { Description = "The 30mm autocannon can fire shells with sufficient space for a small payload, and has modest anti-armor capability", Model = "models/autocannon/autocannon_30mm.mdl", Caliber = 30, - Mass = 960, + Mass = 1000, Year = 1935, ROFMod = 0.5, MagSize = 75, - MagReload = 3, + MagReload = 20, + Cyclic = 225, Round = { MaxLength = 39, PropMass = 0.350, @@ -138,7 +140,8 @@ ACF.RegisterWeapon("40mmAC", "AC", { Year = 1940, ROFMod = 0.48, MagSize = 30, - MagReload = 3, + MagReload = 25, + Cyclic = 200, Round = { MaxLength = 45, PropMass = 0.9, @@ -150,13 +153,14 @@ ACF.RegisterWeapon("50mmAC", "AC", { Description = "The 50mm autocannon fires shells comparable with the 50mm Cannon, making it capable of destroying light armour quite quickly.", Model = "models/autocannon/autocannon_50mm.mdl", Caliber = 50, - Mass = 2130, + Mass = 2000, Year = 1965, ROFMod = 0.4, - MagSize = 20, - MagReload = 3, + MagSize = 25, + MagReload = 30, + Cyclic = 175, Round = { MaxLength = 52, - PropMass = 1.2 + PropMass = 1.2, } }) diff --git a/lua/acf/shared/guns/autoloader.lua b/lua/acf/shared/guns/autoloader.lua index 0807a8662..d6f874d1c 100644 --- a/lua/acf/shared/guns/autoloader.lua +++ b/lua/acf/shared/guns/autoloader.lua @@ -126,6 +126,7 @@ ACF.RegisterWeapon("75mmAL", "AL", { ROFMod = 1, MagSize = 8, MagReload = 15, + Cyclic = 30, Round = { MaxLength = 78, PropMass = 3.8, @@ -142,6 +143,7 @@ ACF.RegisterWeapon("100mmAL", "AL", { ROFMod = 0.85, MagSize = 6, MagReload = 21, + Cyclic = 18, Round = { MaxLength = 93, PropMass = 9.5, @@ -158,6 +160,7 @@ ACF.RegisterWeapon("120mmAL", "AL", { ROFMod = 0.757, MagSize = 5, MagReload = 27, + Cyclic = 11, Round = { MaxLength = 110, PropMass = 18, @@ -174,6 +177,7 @@ ACF.RegisterWeapon("140mmAL", "AL", { ROFMod = 0.743, MagSize = 5, MagReload = 35, + Cyclic = 8, Round = { MaxLength = 127, PropMass = 28, diff --git a/lua/acf/shared/guns/grenadelauncher.lua b/lua/acf/shared/guns/grenadelauncher.lua index d732a1760..04a2c1381 100644 --- a/lua/acf/shared/guns/grenadelauncher.lua +++ b/lua/acf/shared/guns/grenadelauncher.lua @@ -48,8 +48,9 @@ ACF.RegisterWeapon("40mmGL", "GL", { Caliber = 40, Mass = 55, Year = 1970, - MagSize = 6, + MagSize = 30, MagReload = 7.5, + Cyclic = 200, Round = { MaxLength = 7.5, PropMass = 0.01, diff --git a/lua/acf/shared/guns/heavymachinegun.lua b/lua/acf/shared/guns/heavymachinegun.lua index cb2872ef0..de78b0f0c 100644 --- a/lua/acf/shared/guns/heavymachinegun.lua +++ b/lua/acf/shared/guns/heavymachinegun.lua @@ -93,7 +93,7 @@ ACF.RegisterWeaponClass("HMG", { Description = "Designed as autocannons for aircraft, HMGs are rapid firing, lightweight, and compact but sacrifice accuracy, magazine size, and reload times.", MuzzleFlash = "mg_muzzleflash_noscale", ROFMod = 0.14, - Spread = 0.4, + Spread = 1.3, Sound = "weapons/ACF_Gun/mg_fire3.mp3", Caliber = { Min = 13, @@ -116,6 +116,7 @@ ACF.RegisterWeapon("13mmHMG", "HMG", { ROFMod = 3.3, MagSize = 35, MagReload = 6, + Cyclic = 550, Round = { MaxLength = 22, PropMass = 0.09, @@ -132,6 +133,7 @@ ACF.RegisterWeapon("20mmHMG", "HMG", { ROFMod = 1.9, MagSize = 30, MagReload = 6, + Cyclic = 525, Round = { MaxLength = 30, PropMass = 0.12, @@ -148,6 +150,7 @@ ACF.RegisterWeapon("30mmHMG", "HMG", { ROFMod = 1.1, MagSize = 25, MagReload = 6, + Cyclic = 500, Round = { MaxLength = 37, PropMass = 0.35, @@ -164,6 +167,7 @@ ACF.RegisterWeapon("40mmHMG", "HMG", { ROFMod = 0.95, MagSize = 20, MagReload = 8, + Cyclic = 475, Round = { MaxLength = 42, PropMass = 0.9, diff --git a/lua/acf/shared/guns/machinegun.lua b/lua/acf/shared/guns/machinegun.lua index 573554a1e..689311ab4 100644 --- a/lua/acf/shared/guns/machinegun.lua +++ b/lua/acf/shared/guns/machinegun.lua @@ -89,6 +89,7 @@ ACF.RegisterWeapon("7.62mmMG", "MG", { ROFMod = 1.59, MagSize = 250, MagReload = 6, + Cyclic = 700, -- Rounds per minute Round = { MaxLength = 13, PropMass = 0.04, @@ -105,6 +106,7 @@ ACF.RegisterWeapon("12.7mmMG", "MG", { ROFMod = 1, MagSize = 150, MagReload = 6, + Cyclic = 600, Round = { MaxLength = 15.8, PropMass = 0.03, @@ -121,6 +123,7 @@ ACF.RegisterWeapon("14.5mmMG", "MG", { ROFMod = 1, MagSize = 90, MagReload = 5, + Cyclic = 500, Round = { MaxLength = 19.5, PropMass = 0.04, diff --git a/lua/acf/shared/guns/rotaryautocannon.lua b/lua/acf/shared/guns/rotaryautocannon.lua index 65f56f0e3..0b121985f 100644 --- a/lua/acf/shared/guns/rotaryautocannon.lua +++ b/lua/acf/shared/guns/rotaryautocannon.lua @@ -88,8 +88,9 @@ ACF.RegisterWeapon("20mmRAC", "RAC", { Mass = 760, Year = 1965, ROFMod = 2.1, - MagSize = 40, - MagReload = 7, + MagSize = 200, + MagReload = 25, + Cyclic = 4000, Round = { MaxLength = 30, PropMass = 0.12, @@ -104,11 +105,11 @@ ACF.RegisterWeapon("30mmRAC", "RAC", { Mass = 1500, Year = 1975, ROFMod = 1, - MagSize = 40, + MagSize = 100, + MagReload = 35, + Cyclic = 3000, Round = { - MagReload = 8, MaxLength = 40, PropMass = 0.350, } - }) \ No newline at end of file diff --git a/lua/acf/shared/guns/semiauto.lua b/lua/acf/shared/guns/semiauto.lua index 97f138e10..1d13abd9c 100644 --- a/lua/acf/shared/guns/semiauto.lua +++ b/lua/acf/shared/guns/semiauto.lua @@ -104,10 +104,10 @@ ACF_defineGun("76mmSA", { ACF.RegisterWeaponClass("SA", { Name = "Semiautomatic Cannon", - Description = "Semiautomatic cannons offer better payloads than autocannons and less weight at the cost of rate of fire.", + Description = "Semiautomatic cannons offer light weight, small size, and high rates of fire at the cost of often reloading and low accuracy.", MuzzleFlash = "semi_muzzleflash_noscale", ROFMod = 0.36, - Spread = 0.1, + Spread = 1.1, Sound = "weapons/acf_gun/sa_fire1.mp3", Caliber = { Min = 20, @@ -120,11 +120,12 @@ ACF.RegisterWeapon("25mmSA", "SA", { Description = "The 25mm semiauto can quickly put five rounds downrange, being lethal, yet light.", Model = "models/autocannon/semiautocannon_25mm.mdl", Caliber = 25, - Mass = 200, + Mass = 250, Year = 1935, ROFMod = 0.7, MagSize = 5, - MagReload = 2, + MagReload = 2.5, + Cyclic = 300, Round = { MaxLength = 39, PropMass = 0.5, @@ -136,11 +137,12 @@ ACF.RegisterWeapon("37mmSA", "SA", { Description = "The 37mm is surprisingly powerful, its five-round clips boasting a respectable payload and a high muzzle velocity.", Model = "models/autocannon/semiautocannon_37mm.mdl", Caliber = 37, - Mass = 540, + Mass = 500, Year = 1940, ROFMod = 0.7, MagSize = 5, - MagReload = 3.5, + MagReload = 3.7, + Cyclic = 250, Round = { MaxLength = 42, PropMass = 1.125, @@ -152,11 +154,12 @@ ACF.RegisterWeapon("45mmSA", "SA", { Description = "The 45mm can easily shred light armor, with a respectable rate of fire, but its armor penetration pales in comparison to regular cannons.", Model = "models/autocannon/semiautocannon_45mm.mdl", Caliber = 45, - Mass = 870, + Mass = 750, Year = 1965, ROFMod = 0.72, MagSize = 5, - MagReload = 4, + MagReload = 4.5, + Cyclic = 225, Round = { MaxLength = 52, PropMass = 1.8, @@ -168,11 +171,12 @@ ACF.RegisterWeapon("57mmSA", "SA", { Description = "The 57mm is a respectable light armament, offering considerable penetration and moderate fire rate.", Model = "models/autocannon/semiautocannon_57mm.mdl", Caliber = 57, - Mass = 1560, + Mass = 1000, Year = 1965, ROFMod = 0.8, MagSize = 5, - MagReload = 4.5, + MagReload = 5.7, + Cyclic = 200, Round = { MaxLength = 62, PropMass = 2, @@ -184,11 +188,12 @@ ACF.RegisterWeapon("76mmSA", "SA", { Description = "The 76mm semiauto is a fearsome weapon, able to put five 76mm rounds downrange in 8 seconds.", Model = "models/autocannon/semiautocannon_76mm.mdl", Caliber = 76.2, - Mass = 2990, + Mass = 2000, Year = 1984, ROFMod = 0.85, MagSize = 5, - MagReload = 5, + MagReload = 7.6, + Cyclic = 150, Round = { MaxLength = 70, PropMass = 4.75, diff --git a/lua/acf/shared/guns/smokelauncher.lua b/lua/acf/shared/guns/smokelauncher.lua index 35a136610..fc52f8df3 100644 --- a/lua/acf/shared/guns/smokelauncher.lua +++ b/lua/acf/shared/guns/smokelauncher.lua @@ -71,6 +71,9 @@ ACF.RegisterWeapon("40mmSL", "SL", { Caliber = 40, Mass = 1, Year = 1941, + MagSize = 1, + MagReload = 30, + Cyclic = 1, Round = { MaxLength = 17.5, PropMass = 0.000075, @@ -87,6 +90,7 @@ ACF.RegisterWeapon("40mmCL", "SL", { Year = 1950, MagSize = 6, MagReload = 40, + Cyclic = 200, Round = { MaxLength = 12, PropMass = 0.001, From 139114aae69630c577258118446cc89daa01224c Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Tue, 10 Mar 2020 01:50:15 -0300 Subject: [PATCH 035/279] Poblated Contact and Online Wiki menu options - Poblated the Contact option with several links. - Poblated the Online Wiki option with a direct link to the repository's wiki. - Poblated the Missiles option with a link to get ACF-3 Missiles. --- lua/acf/client/cl_menu.lua | 21 ++++++++--- lua/acf/client/menu_items/contact.lua | 43 +++++++++++++++++++++++ lua/acf/client/menu_items/online_wiki.lua | 15 ++++++++ 3 files changed, 74 insertions(+), 5 deletions(-) create mode 100644 lua/acf/client/menu_items/contact.lua create mode 100644 lua/acf/client/menu_items/online_wiki.lua diff --git a/lua/acf/client/cl_menu.lua b/lua/acf/client/cl_menu.lua index 3013befb2..1c48f8888 100644 --- a/lua/acf/client/cl_menu.lua +++ b/lua/acf/client/cl_menu.lua @@ -3,9 +3,20 @@ local Lookup = {} local Count = 0 do -- Menu population functions - local function DefaultAction(Panel) - Panel:AddTitle("There's nothing here.") - Panel:AddLabel("This option is either a work in progress or something isn't working as intended.") + local function DefaultAction(Menu) + Menu:AddTitle("There's nothing here.") + Menu:AddLabel("This option is either a work in progress or something isn't working as intended.") + end + + local function MissilesMenu(Menu) + Menu:AddTitle("ACF-3 Missiles is not installed.") + Menu:AddLabel("This option requires ACF-3 Missiles to be installed. You can get it here:") + + local Link = Menu:AddButton("ACF-3 Missiles Repository") + + function Link:DoClickInternal() + gui.OpenURL("https://github.com/TwistedTail/ACF-3-Missiles") + end end function ACF.AddOption(Name, Icon) @@ -57,13 +68,13 @@ do -- Menu population functions -- Small workaround to give the correct order to the items ACF.AddOption("About the Addon", "information") - ACF.AddOptionItem("About the Addon", "Guidelines", "book_open") + ACF.AddOptionItem("About the Addon", "Online Wiki", "book_open") ACF.AddOptionItem("About the Addon", "Updates", "newspaper") ACF.AddOptionItem("About the Addon", "Contact Us", "feed") ACF.AddOption("Entities", "brick") ACF.AddOptionItem("Entities", "Weapons", "gun") - ACF.AddOptionItem("Entities", "Missiles", "wand") + ACF.AddOptionItem("Entities", "Missiles", "wand", MissilesMenu) ACF.AddOptionItem("Entities", "Mobility", "car") ACF.AddOptionItem("Entities", "Sensors", "transmit") ACF.AddOptionItem("Entities", "Components", "cog") diff --git a/lua/acf/client/menu_items/contact.lua b/lua/acf/client/menu_items/contact.lua new file mode 100644 index 000000000..7abfa367a --- /dev/null +++ b/lua/acf/client/menu_items/contact.lua @@ -0,0 +1,43 @@ +local function CreateMenu(Menu) + Menu:AddTitle("Your feedback is important.") + Menu:AddLabel("For this reason, we've setup a variety of methods to generate discussion among the members of the ACF community.") + + Menu:AddTitle("How to Contribute") + Menu:AddLabel("To make it easier for first time contributors, we've left a guide about how to contribute to the addon.") + + local Contribute = Menu:AddButton("Contributing to ACF") + + function Contribute:DoClickInternal() + gui.OpenURL("https://github.com/Stooberton/ACF-3/blob/master/CONTRIBUTING.md") + end + + Menu:AddTitle("Official Discord Server") + Menu:AddLabel("We have a Discord server! You can discuss the addon's development or just hang around on one of the off-topic channels.") + + local Discord = Menu:AddButton("Join the Discord Server") + + function Discord:DoClickInternal() + gui.OpenURL("https://discordapp.com/invite/shk5sc5") + end + + Menu:AddTitle("Official Steam Group") + Menu:AddLabel("There's also a Steam group, you'll find all important announcements about the addon's development there.") + + local Steam = Menu:AddButton("Join the Steam Group") + + function Steam:DoClickInternal() + gui.OpenURL("https://steamcommunity.com/groups/officialacf") + end + + Menu:AddTitle("Github Issues & Suggestions") + Menu:AddLabel("The recommended method for bug reporting and suggestion posting is the Issues tab on the Github repository.") + Menu:AddLabel("By using this method, you'll be able to easily track your issue and the discussion related to it.") + + local Issue = Menu:AddButton("Report an Issue") + + function Issue:DoClickInternal() + gui.OpenURL("https://github.com/Stooberton/ACF-3/issues/new/choose") + end +end + +ACF.AddOptionItem("About the Addon", "Contact Us", "feed", CreateMenu) diff --git a/lua/acf/client/menu_items/online_wiki.lua b/lua/acf/client/menu_items/online_wiki.lua new file mode 100644 index 000000000..b49749a12 --- /dev/null +++ b/lua/acf/client/menu_items/online_wiki.lua @@ -0,0 +1,15 @@ +local function CreateMenu(Menu) + Menu:AddTitle("A Reference Guide") + Menu:AddLabel("From now on, the ACF wiki will have a greater focus on references about the addon's multiple mechanics.") + Menu:AddLabel("We'll also leave some content aimed for developers so they can take advatange of everything we leave at their disposal.") + + local Wiki = Menu:AddButton("Open the Wiki") + + function Wiki:DoClickInternal() + gui.OpenURL("https://github.com/Stooberton/ACF-3/wiki") + end + + Menu:AddLabel("Note: The wiki is still a work in progress, it'll get poblated as time passes.") +end + +ACF.AddOptionItem("About the Addon", "Online Wiki", "book_open", CreateMenu) From 57dd73c01a249d372eec96e35e67a21e2ee4756e Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sat, 14 Mar 2020 01:11:59 -0300 Subject: [PATCH 036/279] Added new engine class and engine registration functions - Added ACF.RegisterEngineClass function - Added ACF.RegisterEngine function, depends on the classes created by ACF.RegisterEngineClass - Used these new functions with all existing engines. --- lua/acf/base/sh_classes.lua | 55 ++++++ lua/acf/shared/engines/b4.lua | 78 ++++++++ lua/acf/shared/engines/b6.lua | 78 ++++++++ lua/acf/shared/engines/electric.lua | 137 ++++++++++++++ lua/acf/shared/engines/i2.lua | 42 +++++ lua/acf/shared/engines/i3.lua | 116 ++++++++++++ lua/acf/shared/engines/i4.lua | 116 ++++++++++++ lua/acf/shared/engines/i5.lua | 80 ++++++++ lua/acf/shared/engines/i6.lua | 116 ++++++++++++ lua/acf/shared/engines/radial.lua | 78 ++++++++ lua/acf/shared/engines/rotary.lua | 61 ++++++ lua/acf/shared/engines/single.lua | 60 ++++++ lua/acf/shared/engines/special.lua | 232 +++++++++++++++++++++++ lua/acf/shared/engines/turbine.lua | 278 ++++++++++++++++++++++++++++ lua/acf/shared/engines/v10.lua | 60 ++++++ lua/acf/shared/engines/v12.lua | 134 ++++++++++++++ lua/acf/shared/engines/v2.lua | 60 ++++++ lua/acf/shared/engines/v4.lua | 42 +++++ lua/acf/shared/engines/v6.lua | 99 ++++++++++ lua/acf/shared/engines/v8.lua | 116 ++++++++++++ 20 files changed, 2038 insertions(+) diff --git a/lua/acf/base/sh_classes.lua b/lua/acf/base/sh_classes.lua index eb5d09715..abd0d84bb 100644 --- a/lua/acf/base/sh_classes.lua +++ b/lua/acf/base/sh_classes.lua @@ -174,3 +174,58 @@ do -- Ammo type registration function return RegisterClass(ID, Base, Types) end end + +do -- Engine registration functions + ACF.Classes.Engines = ACF.Classes.Engines or {} + + local Engines = ACF.Classes.Engines + + function ACF.RegisterEngineClass(ID, Data) + if not ID then return end + if not Data then return end + + local Class = Engines[ID] + + if not Class then + Class = { + ID = ID, + Lookup = {}, + Items = {}, + Count = 0, + } + + Engines[ID] = Class + end + + for K, V in pairs(Data) do + Class[K] = V + end + end + + function ACF.RegisterEngine(ID, ClassID, Data) + if not ID then return end + if not ClassID then return end + if not Data then return end + if not Engines[ClassID] then return end + + local Class = Engines[ClassID] + local Engine = Class.Lookup[ID] + + if not Engine then + Engine = { + ID = ID, + Class = Class, + ClassID = ClassID, + EntClass = "acf_engine", + } + + Class.Count = Class.Count + 1 + Class.Items[Class.Count] = Engine + Class.Lookup[ID] = Engine + end + + for K, V in pairs(Data) do + Engine[K] = V + end + end +end diff --git a/lua/acf/shared/engines/b4.lua b/lua/acf/shared/engines/b4.lua index 8679e4a18..749234862 100644 --- a/lua/acf/shared/engines/b4.lua +++ b/lua/acf/shared/engines/b4.lua @@ -68,3 +68,81 @@ ACF_DefineEngine( "2.4-B4", { peakmaxrpm = 2650, limitrpm = 2800 } ) + +ACF.RegisterEngineClass("B4", { + Name = "Flat 4 Engine", +}) + +do + ACF.RegisterEngine("1.4-B4", "B4", { + Name = "1.4L Flat 4 Petrol", + Description = "Small air cooled flat four, most commonly found in nazi insects", + Model = "models/engines/b4small.mdl", + Sound = "acf_engines/b4_petrolsmall.wav", + Fuel = "Petrol", + Type = "GenericPetrol", + Mass = 60, + Torque = 105, + FlywheelMass = 0.06, + RPM = { + Idle = 600, + PeakMin = 2600, + PeakMax = 4200, + Limit = 4500, + }, + }) + + ACF.RegisterEngine("2.1-B4", "B4", { + Name = "2.1L Flat 4 Petrol", + Description = "Tuned up flat four, probably find this in things that go fast in a desert.", + Model = "models/engines/b4small.mdl", + Sound = "acf_engines/b4_petrolmedium.wav", + Fuel = "Petrol", + Type = "GenericPetrol", + Mass = 125, + Torque = 180, + FlywheelMass = 0.15, + RPM = { + Idle = 700, + PeakMin = 3000, + PeakMax = 4800, + Limit = 5000, + }, + }) + + ACF.RegisterEngine("2.4-B4", "B4", { + Name = "2.4L Flat 4 Multifuel", + Description = "Tiny military-grade multifuel. Heavy, but grunts hard.", + Model = "models/engines/b4small.mdl", + Sound = "acf_extra/vehiclefx/engines/coh/ba11.wav", + Fuel = "Multifuel", + Type = "GenericDiesel", + Mass = 135, + Torque = 248, + FlywheelMass = 0.4, + RPM = { + Idle = 550, + PeakMin = 1250, + PeakMax = 2650, + Limit = 2800, + }, + }) + + ACF.RegisterEngine("3.2-B4", "B4", { + Name = "3.2L Flat 4 Petrol", + Description = "Bored out fuckswindleton batshit flat four. Fuck yourself.", + Model = "models/engines/b4med.mdl", + Sound = "acf_engines/b4_petrollarge.wav", + Fuel = "Petrol", + Type = "GenericPetrol", + Mass = 210, + Torque = 252, + FlywheelMass = 0.15, + RPM = { + Idle = 900, + PeakMin = 3400, + PeakMax = 5500, + Limit = 6500 + }, + }) +end diff --git a/lua/acf/shared/engines/b6.lua b/lua/acf/shared/engines/b6.lua index 0e4492828..22addad09 100644 --- a/lua/acf/shared/engines/b6.lua +++ b/lua/acf/shared/engines/b6.lua @@ -69,3 +69,81 @@ ACF_DefineEngine( "15.8-B6", { peakmaxrpm = 4275, limitrpm = 4900 } ) + +ACF.RegisterEngineClass("B6", { + Name = "Flat 6 Engine", +}) + +do + ACF.RegisterEngine("2.8-B6", "B6", { + Name = "2.8L Flat 6 Petrol", + Description = "Car sized flat six engine, sporty and light", + Model = "models/engines/b6small.mdl", + Sound = "acf_engines/b6_petrolsmall.wav", + Fuel = "Petrol", + Type = "GenericPetrol", + Mass = 100, + Torque = 136, + FlywheelMass = 0.08, + RPM = { + Idle = 750, + PeakMin = 4300, + PeakMax = 6950, + Limit = 7250, + }, + }) + + ACF.RegisterEngine("5.0-B6", "B6", { + Name = "5.0L Flat 6 Petrol", + Description = "Sports car grade flat six, renown for their smooth operation and light weight", + Model = "models/engines/b6med.mdl", + Sound = "acf_engines/b6_petrolmedium.wav", + Fuel = "Petrol", + Type = "GenericPetrol", + Mass = 240, + Torque = 330, + FlywheelMass = 0.11, + RPM = { + Idle = 900, + PeakMin = 3500, + PeakMax = 6000, + Limit = 6800, + }, + }) + + ACF.RegisterEngine("8.3-B6", "B6", { + Name = "8.3L Flat 6 Multifuel", + Description = "Military-grade multifuel boxer engine. Although heavy, it is compact, durable, and has excellent performance under adverse conditions.", + Model = "models/engines/b6med.mdl", + Sound = "acf_engines/v8_diesel.wav", + Fuel = "Multifuel", + Type = "GenericDiesel", + Mass = 480, + Torque = 565, + FlywheelMass = 0.65, + RPM = { + Idle = 500, + PeakMin = 1900, + PeakMax = 3600, + Limit = 4200, + }, + }) + + ACF.RegisterEngine("15.8-B6", "B6", { + Name = "15.8L Flat 6 Petrol", + Description = "Monstrous aircraft-grade boxer with a high rev range biased powerband", + Model = "models/engines/b6large.mdl", + Sound = "acf_engines/b6_petrollarge.wav", + Fuel = "Petrol", + Type = "GenericPetrol", + Mass = 725, + Torque = 1100, + FlywheelMass = 1, + RPM = { + Idle = 620, + PeakMin = 2500, + PeakMax = 4275, + Limit = 4900, + }, + }) +end diff --git a/lua/acf/shared/engines/electric.lua b/lua/acf/shared/engines/electric.lua index 550d7ad85..6eb507158 100644 --- a/lua/acf/shared/engines/electric.lua +++ b/lua/acf/shared/engines/electric.lua @@ -137,3 +137,140 @@ ACF_DefineEngine( "Electric-Large-NoBatt", { iselec = true, flywheeloverride = 6000 } ) + +do -- Electric Motors + ACF.RegisterEngineClass("EL", { + Name = "Electric Motor", + Description = "Electric motors provide huge amounts of torque, but are very heavy.", + }) + + ACF.RegisterEngine("Electric-Small", "EL", { + Name = "Small Electric Motor", + Description = "A small electric motor, loads of torque, but low power.", + Model = "models/engines/emotorsmall.mdl", + Sound = "acf_engines/electric_small.wav", + Fuel = "Electric", + Type = "Electric", + Mass = 250, + Torque = 384, + FlywheelMass = 0.3, + IsElectric = true, + RPM = { + Idle = 10, + PeakMin = 1, + PeakMax = 1, + Limit = 10000, + Override = 5000, + }, + }) + + ACF.RegisterEngine("Electric-Medium", "EL", { + Name = "Medium Electric Motor", + Description = "A medium electric motor, loads of torque, but low power.", + Model = "models/engines/emotormed.mdl", + Sound = "acf_engines/electric_medium.wav", + Fuel = "Electric", + Type = "Electric", + Mass = 850, + Torque = 1152, + FlywheelMass = 1.5, + IsElectric = true, + RPM = { + Idle = 10, + PeakMin = 1, + PeakMax = 1, + Limit = 7000, + Override = 8000, + } + }) + + ACF.RegisterEngine("Electric-Large", "EL", { + Name = "Large Electric Motor", + Description = "A huge electric motor, loads of torque, but low power.", + Model = "models/engines/emotorlarge.mdl", + Sound = "acf_engines/electric_large.wav", + Fuel = "Electric", + Type = "Electric", + Mass = 1900, + Torque = 3360, + FlywheelMass = 11.2, + IsElectric = true, + RPM = { + Idle = 10, + PeakMin = 1, + PeakMax = 1, + Limit = 4500, + Override = 6000, + }, + }) +end + +do -- Electric Standalone Motors + ACF.RegisterEngineClass("EL-S", { + Name = "Electric Standalone Motor", + Description = "Electric motors provide huge amounts of torque, but are very heavy. Standalones also require external batteries.", + }) + + ACF.RegisterEngine("Electric-Small-NoBatt", "EL-S", { + Name = "Small Electric Standalone Motor", + Description = "A small standalone electric motor, loads of torque, but low power.", + Model = "models/engines/emotor-standalone-sml.mdl", + Sound = "acf_engines/electric_small.wav", + Fuel = "Electric", + Type = "Electric", + Mass = 125, + Torque = 384, + FlywheelMass = 0.3, + iselec = true, + RequiresFuel = true, + RPM = { + Idle = 10, + PeakMin = 1, + PeakMax = 1, + Limit = 10000, + Override = 5000, + } + }) + + ACF.RegisterEngine("Electric-Medium-NoBatt", "EL-S", { + Name = "Medium", + Description = "A medium standalone electric motor, loads of torque, but low power.", + Model = "models/engines/emotor-standalone-mid.mdl", + Sound = "acf_engines/electric_medium.wav", + Fuel = "Electric", + Type = "Electric", + Mass = 575, + Torque = 1152, + FlywheelMass = 1.5, + IsElectric = true, + RequiresFuel = true, + RPM = { + Idle = 10, + PeakMin = 1, + PeakMax = 1, + Limit = 7000, + Override = 8000, + }, + }) + + ACF.RegisterEngine( "Electric-Large-NoBatt", { + Name = "Large Electric Standalone Motor", + Description = "A huge standalone electric motor, loads of torque, but low power.", + Model = "models/engines/emotor-standalone-big.mdl", + Sound = "acf_engines/electric_large.wav", + Fuel = "Electric", + Type = "Electric", + Mass = 1500, + Torque = 3360, + FlywheelMass = 11.2, + IsElectric = true, + RequiresFuel = true, + RPM = { + Idle = 10, + PeakMin = 1, + PeakMax = 1, + Limit = 4500, + Override = 6000, + } + }) +end diff --git a/lua/acf/shared/engines/i2.lua b/lua/acf/shared/engines/i2.lua index c7d8752ff..51a91acf6 100644 --- a/lua/acf/shared/engines/i2.lua +++ b/lua/acf/shared/engines/i2.lua @@ -36,3 +36,45 @@ ACF_DefineEngine( "10.0-I2", { peakmaxrpm = 900, limitrpm = 1200 } ) + +ACF.RegisterEngineClass("I2", { + Name = "Inline 2 Engine", +}) + +do + ACF.RegisterEngine("0.8L-I2", "I2", { + Name = "0.8L I2 Diesel", + Description = "For when a 3 banger is still too bulky for your micro-needs.", + Model = "models/engines/inline2s.mdl", + Sound = "acf_engines/i4_diesel2.wav", + Fuel = "Diesel", + Type = "GenericDiesel", + Mass = 45, + Torque = 105, + FlywheelMass = 0.12, + RPM = { + Idle = 500, + PeakMin = 750, + PeakMax = 2450, + Limit = 2950, + } + }) + + ACF.RegisterEngine("10.0-I2", "I2", { + Name = "10.0L I2 Diesel", + Description = "TORQUE.", + Model = "models/engines/inline2b.mdl", + Sound = "acf_engines/vtwin_large.wav", + Fuel = "Diesel", + Type = "GenericDiesel", + Mass = 800, + Torque = 2000, + FlywheelMass = 7, + RPM = { + Idle = 350, + PeakMin = 450, + PeakMax = 900, + Limit = 1200, + } + }) +end diff --git a/lua/acf/shared/engines/i3.lua b/lua/acf/shared/engines/i3.lua index dadc32c77..4a49f142b 100644 --- a/lua/acf/shared/engines/i3.lua +++ b/lua/acf/shared/engines/i3.lua @@ -106,3 +106,119 @@ ACF_DefineEngine( "11.0-I3", { peakmaxrpm = 1800, limitrpm = 2000 } ) + +ACF.RegisterEngineClass("I3", { + Name = "Inline 3 Engine", +}) + +do -- Petrol Engines + ACF.RegisterEngine("1.2-I3", "I3", { + Name = "1.2L I3 Petrol", + Description = "Tiny microcar engine, efficient but weak.", + Model = "models/engines/inline3s.mdl", + Sound = "acf_engines/i4_petrolsmall2.wav", + Fuel = "Petrol", + Type = "GenericPetrol", + Mass = 40, + Torque = 95, + FlywheelMass = 0.05, + RPM = { + Idle = 1100, + PeakMin = 3300, + PeakMax = 5400, + Limit = 6000, + } + }) + + ACF.RegisterEngine("3.4-I3", "I3", { + Name = "3.4L I3 Petrol", + Description = "Short block engine for light utility use.", + Model = "models/engines/inline3m.mdl", + Sound = "acf_engines/i4_petrolmedium2.wav", + Fuel = "Petrol", + Type = "GenericPetrol", + Mass = 170, + Torque = 195, + FlywheelMass = 0.2, + RPM = { + Idle = 900, + PeakMin = 3500, + PeakMax = 6600, + Limit = 6800, + } + }) + + ACF.RegisterEngine("13.5-I3", "I3", { + Name = "13.5L I3 Petrol", + Description = "Short block light tank engine, likes sideways mountings.", + Model = "models/engines/inline3b.mdl", + Sound = "acf_engines/i4_petrollarge.wav", + Fuel = "Petrol", + Type = "GenericPetrol", + Mass = 500, + Torque = 715, + FlywheelMass = 3.7, + RPM = { + Idle = 500, + PeakMin = 1900, + PeakMax = 3500, + Limit = 3900, + } + }) +end + +do -- Diesel Engines + ACF.RegisterEngine("1.1-I3", "I3", { + Name = "1.1L I3 Diesel", + Description = "ATV grade 3-banger, enormous rev band but a choppy idle, great for light utility work.", + Model = "models/engines/inline3s.mdl", + Sound = "acf_engines/i4_diesel2.wav", + Fuel = "Diesel", + Type = "GenericDiesel", + Mass = 65, + Torque = 150, + FlywheelMass = 0.2, + RPM = { + Idle = 550, + PeakMin = 800, + PeakMax = 2500, + Limit = 3000, + } + }) + + ACF.RegisterEngine("2.8-I3", "I3", { + Name = "2.8L I3 Diesel", + Description = "Medium utility grade I3 diesel, for tractors", + Model = "models/engines/inline3m.mdl", + Sound = "acf_engines/i4_dieselmedium.wav", + Fuel = "Diesel", + Type = "GenericDiesel", + Mass = 200, + Torque = 290, + FlywheelMass = 1, + RPM = { + Idle = 600, + PeakMin = 1200, + PeakMax = 3600, + Limit = 3800 + } + }) + + ACF.RegisterEngine("11.0-I3", "I3", { + Name = "11.0L I3 Diesel", + Description = "Light tank duty engine, compact yet grunts hard.", + Model = "models/engines/inline3b.mdl", + Sound = "acf_engines/i4_diesellarge.wav", + Fuel = "Diesel", + Type = "GenericDiesel", + Mass = 650, + Torque = 1200, + FlywheelMass = 5, + RPM = { + Idle = 550, + PeakMin = 650, + PeakMax = 1800, + Limit = 2000 + } + }) +end \ No newline at end of file diff --git a/lua/acf/shared/engines/i4.lua b/lua/acf/shared/engines/i4.lua index 72f768462..f3c2d8c41 100644 --- a/lua/acf/shared/engines/i4.lua +++ b/lua/acf/shared/engines/i4.lua @@ -106,3 +106,119 @@ ACF_DefineEngine( "15.0-I4", { peakmaxrpm = 1800, limitrpm = 2100 } ) + +ACF.RegisterEngineClass("I4", { + Name = "Inline 4 Engine", +}) + +do -- Petrol Engines + ACF.RegisterEngine("1.5-I4", "I4", { + Name = "1.5L I4 Petrol", + Description = "Small car engine, not a whole lot of git.", + Model = "models/engines/inline4s.mdl", + Sound = "acf_engines/i4_petrolsmall2.wav", + Fuel = "Petrol", + Type = "GenericPetrol", + Mass = 50, + Torque = 90, + FlywheelMass = 0.06, + RPM = { + Idle = 900, + PeakMin = 4000, + PeakMax = 6500, + Limit = 7500, + } + }) + + ACF.RegisterEngine("3.7-I4", "I4", { + Name = "3.7L I4 Petrol", + Description = "Large inline 4, sees most use in light trucks.", + Model = "models/engines/inline4m.mdl", + Sound = "acf_engines/i4_petrolmedium2.wav", + Fuel = "Petrol", + Type = "GenericPetrol", + Mass = 200, + Torque = 240, + FlywheelMass = 0.2, + RPM = { + Idle = 900, + PeakMin = 3700, + PeakMax = 6000, + Limit = 6500 + } + }) + + ACF.RegisterEngine("16.0-I4", "I4", { + Name = "16.0L I4 Petrol", + Description = "Giant, thirsty I4 petrol, most commonly used in boats.", + Model = "models/engines/inline4l.mdl", + Sound = "acf_engines/i4_petrollarge.wav", + Fuel = "Petrol", + Type = "GenericPetrol", + Mass = 600, + Torque = 850, + FlywheelMass = 4, + RPM = { + Idle = 500, + PeakMin = 1750, + PeakMax = 3250, + Limit = 3500, + } + }) +end + +do -- Diesel Engines + ACF.RegisterEngine("1.6-I4", "I4", { + Name = "1.6L I4 Diesel", + Description = "Small and light diesel, for low power applications requiring a wide powerband.", + Model = "models/engines/inline4s.mdl", + Sound = "acf_engines/i4_diesel2.wav", + Fuel = "Diesel", + Type = "GenericDiesel", + Mass = 90, + Torque = 150, + FlywheelMass = 0.2, + RPM = { + Idle = 650, + PeakMin = 1000, + PeakMax = 3000, + Limit = 5000, + } + }) + + ACF.RegisterEngine("3.1-I4", "I4", { + Name = "3.1L I4 Diesel", + Description = "Light truck duty diesel, good overall grunt.", + Model = "models/engines/inline4m.mdl", + Sound = "acf_engines/i4_dieselmedium.wav", + Fuel = "Diesel", + Type = "GenericDiesel", + Mass = 250, + Torque = 320, + FlywheelMass = 1, + RPM = { + Idle = 500, + PeakMin = 1150, + PeakMax = 3500, + Limit = 4000, + } + }) + + ACF.RegisterEngine("15.0-I4", "I4", { + Name = "15.0L I4 Diesel", + Description = "Small boat sized diesel, with large amounts of torque.", + Model = "models/engines/inline4l.mdl", + Sound = "acf_engines/i4_diesellarge.wav", + Fuel = "Diesel", + Type = "GenericDiesel", + Mass = 800, + Torque = 1400, + FlywheelMass = 5, + RPM = { + Idle = 450, + PeakMin = 500, + PeakMax = 1800, + Limit = 2100, + } + }) +end diff --git a/lua/acf/shared/engines/i5.lua b/lua/acf/shared/engines/i5.lua index 0144db150..4c19127b2 100644 --- a/lua/acf/shared/engines/i5.lua +++ b/lua/acf/shared/engines/i5.lua @@ -72,3 +72,83 @@ ACF_DefineEngine( "4.1-I5", { peakmaxrpm = 3200, limitrpm = 3800 } ) + +ACF.RegisterEngineClass("I5", { + Name = "Inline 5 Engine", +}) + +do -- Petrol Engines + ACF.RegisterEngine("2.3-I5", "I5", { + Name = "2.3L I5 Petrol", + Description = "Sedan-grade 5-cylinder, solid and dependable.", + Model = "models/engines/inline5s.mdl", + Sound = "acf_engines/i5_petrolsmall.wav", + Fuel = "Petrol", + Type = "GenericPetrol", + Mass = 100, + Torque = 125, + FlywheelMass = 0.12, + RPM = { + Idle = 900, + PeakMin = 3600, + PeakMax = 5900, + Limit = 7000, + } + }) + + ACF.RegisterEngine("3.9-I5", "I5", { + Name = "3.9L I5 Petrol", + Description = "Truck sized inline 5, strong with a good balance of revs and torque.", + Model = "models/engines/inline5m.mdl", + Sound = "acf_engines/i5_petrolmedium.wav", + Fuel = "Petrol", + Type = "GenericPetrol", + Mass = 250, + Torque = 275, + FlywheelMass = 0.25, + RPM = { + Idle = 700, + PeakMin = 3700, + PeakMax = 6000, + Limit = 6500, + } + }) +end + +do -- Diesel Engines + ACF.RegisterEngine("2.9-I5", "I5", { + Name = "2.9L I5 Diesel", + Description = "Aging fuel-injected diesel, low in horsepower but very forgiving and durable.", + Model = "models/engines/inline5s.mdl", + Sound = "acf_engines/i5_dieselsmall2.wav", + Fuel = "Diesel", + Type = "GenericDiesel", + Mass = 130, + Torque = 180, + FlywheelMass = 0.5, + RPM = { + Idle = 500, + PeakMin = 900, + PeakMax = 2800, + Limit = 4200, + } + }) + + ACF.RegisterEngine("4.1-I5", "I5", { + Name = "4.1L I5 Diesel", + Description = "Heavier duty diesel, found in things that work hard.", + Model = "models/engines/inline5m.mdl", + Sound = "acf_engines/i5_dieselmedium.wav", + Fuel = "Diesel", + Type = "GenericDiesel", + Mass = 400, + Torque = 440, + FlywheelMass = 1.5, + RPM = { + Idle = 650, + PeakMin = 1000, + PeakMax = 3200, + Limit = 3800, + } + }) +end diff --git a/lua/acf/shared/engines/i6.lua b/lua/acf/shared/engines/i6.lua index a4ffab43e..0ac27ecc1 100644 --- a/lua/acf/shared/engines/i6.lua +++ b/lua/acf/shared/engines/i6.lua @@ -106,3 +106,119 @@ ACF_DefineEngine( "20.0-I6", { peakmaxrpm = 2100, limitrpm = 2600 } ) + +ACF.RegisterEngineClass("I6", { + Name = "Inline 6 Engine", +}) + +do -- Petrol Engines + ACF.RegisterEngine("2.2-I6", "I6", { + Name = "2.2L I6 Petrol", + Description = "Car sized I6 petrol with power in the high revs.", + Model = "models/engines/inline6s.mdl", + Sound = "acf_engines/l6_petrolsmall2.wav", + Fuel = "Petrol", + Type = "GenericPetrol", + Mass = 120, + Torque = 130, + FlywheelMass = 0.1, + RPM = { + Idle = 800, + PeakMin = 4000, + PeakMax = 6500, + Limit = 7200, + } + }) + + ACF.RegisterEngine("4.8-I6", "I6", { + Name = "4.8L I6 Petrol", + Description = "Light truck duty I6, good for offroad applications.", + Model = "models/engines/inline6m.mdl", + Sound = "acf_engines/l6_petrolmedium.wav", + Fuel = "Petrol", + Type = "GenericPetrol", + Mass = 300, + Torque = 360, + FlywheelMass = 0.2, + RPM = { + Idle = 900, + PeakMin = 3100, + PeakMax = 5000, + Limit = 5500, + } + }) + + ACF.RegisterEngine( "17.2-I6", { + Name = "17.2L I6 Petrol", + Description = "Heavy tractor duty petrol I6, decent overall powerband.", + Model = "models/engines/inline6l.mdl", + Sound = "acf_engines/l6_petrollarge2.wav", + Fuel = "Petrol", + Type = "GenericPetrol", + Mass = 850, + Torque = 960, + FlywheelMass = 2.5, + RPM = { + Idle = 800, + PeakMin = 2000, + PeakMax = 4000, + Limit = 4250, + } + }) +end + +do -- Diesel Engines + ACF.RegisterEngine("3.0-I6", "I6", { + Name = "3.0L I6 Diesel", + Description = "Car sized I6 diesel, good, wide powerband.", + Model = "models/engines/inline6s.mdl", + Sound = "acf_engines/l6_dieselsmall.wav", + Fuel = "Diesel", + Type = "GenericDiesel", + Mass = 150, + Torque = 200, + FlywheelMass = 0.5, + RPM = { + Idle = 650, + PeakMin = 1000, + PeakMax = 3000, + Limit = 4500, + } + }) + + ACF.RegisterEngine("6.5-I6", "I6", { + Name = "6.5L I6 Diesel", + Description = "Truck duty I6, good overall powerband and torque.", + Model = "models/engines/inline6m.mdl", + Sound = "acf_engines/l6_dieselmedium4.wav", + Fuel = "Diesel", + Type = "GenericDiesel", + Mass = 450, + Torque = 520, + FlywheelMass = 1.5, + RPM = { + Idle = 600, + PeakMin = 1000, + PeakMax = 3000, + Limit = 4000, + } + }) + + ACF.RegisterEngine("20.0-I6", "I6", { + Name = "20.0L I6 Diesel", + Description = "Heavy duty diesel I6, used in generators and heavy movers.", + Model = "models/engines/inline6l.mdl", + Sound = "acf_engines/l6_diesellarge2.wav", + Fuel = "Diesel", + Type = "GenericDiesel", + Mass = 1200, + Torque = 1700, + FlywheelMass = 8, + RPM = { + Idle = 400, + PeakMin = 650, + PeakMax = 2100, + Limit = 2600, + } + }) +end diff --git a/lua/acf/shared/engines/radial.lua b/lua/acf/shared/engines/radial.lua index b8a6a5769..1dd9e3637 100644 --- a/lua/acf/shared/engines/radial.lua +++ b/lua/acf/shared/engines/radial.lua @@ -69,3 +69,81 @@ ACF_DefineEngine( "24.0-R7", { peakmaxrpm = 3150, limitrpm = 3500 } ) + +ACF.RegisterEngineClass("R7", { + Name = "Radial 7 Engine", +}) + +do + ACF.RegisterEngine("3.8-R7", "R7", { + Name = "3.8L R7 Petrol", + Description = "A tiny, old worn-out radial.", + Model = "models/engines/radial7s.mdl", + Sound = "acf_engines/r7_petrolsmall.wav", + Fuel = "Petrol", + Type = "Radial", + Mass = 210, + Torque = 310, + FlywheelMass = 0.22, + RPM = { + Idle = 700, + PeakMin = 2600, + PeakMax = 4350, + Limit = 4800, + } + }) + + ACF.RegisterEngine("11.0-R7", "R7", { + Name = "11.0L R7 Petrol", + Description = "Mid range radial, thirsty and smooth.", + Model = "models/engines/radial7m.mdl", + Sound = "acf_engines/r7_petrolmedium.wav", + Fuel = "Petrol", + Type = "Radial", + Mass = 385, + Torque = 560, + FlywheelMass = 0.45, + RPM = { + Idle = 600, + PeakMin = 2300, + PeakMax = 3850, + Limit = 4400, + } + }) + + ACF.RegisterEngine("8.0-R7", "R7", { + Name = "8.0L R7 Diesel", + Description = "Heavy and with a narrow powerband, but efficient, and well-optimized to cruising.", + Model = "models/engines/radial7m.mdl", + Sound = "acf_engines/r7_petrolmedium.wav", + Fuel = "Multifuel", + Type = "GenericDiesel", + Mass = 450, + Torque = 800, + FlywheelMass = 1, + RPM = { + Idle = 400, + PeakMin = 2200, + PeakMax = 2500, + Limit = 2800, + } + }) + + ACF.RegisterEngine("24.0-R7", "R7", { + Name = "24.0L R7 Petrol", + Description = "Massive American radial monster, destined for fighter aircraft and heavy tanks.", + Model = "models/engines/radial7l.mdl", + Sound = "acf_engines/r7_petrollarge.wav", + Fuel = "Petrol", + Type = "Radial", + Mass = 952, + Torque = 1615, + FlywheelMass = 3.4, + RPM = { + Idle = 750, + PeakMin = 1900, + PeakMax = 3150, + Limit = 3500, + } + }) +end \ No newline at end of file diff --git a/lua/acf/shared/engines/rotary.lua b/lua/acf/shared/engines/rotary.lua index eae16226d..0f8b98ae9 100644 --- a/lua/acf/shared/engines/rotary.lua +++ b/lua/acf/shared/engines/rotary.lua @@ -51,3 +51,64 @@ ACF_DefineEngine( "2.0L-R", { peakmaxrpm = 8500, limitrpm = 9500 } ) + +ACF.RegisterEngineClass("R", { + Name = "Rotary Engine", + Description = "Wankels have rather wide powerbands, but are very high strung." +}) + +do + ACF.RegisterEngine("900cc-R", "R", { + Name = "0.9L Rotary", + Description = "Small 2-rotor Wankel, suited for yard use.", + Model = "models/engines/wankel_2_small.mdl", + Sound = "acf_engines/wankel_small.wav", + Fuel = "Petrol", + Type = "Wankel", + Mass = 50, + Torque = 78, + FlywheelMass = 0.06, + RPM = { + Idle = 950, + PeakMin = 4500, + PeakMax = 9000, + Limit = 9200, + } + }) + + ACF.RegisterEngine("1.3L-R", "R", { + Name = "1.3L Rotary", + Description = "Medium 2-rotor Wankel.", + Model = "models/engines/wankel_2_med.mdl", + Sound = "acf_engines/wankel_medium.wav", + Fuel = "Petrol", + Type = "Wankel", + Mass = 140, + Torque = 124, + FlywheelMass = 0.06, + RPM = { + Idle = 950, + PeakMin = 4100, + PeakMax = 8500, + Limit = 9000, + } + }) + + ACF.RegisterEngine("2.0L-R", "R", { + Name = "2.0L Rotary", + Description = "High performance 3-rotor Wankel.", + Model = "models/engines/wankel_3_med.mdl", + Sound = "acf_engines/wankel_large.wav", + Fuel = "Petrol", + Type = "Wankel", + Mass = 200, + Torque = 188, + FlywheelMass = 0.1, + RPM = { + Idle = 950, + PeakMin = 4100, + PeakMax = 8500, + Limit = 9500, + } + }) +end \ No newline at end of file diff --git a/lua/acf/shared/engines/single.lua b/lua/acf/shared/engines/single.lua index 72b3b6ee8..897863177 100644 --- a/lua/acf/shared/engines/single.lua +++ b/lua/acf/shared/engines/single.lua @@ -51,3 +51,63 @@ ACF_DefineEngine( "1.3-I1", { peakmaxrpm = 6000, limitrpm = 6700 } ) + +ACF.RegisterEngineClass("I1", { + Name = "Single Cylinder Engine", +}) + +do + ACF.RegisterEngine("0.25-I1", "I1", { + Name = "250cc Single Cylinder", + Description = "Tiny bike engine.", + model = "models/engines/1cylsml.mdl", + Sound = "acf_engines/i1_small.wav", + Fuel = "Petrol", + Type = "GenericPetrol", + Mass = 15, + Torque = 20, + FlywheelMass = 0.005, + RPM = { + Idle = 1200, + PeakMin = 4000, + PeakMax = 6500, + Limit = 7500, + } + }) + + ACF.RegisterEngine("0.5-I1", "I1", { + Name = "500cc Single Cylinder", + Description = "Large single cylinder bike engine.", + Model = "models/engines/1cylmed.mdl", + Sound = "acf_engines/i1_medium.wav", + Fuel = "Petrol", + Type = "GenericPetrol", + Mass = 20, + Torque = 40, + FlywheelMass = 0.005, + RPM = { + Idle = 900, + PeakMin = 4300, + PeakMax = 7000, + Limit = 8000, + } + }) + + ACF.RegisterEngine("1.3-I1", "I1", { + Name = "1300cc Single Cylinder", + Description = "Ridiculously large single cylinder engine, seriously what the fuck.", + Model = "models/engines/1cylbig.mdl", + Sound = "acf_engines/i1_large.wav", + Fuel = "Petrol", + Type = "GenericPetrol", + Mass = 50, + Torque = 90, + FlywheelMass = 0.1, + RPM = { + Idle = 600, + PeakMin = 3600, + PeakMax = 6000, + Limit = 6700, + } + }) +end \ No newline at end of file diff --git a/lua/acf/shared/engines/special.lua b/lua/acf/shared/engines/special.lua index 8380741cf..fd4f636e7 100644 --- a/lua/acf/shared/engines/special.lua +++ b/lua/acf/shared/engines/special.lua @@ -201,3 +201,235 @@ ACF_DefineEngine( "3.0-V12", { limitrpm = 12500 } ) +ACF.RegisterEngineClass("SP", { + Name = "Special Engine", +}) + +do -- Special Rotary Engines + ACF.RegisterEngine("2.6L-Wankel", "SP", { + Name = "2.6L Rotary", + Description = "4 rotor racing Wankel, high revving and high strung.", + Model = "models/engines/wankel_4_med.mdl", + Sound = "acf_engines/wankel_large.wav", + Fuel = "Petrol", + Type = "Wankel", + Mass = 260, + Torque = 250, + FlywheelMass = 0.11, + RequiresFuel = true, + RPM = { + Idle = 1200, + PeakMin = 4500, + PeakMax = 9000, + Limit = 9500, + } + }) +end + +do -- Special I2 Engines + ACF.RegisterEngine("0.9L-I2", "SP", { + Name = "0.9L I2 Petrol", + Description = "Turbocharged inline twin engine that delivers surprising pep for its size.", + Model = "models/engines/inline2s.mdl", + Sound = "acf_extra/vehiclefx/engines/ponyengine.wav", + Fuel = "Petrol", + Type = "GenericPetrol", + Mass = 60, + Torque = 116, + FlywheelMass = 0.085, + RequiresFuel = true, + RPM = { + Idle = 750, + PeakMin = 3125, + PeakMax = 5100, + Limit = 6000, + } + }) +end + +do -- Special I4 Engines + ACF.RegisterEngine("1.0L-I4", "SP", { + Name = "1.0L I4 Petrol", + Description = "Tiny I4 designed for racing bikes. Doesn't pack much torque, but revs ludicrously high.", + Model = "models/engines/inline4s.mdl", + Sound = "acf_extra/vehiclefx/engines/l4/mini_onhigh.wav", + Fuel = "Petrol", + Type = "GenericPetrol", + Mass = 78, + Torque = 68, + FlywheelMass = 0.031, + RequiresFuel = true, + Pitch = 0.75, + RPM = { + Idle = 1200, + PeakMin = 7500, + PeakMax = 11500, + Limit = 12000, + } + }) + + ACF.RegisterEngine("1.9L-I4", "SP", { + Name = "1.9L I4 Petrol", + Description = "Supercharged racing 4 cylinder, most of the power in the high revs.", + Model = "models/engines/inline4s.mdl", + Sound = "acf_engines/i4_special.wav", + Fuel = "Petrol", + Type = "GenericPetrol", + Mass = 150, + Torque = 176, + FlywheelMass = 0.06, + RequiresFuel = true, + RPM = { + Idle = 950, + PeakMin = 5200, + PeakMax = 8500, + Limit = 9000, + } + }) +end + +do -- Special V4 Engines + ACF.RegisterEngine("1.8L-V4", "SP", { + Name = "1.8L V4 Petrol", + Description = "Naturally aspirated rally-tuned V4 with enlarged bore and stroke.", + Model = "models/engines/v4s.mdl", + Sound = "acf_extra/vehiclefx/engines/l4/elan_onlow.wav", + Fuel = "Petrol", + Type = "GenericPetrol", + Mass = 92, + Torque = 124.8, + FlywheelMass = 0.04, + RequiresFuel = true, + RPM = { + Idle = 900, + PeakMin = 4600, + PeakMax = 7000, + Limit = 7500, + } + }) +end + +do -- Special I6 Engines + ACF.RegisterEngine("3.8-I6", "SP", { + Name = "3.8L I6 Petrol", + Description = "Large racing straight six, powerful and high revving, but lacking in torque.", + Model = "models/engines/inline6m.mdl", + Sound = "acf_engines/l6_special.wav", + Fuel = "Petrol", + Type = "GenericPetrol", + Mass = 180, + Torque = 224, + FlywheelMass = 0.1, + RequiresFuel = true, + RPM = { + Idle = 1100, + PeakMin = 5200, + PeakMax = 8500, + Limit = 9000, + } + }) +end + +do -- Special V6 Engines + ACF.RegisterEngine("2.4L-V6", "SP", { + Name = "2.4L V6 Petrol", + Description = "Although the cast iron engine block is fairly weighty, this tiny v6 makes up for it with impressive power. The unique V angle allows uncharacteristically high RPM for a V6.", + Model = "models/engines/v6small.mdl", + Sound = "acf_extra/vehiclefx/engines/l6/capri_onmid.wav", + Fuel = "Petrol", + Type = "GenericPetrol", + Mass = 134, + Torque = 172, + FlywheelMass = 0.075, + RequiresFuel = true, + RPM = { + Idle = 950, + PeakMin = 4500, + PeakMax = 7100, + Limit = 8000, + } + }) +end + +do -- Special V8 Engines + ACF.RegisterEngine("2.9-V8", "SP", { + Name = "2.9L V8 Petrol", + Description = "Racing V8, very high revving and loud", + Model = "models/engines/v8s.mdl", + Sound = "acf_engines/v8_special.wav", + Fuel = "Petrol", + Type = "GenericPetrol", + Mass = 180, + Torque = 200, + FlywheelMass = 0.075, + RequiresFuel = true, + RPM = { + Idle = 1000, + PeakMin = 5500, + PeakMax = 9000, + Limit = 10000, + } + }) + + ACF.RegisterEngine("7.2-V8", "SP", { + Name = "7.2L V8 Petrol", + Description = "Very high revving, glorious v8 of ear rapetasticalness.", + Model = "models/engines/v8m.mdl", + Sound = "acf_engines/v8_special2.wav", + Fuel = "Petrol", + Type = "GenericPetrol", + Mass = 400, + Torque = 340, + FlywheelMass = 0.15, + RequiresFuel = true, + RPM = { + Idle = 1000, + PeakMin = 5000, + PeakMax = 8000, + Limit = 8500, + } + }) +end + +do -- Special V10 Engines + ACF.RegisterEngine("5.3-V10", "SP", { + Name = "5.3L V10 Special", + Description = "Extreme performance v10", + Model = "models/engines/v10sml.mdl", + Sound = "acf_engines/v10_special.wav", + Fuel = "Petrol", + Type = "GenericPetrol", + Mass = 300, + Torque = 320, + FlywheelMass = 0.15, + RequiresFuel = true, + RPM = { + Idle = 1100, + PeakMin = 5750, + PeakMax = 8000, + Limit = 9000, + } + }) +end + +do -- Special V12 Engines + ACF.RegisterEngine("3.0-V12", "SP", { + Name = "3.0L V12 Petrol", + Description = "A purpose-built racing v12, not known for longevity.", + Model = "models/engines/v12s.mdl", + Sound = "acf_extra/vehiclefx/engines/v12/gtb4_onmid.wav", + Fuel = "Petrol", + Type = "GenericPetrol", + Mass = 175, + Torque = 248, + FlywheelMass = 0.1, + RequiresFuel = true, + Pitch = 0.85, + RPM = { + Idle = 1200, + PeakMin = 6875, + PeakMax = 11000, + Limit = 12500, + } + }) +end diff --git a/lua/acf/shared/engines/turbine.lua b/lua/acf/shared/engines/turbine.lua index 0f5972351..f34aee4cf 100644 --- a/lua/acf/shared/engines/turbine.lua +++ b/lua/acf/shared/engines/turbine.lua @@ -255,4 +255,282 @@ ACF_DefineEngine( "Turbine-Large-Ground-Trans", { pitch = 1.35 } ) +ACF.RegisterEngineClass("GT", { + Name = "Gas Turbine", + Description = "These turbines are optimized for aero use due to them being powerful but suffering from poor throttle response and fuel consumption." +}) +do -- Forward-facing Gas Turbines + ACF.RegisterEngine("Turbine-Small", "GT", { + Name = "Gas Turbine, Small", + Description = "A small gas turbine, high power and a very wide powerband.", + Model = "models/engines/gasturbine_s.mdl", + Sound = "acf_engines/turbine_small.wav", + Fuel = "Multifuel", + Type = "Turbine", + Mass = 200, + Torque = 550, + FlywheelMass = 2.9, + RequiresFuel = true, + IsElectric = true, + RPM = { + Idle = 1400, + PeakMin = 1000, + PeakMax = 1500, + Limit = 10000, + Override = 4167, + } + }) + + ACF.RegisterEngine("Turbine-Medium", "GT", { + Name = "Gas Turbine, Medium", + Description = "A medium gas turbine, moderate power but a very wide powerband.", + Model = "models/engines/gasturbine_m.mdl", + Sound = "acf_engines/turbine_medium.wav", + Fuel = "Multifuel", + Type = "Turbine", + Mass = 400, + Torque = 813, + FlywheelMass = 4.3, + RequiresFuel = true, + IsElectric = true, + RPM = { + Idle = 1800, + PeakMin = 1200, + PeakMax = 1800, + Limit = 12000, + Override = 5000, + } + }) + + ACF.RegisterEngine("Turbine-Large", "GT", { + Name = "Gas Turbine, Large", + Description = "A large gas turbine, powerful with a wide powerband.", + Model = "models/engines/gasturbine_l.mdl", + Sound = "acf_engines/turbine_large.wav", + Fuel = "Multifuel", + Type = "Turbine", + Mass = 1100, + Torque = 1990, + FlywheelMass = 10.5, + RequiresFuel = true, + IsElectric = true, + RPM = { + Idle = 2000, + PeakMin = 1350, + PeakMax = 2025, + Limit = 13500, + Override = 5625, + } + }) +end + +do -- Transaxial Gas Turbines + ACF.RegisterEngine("Turbine-Small-Trans", "GT", { + Name = "Gas Turbine, Small, Transaxial", + Description = "A small gas turbine, high power and a very wide powerband. Outputs to the side instead of rear.", + Model = "models/engines/turbine_s.mdl", + Sound = "acf_engines/turbine_small.wav", + Fuel = "Multifuel", + Type = "Turbine", + Mass = 160, + Torque = 440, + FlywheelMass = 2.3, + RequiresFuel = true, + IsElectric = true, + IsTrans = true, + RPM = { + Idle = 1400, + PeakMin = 1000, + PeakMax = 1500, + Limit = 10000, + Override = 4167, + } + }) + + ACF.RegisterEngine("Turbine-Medium-Trans", "GT", { + Name = "Gas Turbine, Medium, Transaxial", + Description = "A medium gas turbine, moderate power but a very wide powerband. Outputs to the side instead of rear.", + Model = "models/engines/turbine_m.mdl", + Sound = "acf_engines/turbine_medium.wav", + Fuel = "Multifuel", + Type = "Turbine", + Mass = 320, + Torque = 650, + FlywheelMass = 3.4, + RequiresFuel = true, + IsElectric = true, + IsTrans = true, + RPM = { + Idle = 1800, + PeakMin = 1200, + PeakMax = 1800, + Limit = 12000, + Override = 5000, + } + }) + + ACF.RegisterEngine("Turbine-Large-Trans", "GT", { + Name = "Gas Turbine, Large, Transaxial", + Description = "A large gas turbine, powerful with a wide powerband. Outputs to the side instead of rear.", + Model = "models/engines/turbine_l.mdl", + Sound = "acf_engines/turbine_large.wav", + Fuel = "Multifuel", + Type = "Turbine", + Mass = 880, + Torque = 1592, + FlywheelMass = 8.4, + RequiresFuel = true, + IsElectric = true, + IsTrans = true, + RPM = { + Idle = 2000, + PeakMin = 1350, + PeakMax = 2025, + Limit = 13500, + Override = 5625, + } + }) +end + +ACF.RegisterEngineClass("GGT", { + Name = "Ground Gas Turbine", + Description = "Ground-use turbines have excellent low-rev performance and are deceptively powerful. However, they have sluggish throttle response, high gearbox demands, high fuel usage, and low tolerance to damage." +}) + +do -- Forward-facing Ground Gas Turbines + ACF.RegisterEngine("Turbine-Ground-Small", "GGT", { + Name = "Ground Gas Turbine, Small", + Description = "A small gas turbine, fitted with ground-use air filters and tuned for ground use.", + Model = "models/engines/gasturbine_s.mdl", + Sound = "acf_engines/turbine_small.wav", + Fuel = "Multifuel", + Type = "Radial", + Mass = 350, + Torque = 800, + FlywheelMass = 14.3, + RequiresFuel = true, + IsElectric = true, + RPM = { + Idle = 700, + PeakMin = 1000, + PeakMax = 1350, + Limit = 3000, + Override = 1667, + } + }) + + ACF.RegisterEngine("Turbine-Ground-Medium", "GGT", { + Name = "Ground Gas Turbine, Medium", + Description = "A medium gas turbine, fitted with ground-use air filters and tuned for ground use.", + Model = "models/engines/gasturbine_m.mdl", + Sound = "acf_engines/turbine_medium.wav", + Fuel = "Multifuel", + Type = "Radial", --This is done to give proper fuel consumption and make the turbines not instant-torque from idle + Mass = 600, + Torque = 1200, + FlywheelMass = 29.6, + RequiresFuel = true, + IsElectric = true, + Pitch = 1.15, + RPM = { + Idle = 600, + PeakMin = 1500, + PeakMax = 2000, + Limit = 3000, + Override = 1450, + } + }) + + ACF.RegisterEngine("Turbine-Ground-Large", "GGT", { + Name = "Ground Gas Turbine, Large", + Description = "A large gas turbine, fitted with ground-use air filters and tuned for ground use.", + Model = "models/engines/gasturbine_l.mdl", + Sound = "acf_engines/turbine_large.wav", + Fuel = "Multifuel", + Type = "Radial", + Mass = 1650, + Torque = 4000, + FlywheelMass = 75, + RequiresFuel = true, + IsElectric = true, + Pitch = 1.35, + RPM = { + Idle = 500, + PeakMin = 1000, + PeakMax = 1250, + Limit = 3000, + Override = 1250, + } + }) +end + +do -- Transaxial Ground Gas Turbines + ACF.RegisterEngine("Turbine-Small-Ground-Trans", "GGT", { + Name = "Ground Gas Turbine, Small, Transaxial", + Description = "A small gas turbine fitted with ground-use air filters and tuned for ground use. Outputs to the side instead of rear.", + Model = "models/engines/turbine_s.mdl", + Sound = "acf_engines/turbine_small.wav", + Fuel = "Multifuel", + Type = "Radial", + Mass = 280, + Torque = 600, + FlywheelMass = 11.4, + RequiresFuel = true, + IsElectric = true, + IsTrans = true, + RPM = { + Idle = 700, + PeakMin = 1000, + PeakMax = 1350, + Limit = 3000, + Override = 1667, + } + }) + + ACF.RegisterEngine("Turbine-Medium-Ground-Trans", "GGT", { + Name = "Ground Gas Turbine, Medium, Transaxial", + Description = "A medium gas turbine fitted with ground-use air filters and tuned for ground use. Outputs to the side instead of rear.", + Model = "models/engines/turbine_m.mdl", + Sound = "acf_engines/turbine_medium.wav", + Fuel = "Multifuel", + Type = "Radial", + Mass = 480, + Torque = 900, + FlywheelMass = 23.7, + RequiresFuel = true, + IsElectric = true, + IsTrans = true, + Pitch = 1.15, + RPM = { + Idle = 600, + PeakMin = 1500, + PeakMax = 2000, + Limit = 3000, + Override = 1450, + } + }) + + ACF.RegisterEngine("Turbine-Large-Ground-Trans", "GGT", { + Name = "Ground Gas Turbine, Large, Transaxial", + Description = "A large gas turbine fitted with ground-use air filters and tuned for ground use. Outputs to the side instead of rear.", + Model = "models/engines/turbine_l.mdl", + Sound = "acf_engines/turbine_large.wav", + Fuel = "Multifuel", + Type = "Radial", + Mass = 1320, + Torque = 3000, + FlywheelMass = 60, + RequiresFuel = true, + IsElectric = true, + IsTrans = true, + Pitch = 1.35, + RPM = { + Idle = 500, + PeakMin = 1000, + PeakMax = 1250, + Limit = 3000, + Override = 1250, + } + }) +end diff --git a/lua/acf/shared/engines/v10.lua b/lua/acf/shared/engines/v10.lua index 99da94f01..fd19e5f23 100644 --- a/lua/acf/shared/engines/v10.lua +++ b/lua/acf/shared/engines/v10.lua @@ -50,3 +50,63 @@ ACF_DefineEngine( "22.0-V10", { peakmaxrpm = 1900, limitrpm = 2500 } ) + +ACF.RegisterEngineClass("V10", { + Name = "V10 Engine", +}) + +do + ACF.RegisterEngine("4.3-V10", "V10", { + Name = "4.3L V10 Petrol", + Description = "Small-block V-10 gasoline engine, great for powering a hot rod lincoln", + Model = "models/engines/v10sml.mdl", + Sound = "acf_engines/v10_petrolsmall.wav", + Fuel = "Petrol", + Type = "GenericPetrol", + Mass = 160, + Torque = 288, + FlywheelMass = 0.2, + RPM = { + Idle = 900, + PeakMin = 3500, + PeakMax = 5800, + Limit = 6250, + } + }) + + ACF.RegisterEngine("8.0-V10", "V10", { + Name = "8.0L V10 Petrol", + Description = "Beefy 10-cylinder gas engine, gets 9 kids to soccer practice", + Model = "models/engines/v10med.mdl", + Sound = "acf_engines/v10_petrolmedium.wav", + Fuel = "Petrol", + Type = "GenericPetrol", + Mass = 300, + Torque = 490, + FlywheelMass = 0.5, + RPM = { + Idle = 750, + PeakMin = 3400, + PeakMax = 5500, + Limit = 6500, + } + }) + + ACF.RegisterEngine("22.0-V10", "V10", { + Name = "22.0L V10 Multifuel", + Description = "Heavy multifuel V-10, gearbox-shredding torque but very heavy.", + Model = "models/engines/v10big.mdl", + Sound = "acf_engines/v10_diesellarge.wav", + Fuel = "Multifuel", + Type = "GenericDiesel", + Mass = 1600, + Torque = 2605, + FlywheelMass = 5, + RPM = { + Idle = 525, + PeakMin = 750, + PeakMax = 1900, + Limit = 2500, + } + }) +end diff --git a/lua/acf/shared/engines/v12.lua b/lua/acf/shared/engines/v12.lua index 038c7f97f..010094c51 100644 --- a/lua/acf/shared/engines/v12.lua +++ b/lua/acf/shared/engines/v12.lua @@ -123,3 +123,137 @@ ACF_DefineEngine( "13.0-V12", { peakmaxrpm = 4000, limitrpm = 4250 } ) + +ACF.RegisterEngineClass("V12", { + Name = "V12 Engine", +}) + +do -- Petrol Engines + ACF.RegisterEngine("4.6-V12", "V12", { + Name = "4.6L V12 Petrol", + Description = "An elderly racecar engine; low on torque, but plenty of power", + Model = "models/engines/v12s.mdl", + Sound = "acf_engines/v12_petrolsmall.wav", + Fuel = "Petrol", + Type = "GenericPetrol", + Mass = 188, + Torque = 235, + FlywheelMass = 0.2, + RPM = { + Idle = 1000, + PeakMin = 4500, + PeakMax = 7500, + Limit = 8000, + } + }) + + ACF.RegisterEngine("7.0-V12", "V12", { + Name = "7.0L V12 Petrol", + Description = "A high end V12; primarily found in very expensive cars", + Model = "models/engines/v12m.mdl", + Sound = "acf_engines/v12_petrolmedium.wav", + Fuel = "Petrol", + Type = "GenericPetrol", + Mass = 360, + Torque = 500, + FlywheelMass = 0.45, + RPM = { + Idle = 800, + PeakMin = 3600, + PeakMax = 6000, + Limit = 7500, + } + }) + + ACF.RegisterEngine("13.0-V12", "V12", { + Name = "13.0L V12 Petrol", + Description = "Thirsty gasoline v12, good torque and power for medium applications.", + Model = "models/engines/v12m.mdl", + Sound = "acf_engines/v12_special.wav", + Fuel = "Petrol", + Type = "GenericPetrol", + Mass = 520, + Torque = 660, + FlywheelMass = 1, + RPM = { + Idle = 700, + PeakMin = 2500, + PeakMax = 4000, + Limit = 4250, + } + }) + + ACF.RegisterEngine("23.0-V12", "V12", { + Name = "23.0L V12 Petrol", + Description = "A large, thirsty gasoline V12, found in early cold war tanks", + Model = "models/engines/v12l.mdl", + Sound = "acf_engines/v12_petrollarge.wav", + Fuel = "Petrol", + Type = "GenericPetrol", + Mass = 1350, + Torque = 1925, + FlywheelMass = 5, + RPM = { + Idle = 600, + PeakMin = 1500, + PeakMax = 3000, + Limit = 3250, + } + }) +end + +do -- Diesel Engines + ACF.RegisterEngine("4.0-V12", "V12", { + Name = "4.0L V12 Diesel", + Description = "Reliable truck-duty diesel; a lot of smooth torque", + Model = "models/engines/v12s.mdl", + Sound = "acf_engines/v12_dieselsmall.wav", + Fuel = "Diesel", + Type = "GenericDiesel", + Mass = 305, + Torque = 375, + FlywheelMass = 0.475, + RPM = { + Idle = 650, + PeakMin = 1200, + PeakMax = 3800, + Limit = 4000, + } + }) + + ACF.RegisterEngine("9.2-V12", "V12", { + Name = "9.2L V12 Diesel", + Description = "High torque light-tank V12, used mainly for vehicles that require balls", + Model = "models/engines/v12m.mdl", + Sound = "acf_engines/v12_dieselmedium.wav", + Fuel = "Diesel", + Type = "GenericDiesel", + Mass = 600, + Torque = 750, + FlywheelMass = 2.5, + RPM = { + Idle = 675, + PeakMin = 1100, + PeakMax = 3300, + Limit = 3500, + } + }) + + ACF.RegisterEngine("21.0-V12", "V12", { + Name = "21.0L V12 Diesel", + Description = "AVDS-1790-2 tank engine; massively powerful, but enormous and heavy", + Model = "models/engines/v12l.mdl", + Sound = "acf_engines/v12_diesellarge.wav", + Fuel = "Diesel", + Type = "GenericDiesel", + Mass = 1800, + Torque = 3560, + FlywheelMass = 7, + RPM = { + Idle = 400, + PeakMin = 500, + PeakMax = 1500, + Limit = 2500, + } + }) +end diff --git a/lua/acf/shared/engines/v2.lua b/lua/acf/shared/engines/v2.lua index fd4cc4c29..f0fe48dc0 100644 --- a/lua/acf/shared/engines/v2.lua +++ b/lua/acf/shared/engines/v2.lua @@ -51,3 +51,63 @@ ACF_DefineEngine( "2.4-V2", { peakmaxrpm = 5500, limitrpm = 6000 } ) + +ACF.RegisterEngineClass("V2", { + Name = "V-Twin Engine", +}) + +do -- Petrol Engines + ACF.RegisterEngine("0.6-V2", "V2", { + Name = "600cc V-Twin", + Description = "Twin cylinder bike engine, torquey for its size", + Model = "models/engines/v-twins2.mdl", + Sound = "acf_engines/vtwin_small.wav", + Fuel = "Petrol", + Type = "GenericPetrol", + Mass = 30, + Torque = 50, + FlywheelMass = 0.01, + RPM = { + Idle = 900, + PeakMin = 4000, + PeakMax = 6500, + Limit = 7000, + } + }) + + ACF.RegisterEngine("1.2-V2", "V2", { + Name = "1200cc V-Twin", + Description = "Large displacement vtwin engine", + Model = "models/engines/v-twinm2.mdl", + Sound = "acf_engines/vtwin_medium.wav", + Fuel = "Petrol", + Type = "GenericPetrol", + Mass = 50, + Torque = 85, + FlywheelMass = 0.02, + RPM = { + Idle = 725, + PeakMin = 3300, + PeakMax = 5500, + Limit = 6250, + } + }) + + ACF.RegisterEngine("2.4-V2", "V2", { + Name = "2400cc V-Twin", + Description = "Huge fucking Vtwin 'MURRICA FUCK YEAH", + Model = "models/engines/v-twinl2.mdl", + Sound = "acf_engines/vtwin_large.wav", + Fuel = "Petrol", + Type = "GenericPetrol", + Mass = 100, + Torque = 160, + FlywheelMass = 0.075, + RPM = { + Idle = 900, + PeakMin = 3300, + PeakMax = 5500, + Limit = 6000, + } + }) +end diff --git a/lua/acf/shared/engines/v4.lua b/lua/acf/shared/engines/v4.lua index f027dfa98..d7fe6992d 100644 --- a/lua/acf/shared/engines/v4.lua +++ b/lua/acf/shared/engines/v4.lua @@ -36,3 +36,45 @@ ACF_DefineEngine( "3.3L-V4", { peakmaxrpm = 3100, limitrpm = 3900 } ) + +ACF.RegisterEngineClass("V4", { + Name = "V4 Engine", +}) + +do -- Diesel Engines + ACF.RegisterEngine("1.9L-V4", "V4", { + Name = "1.9L V4 Diesel", + Description = "Torquey little lunchbox; for those smaller vehicles that don't agree with petrol powerbands", + Model = "models/engines/v4s.mdl", + Sound = "acf_engines/i4_diesel2.wav", + Fuel = "Diesel", + Type = "GenericDiesel", + Mass = 110, + Torque = 165, + FlywheelMass = 0.3, + RPM = { + Idle = 650, + PeakMin = 950, + PeakMax = 3000, + Limit = 4000, + } + }) + + ACF.RegisterEngine("3.3L-V4", "V4", { + Name = "3.3L V4 Diesel", + Description = "Compact cube of git; for moderate utility applications", + Model = "models/engines/v4m.mdl", + Sound = "acf_engines/i4_dieselmedium.wav", + Fuel = "Diesel", + Type = "GenericDiesel", + Mass = 275, + Torque = 480, + FlywheelMass = 1.05, + RPM = { + Idle = 600, + PeakMin = 1050, + PeakMax = 3100, + Limit = 3900, + } + }) +end diff --git a/lua/acf/shared/engines/v6.lua b/lua/acf/shared/engines/v6.lua index c5b087bda..d96925848 100644 --- a/lua/acf/shared/engines/v6.lua +++ b/lua/acf/shared/engines/v6.lua @@ -85,3 +85,102 @@ ACF_DefineEngine( "15.0-V6", { peakmaxrpm = 1950, limitrpm = 3100 } ) + +ACF.RegisterEngineClass("V6", { + Name = "V6 Engine", + Description = "V6s are more torquey than the Boxer and Inline 6s but suffer in power." +}) + +do -- Petrol Engines + ACF.RegisterEngine("3.6-V6", "V6", { + Name = "3.6L V6 Petrol", + Description = "Meaty Car sized V6, lots of torque.", + Model = "models/engines/v6small.mdl", + Sound = "acf_engines/v6_petrolsmall.wav", + Fuel = "Petrol", + Type = "GenericPetrol", + Mass = 190, + Torque = 253, + FlywheelMass = 0.25, + RPM = { + Idle = 700, + PeakMin = 2200, + PeakMax = 3500, + Limit = 5000, + } + }) + + ACF.RegisterEngine("6.2-V6", "V6", { + Name = "6.2L V6 Petrol", + Description = "Heavy duty 6V71 v6, throatier than an LA whore, but loaded with torque.", + Model = "models/engines/v6med.mdl", + Sound = "acf_engines/v6_petrolmedium.wav", + Fuel = "Petrol", + Type = "GenericPetrol", + Mass = 360, + Torque = 472, + FlywheelMass = 0.45, + RPM = { + Idle = 800, + PeakMin = 2200, + PeakMax = 3600, + Limit = 5000, + } + }) + + ACF.RegisterEngine("12.0-V6", "V6", { + Name = "12.0L V6 Petrol", + Description = "Fuck duty V6, guts ripped from god himself diluted in salt and shaped into an engine.", + Model = "models/engines/v6large.mdl", + Sound = "acf_engines/v6_petrollarge.wav", + Fuel = "Petrol", + Type = "GenericPetrol", + Mass = 675, + Torque = 1445, + FlywheelMass = 4, + RPM = { + Idle = 600, + PeakMin = 1575, + PeakMax = 2650, + Limit = 3800, + } + }) +end + +do -- Diesel Engines + ACF.RegisterEngine("5.2-V6", "V6", { + Name = "5.2L V6 Diesel", + Description = "Light AFV-grade two-stroke diesel, high output but heavy.", + Model = "models/engines/v6med.mdl", + Sound = "acf_engines/i5_dieselmedium.wav", + Fuel = "Diesel", + Type = "GenericDiesel", + Mass = 520, + Torque = 485, + FlywheelMass = 0.8, + RPM = { + Idle = 650, + PeakMin = 1800, + PeakMax = 4200, + Limit = 4300, + } + }) + + ACF.RegisterEngine("15.0-V6", "V6", { + Name = "15.0L V6 Diesel", + Description = "Powerful military-grade large V6, with impressive output. Well suited to medium-sized AFVs.", + Model = "models/engines/v6large.mdl", + Sound = "acf_engines/v6_diesellarge.wav", + Fuel = "Diesel", + Type = "GenericDiesel", + Mass = 900, + Torque = 1767, + FlywheelMass = 6.4, + RPM = { + Idle = 400, + PeakMin = 1150, + PeakMax = 1950, + Limit = 3100, + } + }) +end diff --git a/lua/acf/shared/engines/v8.lua b/lua/acf/shared/engines/v8.lua index ec83d4644..4cd6c90e1 100644 --- a/lua/acf/shared/engines/v8.lua +++ b/lua/acf/shared/engines/v8.lua @@ -106,3 +106,119 @@ ACF_DefineEngine( "19.0-V8", { peakmaxrpm = 1800, limitrpm = 2500 } ) + +ACF.RegisterEngineClass("V8", { + Name = "V8 Engine", +}) + +do -- Petrol Engines + ACF.RegisterEngine("5.7-V8", "V8", { + Name = "5.7L V8 Petrol", + Description = "Car sized petrol engine, good power and mid range torque", + Model = "models/engines/v8s.mdl", + Sound = "acf_engines/v8_petrolsmall.wav", + Fuel = "Petrol", + Type = "GenericPetrol", + Mass = 260, + Torque = 320, + FlywheelMass = 0.15, + RPM = { + Idle = 800, + PeakMin = 3000, + PeakMax = 5000, + Limit = 6500, + } + }) + + ACF.RegisterEngine("9.0-V8", "V8", { + Name = "9.0L V8 Petrol", + Description = "Thirsty, giant V8, for medium applications", + Model = "models/engines/v8m.mdl", + Sound = "acf_engines/v8_petrolmedium.wav", + Fuel = "Petrol", + Type = "GenericPetrol", + Mass = 400, + Torque = 460, + FlywheelMass = 0.25, + RPM = { + Idle = 700, + PeakMin = 3100, + PeakMax = 5000, + Limit = 5500, + } + }) + + ACF.RegisterEngine("18.0-V8", "V8", { + Name = "18.0L V8 Petrol", + Description = "American gasoline tank V8, good overall power and torque and fairly lightweight", + Model = "models/engines/v8l.mdl", + Sound = "acf_engines/v8_petrollarge.wav", + Fuel = "Petrol", + Type = "GenericPetrol", + Mass = 850, + Torque = 1458, + FlywheelMass = 2.8, + RPM = { + Idle = 600, + PeakMin = 2000, + PeakMax = 3300, + Limit = 3800, + } + }) +end + +do -- Diesel Engines + ACF.RegisterEngine("4.5-V8", "V8", { + Name = "4.5L V8 Diesel", + Description = "Light duty diesel v8, good for light vehicles that require a lot of torque", + Model = "models/engines/v8s.mdl", + Sound = "acf_engines/v8_dieselsmall.wav", + Fuel = "Diesel", + Type = "GenericDiesel", + Mass = 320, + Torque = 415, + FlywheelMass = 0.75, + RPM = { + Idle = 800, + PeakMin = 1000, + PeakMax = 3000, + Limit = 5000, + } + }) + + ACF.RegisterEngine("7.8-V8", "V8", { + Name = "7.8L V8 Diesel", + Description = "Redneck chariot material. Truck duty V8 diesel, has a good, wide powerband", + Model = "models/engines/v8m.mdl", + Sound = "acf_engines/v8_dieselmedium2.wav", + Fuel = "Diesel", + Type = "GenericDiesel", + Mass = 520, + Torque = 700, + FlywheelMass = 1.6, + RPM = { + Idle = 650, + PeakMin = 1000, + PeakMax = 3000, + Limit = 4000, + } + }) + + ACF.RegisterEngine("19.0-V8", "V8", { + Name = "19.0L V8 Diesel", + Description = "Heavy duty diesel V8, used in heavy construction equipment and tanks", + Model = "models/engines/v8l.mdl", + Sound = "acf_engines/v8_diesellarge.wav", + Fuel = "Diesel", + Type = "GenericDiesel", + Mass = 1200, + Torque = 2300, + FlywheelMass = 4.5, + RPM = { + Idle = 500, + PeakMin = 600, + PeakMax = 1800, + Limit = 2500, + } + }) +end From 5e6ccadf090cee14c50bcae6d1bdccabcd0d1ee7 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Tue, 17 Mar 2020 02:32:42 -0300 Subject: [PATCH 037/279] Added engine selection menu - Divided the mobility option between engine and gearbox. - Populated the engine option with the engine selection controls. - Fixed some engine names. - Shortened the GGT class description a bit. - Fixed Large Electric Standalone Motor not being registered correctly. --- lua/acf/client/cl_menu.lua | 5 +- lua/acf/client/menu_items/engines_menu.lua | 141 +++++++++++++++++++++ lua/acf/shared/engines/electric.lua | 4 +- lua/acf/shared/engines/turbine.lua | 26 ++-- 4 files changed, 159 insertions(+), 17 deletions(-) create mode 100644 lua/acf/client/menu_items/engines_menu.lua diff --git a/lua/acf/client/cl_menu.lua b/lua/acf/client/cl_menu.lua index 1c48f8888..c9fff9e9e 100644 --- a/lua/acf/client/cl_menu.lua +++ b/lua/acf/client/cl_menu.lua @@ -75,9 +75,10 @@ do -- Menu population functions ACF.AddOption("Entities", "brick") ACF.AddOptionItem("Entities", "Weapons", "gun") ACF.AddOptionItem("Entities", "Missiles", "wand", MissilesMenu) - ACF.AddOptionItem("Entities", "Mobility", "car") + ACF.AddOptionItem("Entities", "Engines", "car") + ACF.AddOptionItem("Entities", "Gearboxes", "cog") ACF.AddOptionItem("Entities", "Sensors", "transmit") - ACF.AddOptionItem("Entities", "Components", "cog") + ACF.AddOptionItem("Entities", "Components", "drive") end do -- ACF Menu context panel diff --git a/lua/acf/client/menu_items/engines_menu.lua b/lua/acf/client/menu_items/engines_menu.lua new file mode 100644 index 000000000..044400284 --- /dev/null +++ b/lua/acf/client/menu_items/engines_menu.lua @@ -0,0 +1,141 @@ +local Engines = ACF.Classes.Engines +local FuelDensity = ACF.FuelDensity +local Efficiency = ACF.Efficiency +local Selected = {} +local Sorted = {} + +local function LoadSortedList(Panel, List, Member) + local Choices = Sorted[List] + + if not Choices then + Choices = {} + + local Count = 0 + for _, V in pairs(List) do + Count = Count + 1 + Choices[Count] = V + end + + table.SortByMember(Choices, Member, true) + + Sorted[List] = Choices + Selected[Choices] = 1 + end + + Panel:Clear() + + for _, V in pairs(Choices) do + Panel:AddChoice(V.Name, V) + end + + Panel:ChooseOptionID(Selected[Choices]) +end + +local function UpdateEngineStats(Label, Data) + local RPM = Data.RPM + local PeakkW = Data.Torque * RPM.PeakMax / 9548.8 + local PeakkWRPM = RPM.PeakMax + local MinPower = RPM.PeakMin + local MaxPower = RPM.PeakMax + + local RPMText = "Idle RPM : %s RPM\nPowerband : %s-%s RPM\nRedline : %s RPM\nMass : %s" + local Text = "" + + -- Electric motors and turbines get peak power in middle of rpm range + if Data.IsElectric then + PeakkW = Data.Torque * (1 + RPM.PeakMax / RPM.Limit) * RPM.Limit / (4 * 9548.8) + PeakkWRPM = math.floor(RPM.Limit * 0.5) + MinPower = RPM.Idle + MaxPower = PeakkWRPM + end + + Text = Text .. RPMText:format(RPM.Idle, MinPower, MaxPower, RPM.Limit, ACF.GetProperMass(Data.Mass)) + + local TorqueText = "\nPeak Torque : %s n/m - %s ft-lb" + local PowerText = "\nPeak Power : %s kW - %s HP @ %s RPM" + local FuelText = "\n\nFuel Type : %s%s%s" + local Consumption, Power = "", "" + local Boost = Data.RequiresFuel and ACF.TorqueBoost or 1 + local Fuel = Data.Fuel + + if Fuel == "Electric" then + local ElecText = "\nPeak Energy Consumption :\n%s kW - %s MJ/min" + local ElecRate = ACF.ElecRate * PeakkW / Efficiency[Data.Type] + + Consumption = ElecText:format(math.Round(ElecRate, 2), math.Round(ElecRate * 0.06, 2)) + else + local ConsumptionText = "\n%s Consumption :\n%s L/min - %s gal/min @ %s RPM" + + if Fuel == "Multifuel" or Fuel == "Diesel" then + local FuelRate = ACF.FuelRate * Efficiency[Data.Type] * ACF.TorqueBoost * PeakkW / (60 * FuelDensity.Diesel) + + Consumption = Consumption .. ConsumptionText:format("Diesel", math.Round(FuelRate, 2), math.Round(FuelRate * 0.264, 2), PeakkWRPM) + end + + if Fuel == "Multifuel" or Fuel == "Petrol" then + local FuelRate = ACF.FuelRate * Efficiency[Data.Type] * ACF.TorqueBoost * PeakkW / (60 * FuelDensity.Petrol) + + Consumption = Consumption .. ConsumptionText:format("Petrol", math.Round(FuelRate, 2), math.Round(FuelRate * 0.264, 2), PeakkWRPM) + end + end + + Power = Power .. "\n" .. PowerText:format(math.floor(PeakkW * Boost), math.floor(PeakkW * Boost * 1.34), PeakkWRPM) + Power = Power .. TorqueText:format(math.floor(Data.Torque * Boost), math.floor(Data.Torque * Boost * 0.73)) + + if Data.RequiresFuel then + Consumption = Consumption .. "\n\nThis engine requires fuel." + else + Power = Power .. "\n\nWhen Fueled :" .. PowerText:format(math.floor(PeakkW * ACF.TorqueBoost), math.floor(PeakkW * ACF.TorqueBoost * 1.34), PeakkWRPM) + Power = Power .. TorqueText:format(math.floor(Data.Torque * ACF.TorqueBoost), math.floor(Data.Torque * ACF.TorqueBoost * 0.73)) + end + + Text = Text .. FuelText:format(Fuel, Consumption, Power) + + Label:SetText(Text) +end + +local function CreateMenu(Menu) + local EngineClass = Menu:AddComboBox() + local EngineList = Menu:AddComboBox() + local EngineName = Menu:AddTitle() + local EngineDesc = Menu:AddLabel() + local EngineStats = Menu:AddLabel() + + ACF.WriteValue("PrimaryClass", "acf_engine") + ACF.WriteValue("SecondaryClass", "acf_fueltank") + + function EngineClass:OnSelect(Index, _, Data) + if self.Selected == Data then return end + + self.Selected = Data + + local Choices = Sorted[Engines] + Selected[Choices] = Index + + ACF.WriteValue("EngineClass", Data.ID) + + LoadSortedList(EngineList, Data.Items, "Mass") + end + + function EngineList:OnSelect(Index, _, Data) + if self.Selected == Data then return end + + self.Selected = Data + + local ClassData = EngineClass.Selected + local ClassDesc = ClassData.Description + local Choices = Sorted[ClassData.Items] + Selected[Choices] = Index + + ACF.WriteValue("Engine", Data.ID) + + EngineName:SetText(Data.Name) + EngineDesc:SetText((ClassDesc and (ClassDesc .. "\n\n") or "") .. Data.Description) + + UpdateEngineStats(EngineStats, Data) + end + + LoadSortedList(EngineClass, Engines, "ID") +end + +ACF.AddOptionItem("Entities", "Engines", "car", CreateMenu) diff --git a/lua/acf/shared/engines/electric.lua b/lua/acf/shared/engines/electric.lua index 6eb507158..a884b3b10 100644 --- a/lua/acf/shared/engines/electric.lua +++ b/lua/acf/shared/engines/electric.lua @@ -233,7 +233,7 @@ do -- Electric Standalone Motors }) ACF.RegisterEngine("Electric-Medium-NoBatt", "EL-S", { - Name = "Medium", + Name = "Medium Electric Standalone Motor", Description = "A medium standalone electric motor, loads of torque, but low power.", Model = "models/engines/emotor-standalone-mid.mdl", Sound = "acf_engines/electric_medium.wav", @@ -253,7 +253,7 @@ do -- Electric Standalone Motors }, }) - ACF.RegisterEngine( "Electric-Large-NoBatt", { + ACF.RegisterEngine("Electric-Large-NoBatt", "EL-S", { Name = "Large Electric Standalone Motor", Description = "A huge standalone electric motor, loads of torque, but low power.", Model = "models/engines/emotor-standalone-big.mdl", diff --git a/lua/acf/shared/engines/turbine.lua b/lua/acf/shared/engines/turbine.lua index f34aee4cf..77e58c30d 100644 --- a/lua/acf/shared/engines/turbine.lua +++ b/lua/acf/shared/engines/turbine.lua @@ -262,7 +262,7 @@ ACF.RegisterEngineClass("GT", { do -- Forward-facing Gas Turbines ACF.RegisterEngine("Turbine-Small", "GT", { - Name = "Gas Turbine, Small", + Name = "Small Gas Turbine", Description = "A small gas turbine, high power and a very wide powerband.", Model = "models/engines/gasturbine_s.mdl", Sound = "acf_engines/turbine_small.wav", @@ -283,7 +283,7 @@ do -- Forward-facing Gas Turbines }) ACF.RegisterEngine("Turbine-Medium", "GT", { - Name = "Gas Turbine, Medium", + Name = "Medium Gas Turbine", Description = "A medium gas turbine, moderate power but a very wide powerband.", Model = "models/engines/gasturbine_m.mdl", Sound = "acf_engines/turbine_medium.wav", @@ -304,7 +304,7 @@ do -- Forward-facing Gas Turbines }) ACF.RegisterEngine("Turbine-Large", "GT", { - Name = "Gas Turbine, Large", + Name = "Large Gas Turbine", Description = "A large gas turbine, powerful with a wide powerband.", Model = "models/engines/gasturbine_l.mdl", Sound = "acf_engines/turbine_large.wav", @@ -327,7 +327,7 @@ end do -- Transaxial Gas Turbines ACF.RegisterEngine("Turbine-Small-Trans", "GT", { - Name = "Gas Turbine, Small, Transaxial", + Name = "Small Transaxial Gas Turbine", Description = "A small gas turbine, high power and a very wide powerband. Outputs to the side instead of rear.", Model = "models/engines/turbine_s.mdl", Sound = "acf_engines/turbine_small.wav", @@ -349,7 +349,7 @@ do -- Transaxial Gas Turbines }) ACF.RegisterEngine("Turbine-Medium-Trans", "GT", { - Name = "Gas Turbine, Medium, Transaxial", + Name = "Medium Transaxial Gas Turbine", Description = "A medium gas turbine, moderate power but a very wide powerband. Outputs to the side instead of rear.", Model = "models/engines/turbine_m.mdl", Sound = "acf_engines/turbine_medium.wav", @@ -371,7 +371,7 @@ do -- Transaxial Gas Turbines }) ACF.RegisterEngine("Turbine-Large-Trans", "GT", { - Name = "Gas Turbine, Large, Transaxial", + Name = "Large Transaxial Gas Turbine", Description = "A large gas turbine, powerful with a wide powerband. Outputs to the side instead of rear.", Model = "models/engines/turbine_l.mdl", Sound = "acf_engines/turbine_large.wav", @@ -395,12 +395,12 @@ end ACF.RegisterEngineClass("GGT", { Name = "Ground Gas Turbine", - Description = "Ground-use turbines have excellent low-rev performance and are deceptively powerful. However, they have sluggish throttle response, high gearbox demands, high fuel usage, and low tolerance to damage." + Description = "Ground-use turbines have excellent low-rev performance and are deceptively powerful. However, they have high gearbox demands, high fuel usage and low tolerance to damage." }) do -- Forward-facing Ground Gas Turbines ACF.RegisterEngine("Turbine-Ground-Small", "GGT", { - Name = "Ground Gas Turbine, Small", + Name = "Small Ground Gas Turbine", Description = "A small gas turbine, fitted with ground-use air filters and tuned for ground use.", Model = "models/engines/gasturbine_s.mdl", Sound = "acf_engines/turbine_small.wav", @@ -421,7 +421,7 @@ do -- Forward-facing Ground Gas Turbines }) ACF.RegisterEngine("Turbine-Ground-Medium", "GGT", { - Name = "Ground Gas Turbine, Medium", + Name = "Medium Ground Gas Turbine", Description = "A medium gas turbine, fitted with ground-use air filters and tuned for ground use.", Model = "models/engines/gasturbine_m.mdl", Sound = "acf_engines/turbine_medium.wav", @@ -443,7 +443,7 @@ do -- Forward-facing Ground Gas Turbines }) ACF.RegisterEngine("Turbine-Ground-Large", "GGT", { - Name = "Ground Gas Turbine, Large", + Name = "Large Ground Gas Turbine", Description = "A large gas turbine, fitted with ground-use air filters and tuned for ground use.", Model = "models/engines/gasturbine_l.mdl", Sound = "acf_engines/turbine_large.wav", @@ -467,7 +467,7 @@ end do -- Transaxial Ground Gas Turbines ACF.RegisterEngine("Turbine-Small-Ground-Trans", "GGT", { - Name = "Ground Gas Turbine, Small, Transaxial", + Name = "Small Transaxial Ground Gas Turbine", Description = "A small gas turbine fitted with ground-use air filters and tuned for ground use. Outputs to the side instead of rear.", Model = "models/engines/turbine_s.mdl", Sound = "acf_engines/turbine_small.wav", @@ -489,7 +489,7 @@ do -- Transaxial Ground Gas Turbines }) ACF.RegisterEngine("Turbine-Medium-Ground-Trans", "GGT", { - Name = "Ground Gas Turbine, Medium, Transaxial", + Name = "Medium Transaxial Ground Gas Turbine", Description = "A medium gas turbine fitted with ground-use air filters and tuned for ground use. Outputs to the side instead of rear.", Model = "models/engines/turbine_m.mdl", Sound = "acf_engines/turbine_medium.wav", @@ -512,7 +512,7 @@ do -- Transaxial Ground Gas Turbines }) ACF.RegisterEngine("Turbine-Large-Ground-Trans", "GGT", { - Name = "Ground Gas Turbine, Large, Transaxial", + Name = "Large Transaxial Ground Gas Turbine", Description = "A large gas turbine fitted with ground-use air filters and tuned for ground use. Outputs to the side instead of rear.", Model = "models/engines/turbine_l.mdl", Sound = "acf_engines/turbine_large.wav", From 03ae309d76e1519766752a094fb7034325333ac0 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Wed, 18 Mar 2020 02:50:29 -0300 Subject: [PATCH 038/279] Added fuel tank registration function - Added ACF.RegisterFuelTank function. - Ported all existing fuel tanks to the new fuel tank registration function. - Added a fuel tank selection combobox to the engine selection menu. --- lua/acf/base/sh_classes.lua | 27 ++ lua/acf/client/menu_items/engines_menu.lua | 4 + lua/acf/shared/fueltanks/basic.lua | 398 +++++++++++++++++++++ 3 files changed, 429 insertions(+) diff --git a/lua/acf/base/sh_classes.lua b/lua/acf/base/sh_classes.lua index abd0d84bb..840ef57ec 100644 --- a/lua/acf/base/sh_classes.lua +++ b/lua/acf/base/sh_classes.lua @@ -229,3 +229,30 @@ do -- Engine registration functions end end end + +do -- Fuel tank registration function + ACF.Classes.FuelTanks = ACF.Classes.FuelTanks or {} + + local FuelTanks = ACF.Classes.FuelTanks + + function ACF.RegisterFuelTank(ID, Data) + if not ID then return end + if not Data then return end + + local FuelTank = FuelTanks[ID] + + if not FuelTank then + FuelTank = { + ID = ID, + EntClass = "acf_fueltank", + IsExplosive = true, + } + + FuelTanks[ID] = FuelTank + end + + for K, V in pairs(Data) do + FuelTank[K] = V + end + end +end diff --git a/lua/acf/client/menu_items/engines_menu.lua b/lua/acf/client/menu_items/engines_menu.lua index 044400284..efaf3b68b 100644 --- a/lua/acf/client/menu_items/engines_menu.lua +++ b/lua/acf/client/menu_items/engines_menu.lua @@ -1,3 +1,4 @@ +local FuelTanks = ACF.Classes.FuelTanks local Engines = ACF.Classes.Engines local FuelDensity = ACF.FuelDensity local Efficiency = ACF.Efficiency @@ -101,6 +102,8 @@ local function CreateMenu(Menu) local EngineDesc = Menu:AddLabel() local EngineStats = Menu:AddLabel() + local FuelList = Menu:AddComboBox() + ACF.WriteValue("PrimaryClass", "acf_engine") ACF.WriteValue("SecondaryClass", "acf_fueltank") @@ -136,6 +139,7 @@ local function CreateMenu(Menu) end LoadSortedList(EngineClass, Engines, "ID") + LoadSortedList(FuelList, FuelTanks, "ID") end ACF.AddOptionItem("Entities", "Engines", "car", CreateMenu) diff --git a/lua/acf/shared/fueltanks/basic.lua b/lua/acf/shared/fueltanks/basic.lua index 690ddd409..312189f75 100644 --- a/lua/acf/shared/fueltanks/basic.lua +++ b/lua/acf/shared/fueltanks/basic.lua @@ -353,3 +353,401 @@ ACF_DefineFuelTankSize( "Storage_Tank", { explosive = false, nolinks = true } ) + +do -- Fuel tanks + ACF.RegisterFuelTank("Tank_1x1x1", { --ID used in code + Name = "1x1x1", + Description = "Seriously consider walking.", + Model = "models/fueltank/fueltank_1x1x1.mdl", + SurfaceArea = 590.5, + Volume = 1019.9, + }) + + ACF.RegisterFuelTank("Tank_1x1x2", { + Name = "1x1x2", + Description = "Will keep a kart running all day.", + Model = "models/fueltank/fueltank_1x1x2.mdl", + SurfaceArea = 974, + Volume = 1983.1, + }) + + ACF.RegisterFuelTank("Tank_1x1x4", { + Name = "1x1x4", + Description = "Dinghy", + Model = "models/fueltank/fueltank_1x1x4.mdl", + SurfaceArea = 1777.4, + Volume = 3995.1, + }) + + ACF.RegisterFuelTank("Tank_1x2x1", { + Name = "1x2x1", + Description = "Will keep a kart running all day.", + Model = "models/fueltank/fueltank_1x2x1.mdl", + SurfaceArea = 995, + Volume = 2062.5, + }) + + ACF.RegisterFuelTank("Tank_1x2x2", { + Name = "1x2x2", + Description = "Dinghy", + Model = "models/fueltank/fueltank_1x2x2.mdl", + SurfaceArea = 1590.8, + Volume = 4070.9, + }) + + ACF.RegisterFuelTank("Tank_1x2x4", { + Name = "1x2x4", + Description = "Outboard motor.", + Model = "models/fueltank/fueltank_1x2x4.mdl", + SurfaceArea = 2796.6, + Volume = 8119.2, + }) + + ACF.RegisterFuelTank("Tank_1x4x1", { + Name = "1x4x1", + Description = "Dinghy", + Model = "models/fueltank/fueltank_1x4x1.mdl", + SurfaceArea = 1745.6, + Volume = 3962, + }) + + ACF.RegisterFuelTank("Tank_1x4x2", { + Name = "1x4x2", + Description = "Clown car.", + Model = "models/fueltank/fueltank_1x4x2.mdl", + SurfaceArea = 2753.9, + Volume = 8018, + }) + + ACF.RegisterFuelTank("Tank_1x4x4", { + Name = "1x4x4", + Description = "Fuel pancake.", + Model = "models/fueltank/fueltank_1x4x4.mdl", + SurfaceArea = 4761, + Volume = 16030.4, + }) + + ACF.RegisterFuelTank("Tank_1x6x1", { + Name = "1x6x1", + Description = "Lawn tractors.", + Model = "models/fueltank/fueltank_1x6x1.mdl", + SurfaceArea = 2535.3, + Volume = 5973.1, + }) + + ACF.RegisterFuelTank("Tank_1x6x2", { + Name = "1x6x2", + Description = "Small tractor tank.", + Model = "models/fueltank/fueltank_1x6x2.mdl", + SurfaceArea = 3954.1, + Volume = 12100.3, + }) + + ACF.RegisterFuelTank("Tank_1x6x4", { + Name = "1x6x4", + Description = "Fuel. Will keep you going for awhile.", + Model = "models/fueltank/fueltank_1x6x4.mdl", + SurfaceArea = 6743.3, + Volume = 24109.4, + }) + + ACF.RegisterFuelTank("Tank_1x8x1", { + Name = "1x8x1", + Description = "Clown car.", + Model = "models/fueltank/fueltank_1x8x1.mdl", + SurfaceArea = 3315.5, + Volume = 7962.4, + }) + + ACF.RegisterFuelTank("Tank_1x8x2", { + Name = "1x8x2", + Description = "Gas stations? We don't need no stinking gas stations!", + Model = "models/fueltank/fueltank_1x8x2.mdl", + SurfaceArea = 5113.7, + Volume = 16026.2, + }) + + ACF.RegisterFuelTank("Tank_1x8x4", { + Name = "1x8x4", + Description = "Beep beep.", + Model = "models/fueltank/fueltank_1x8x4.mdl", + SurfaceArea = 8696, + Volume = 31871, + }) + + ACF.RegisterFuelTank("Tank_2x2x1", { + Name = "2x2x1", + Description = "Dinghy", + Model = "models/fueltank/fueltank_2x2x1.mdl", + SurfaceArea = 1592.2, + Volume = 4285.2, + }) + + ACF.RegisterFuelTank("Tank_2x2x2", { + Name = "2x2x2", + Description = "Clown car.", + Model = "models/fueltank/fueltank_2x2x2.mdl", + SurfaceArea = 2360.4, + Volume = 8212.9, + }) + + ACF.RegisterFuelTank("Tank_2x2x4", { + Name = "2x2x4", + Description = "Mini Cooper.", + Model = "models/fueltank/fueltank_2x2x4.mdl", + SurfaceArea = 3988.6, + Volume = 16362, + }) + + ACF.RegisterFuelTank("Tank_2x4x1", { + Name = "2x4x1", + Description = "Good bit of go-juice.", + Model = "models/fueltank/fueltank_2x4x1.mdl", + SurfaceArea = 2808.8, + Volume = 8628, + }) + + ACF.RegisterFuelTank("Tank_2x4x2", { + Name = "2x4x2", + Description = "Mini Cooper.", + Model = "models/fueltank/fueltank_2x4x2.mdl", + SurfaceArea = 3996.1, + Volume = 16761.4, + }) + + ACF.RegisterFuelTank("Tank_2x4x4", { + Name = "2x4x4", + Description = "Land boat.", + Model = "models/fueltank/fueltank_2x4x4.mdl", + SurfaceArea = 6397.3, + Volume = 32854.4, + }) + + ACF.RegisterFuelTank("Tank_2x6x1", { + Name = "2x6x1", + Description = "Conformal fuel tank, fits narrow spaces.", + Model = "models/fueltank/fueltank_2x6x1.mdl", + SurfaceArea = 3861.4, + Volume = 12389.9, + }) + + ACF.RegisterFuelTank("Tank_2x6x2", { + Name = "2x6x2", + Description = "Compact car.", + Model = "models/fueltank/fueltank_2x6x2.mdl", + SurfaceArea = 5388, + Volume = 24127.7, + }) + + ACF.RegisterFuelTank("Tank_2x6x4", { + Name = "2x6x4", + Description = "Sedan.", + Model = "models/fueltank/fueltank_2x6x4.mdl", + SurfaceArea = 8485.6, + Volume = 47537.2, + }) + + ACF.RegisterFuelTank("Tank_2x8x1", { + Name = "2x8x1", + Description = "Conformal fuel tank, fits into tight spaces", + Model = "models/fueltank/fueltank_2x8x1.mdl", + SurfaceArea = 5094.5, + Volume = 16831.8, + }) + + ACF.RegisterFuelTank("Tank_2x8x2", { + Name = "2x8x2", + Description = "Truck.", + Model = "models/fueltank/fueltank_2x8x2.mdl", + SurfaceArea = 6980, + Volume = 32275.9, + }) + + ACF.RegisterFuelTank("Tank_2x8x4", { + Name = "2x8x4", + Description = "With great capacity, comes great responsibili--VROOOOM", + Model = "models/fueltank/fueltank_2x8x4.mdl", + SurfaceArea = 10898.2, + Volume = 63976, + }) + + ACF.RegisterFuelTank("Tank_4x4x1", { + Name = "4x4x1", + Description = "Sedan.", + Model = "models/fueltank/fueltank_4x4x1.mdl", + SurfaceArea = 4619.1, + Volume = 16539.8, + }) + + ACF.RegisterFuelTank("Tank_4x4x2", { + Name = "4x4x2", + Description = "Land boat.", + Model = "models/fueltank/fueltank_4x4x2.mdl", + SurfaceArea = 6071.4, + Volume = 32165.2, + }) + + ACF.RegisterFuelTank("Tank_4x4x4", { + Name = "4x4x4", + Description = "Popular with arsonists.", + Model = "models/fueltank/fueltank_4x4x4.mdl", + SurfaceArea = 9145.3, + Volume = 62900.1, + }) + + ACF.RegisterFuelTank("Tank_4x6x1", { + Name = "4x6x1", + Description = "Conformal fuel tank, fits in tight spaces.", + Model = "models/fueltank/fueltank_4x6x1.mdl", + SurfaceArea = 6553.6, + Volume = 24918.6, + }) + + ACF.RegisterFuelTank("Tank_4x6x2", { + Name = "4x6x2", + Description = "Fire juice.", + Model = "models/fueltank/fueltank_4x6x2.mdl", + SurfaceArea = 8425.3, + Volume = 48581.2, + }) + + ACF.RegisterFuelTank("Tank_4x6x4", { + Name = "4x6x4", + Description = "Trees are gay anyway.", + Model = "models/fueltank/fueltank_4x6x4.mdl", + SurfaceArea = 12200.6, + Volume = 94640, + }) + + ACF.RegisterFuelTank("Tank_4x8x1", { + Name = "4x8x1", + Description = "Arson material.", + Model = "models/fueltank/fueltank_4x8x1.mdl", + SurfaceArea = 8328.2, + Volume = 32541.9, + }) + + ACF.RegisterFuelTank("Tank_4x8x2", { + Name = "4x8x2", + Description = "What's a gas station?", + Model = "models/fueltank/fueltank_4x8x2.mdl", + SurfaceArea = 10419.5, + Volume = 63167.1, + }) + + ACF.RegisterFuelTank("Tank_4x8x4", { + Name = "4x8x4", + Description = "\'MURRICA FUCKYEAH!", + Model = "models/fueltank/fueltank_4x8x4.mdl", + SurfaceArea = 14993.3, + Volume = 123693.2, + }) + + ACF.RegisterFuelTank("Tank_6x6x1", { + Name = "6x6x1", + Description = "Got gas?", + Model = "models/fueltank/fueltank_6x6x1.mdl", + SurfaceArea = 9405.2, + Volume = 37278.5, + }) + + ACF.RegisterFuelTank("Tank_6x6x2", { + Name = "6x6x2", + Description = "Drive across the desert without a fuck to give.", + Model = "models/fueltank/fueltank_6x6x2.mdl", + SurfaceArea = 11514.5, + Volume = 73606.2, + }) + + ACF.RegisterFuelTank("Tank_6x6x4", { + Name = "6x6x4", + Description = "May contain Mesozoic ghosts.", + Model = "models/fueltank/fueltank_6x6x4.mdl", + SurfaceArea = 16028.8, + Volume = 143269, + }) + + ACF.RegisterFuelTank("Tank_6x8x1", { + Name = "6x8x1", + Description = "Conformal fuel tank, does what all its friends do.", + Model = "models/fueltank/fueltank_6x8x1.mdl", + SurfaceArea = 12131.1, + Volume = 48480.2, + }) + + ACF.RegisterFuelTank("Tank_6x8x2", { + Name = "6x8x2", + Description = "Certified 100% dinosaur juice.", + Model = "models/fueltank/fueltank_6x8x2.mdl", + SurfaceArea = 14403.8, + Volume = 95065.5, + }) + + ACF.RegisterFuelTank("Tank_6x8x4", { + Name = "6x8x4", + Description = "Will last you a while.", + Model = "models/fueltank/fueltank_6x8x4.mdl", + SurfaceArea = 19592.4, + Volume = 187296.4, + }) + + ACF.RegisterFuelTank("Tank_8x8x1", { + Name = "8x8x1", + Description = "Sloshy sloshy!", + Model = "models/fueltank/fueltank_8x8x1.mdl", + SurfaceArea = 15524.8, + Volume = 64794.2, + }) + + ACF.RegisterFuelTank("Tank_8x8x2", { + Name = "8x8x2", + Description = "What's global warming?", + Model = "models/fueltank/fueltank_8x8x2.mdl", + SurfaceArea = 18086.4, + Volume = 125868.9, + }) + + ACF.RegisterFuelTank("Tank_8x8x4", { + Name = "8x8x4", + Description = "Tank Tank.", + Model = "models/fueltank/fueltank_8x8x4.mdl", + SurfaceArea = 23957.6, + Volume = 246845.3, + }) + + ACF.RegisterFuelTank("Fuel_Drum", { + Name = "Fuel Drum", + Description = "Tends to explode when shot.", + Model = "models/props_c17/oildrum001_explosive.mdl", + SurfaceArea = 5128.9, + Volume = 26794.4, + }) + + ACF.RegisterFuelTank("Jerry_Can", { + Name = "Jerry Can", + Description = "Handy portable fuel container.", + Model = "models/props_junk/gascan001a.mdl", + SurfaceArea = 1839.7, + Volume = 4384.1,, + }) + + ACF.RegisterFuelTank("Transport_Tank", { + Name = "Transport Tank", + Description = "Disappointingly non-explosive.", + Model = "models/props_wasteland/horizontalcoolingtank04.mdl", + SurfaceArea = 127505.5, + Volume = 2102493.3, + IsExplosive = false, + Unlinkable = true, + }) + + ACF.RegisterFuelTank("Storage_Tank", { + Name = "Storage Tank", + Description = "Disappointingly non-explosive.", + Model = "models/props_wasteland/coolingtank02.mdl", + SurfaceArea = 144736.3, + Volume = 2609960, + IsExplosive = false, + Unlinkable = true, + }) +end From 068077539dd19f16af8d7c3e34178e8892819281 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Fri, 20 Mar 2020 03:00:56 -0300 Subject: [PATCH 039/279] Separated fuel tanks into different fuel tank classes - Along with ACF.RegisterFuelTank, developers must previously use ACF.RegisterFuelTankClass to create a new fuel tank class or use one of the existing ones in order to register a new fuel tank. --- lua/acf/base/sh_classes.lua | 37 ++- lua/acf/shared/fueltanks/basic.lua | 398 ------------------------ lua/acf/shared/fueltanks/misc.lua | 42 +++ lua/acf/shared/fueltanks/size_eight.lua | 30 ++ lua/acf/shared/fueltanks/size_four.lua | 78 +++++ lua/acf/shared/fueltanks/size_one.lua | 126 ++++++++ lua/acf/shared/fueltanks/size_six.lua | 54 ++++ lua/acf/shared/fueltanks/size_two.lua | 102 ++++++ 8 files changed, 465 insertions(+), 402 deletions(-) create mode 100644 lua/acf/shared/fueltanks/misc.lua create mode 100644 lua/acf/shared/fueltanks/size_eight.lua create mode 100644 lua/acf/shared/fueltanks/size_four.lua create mode 100644 lua/acf/shared/fueltanks/size_one.lua create mode 100644 lua/acf/shared/fueltanks/size_six.lua create mode 100644 lua/acf/shared/fueltanks/size_two.lua diff --git a/lua/acf/base/sh_classes.lua b/lua/acf/base/sh_classes.lua index 840ef57ec..2b821c744 100644 --- a/lua/acf/base/sh_classes.lua +++ b/lua/acf/base/sh_classes.lua @@ -235,20 +235,49 @@ do -- Fuel tank registration function local FuelTanks = ACF.Classes.FuelTanks - function ACF.RegisterFuelTank(ID, Data) + function ACF.RegisterFuelTankClass(ID, Data) if not ID then return end if not Data then return end - local FuelTank = FuelTanks[ID] + local Class = FuelTanks[ID] + + if not Class then + Class = { + ID = ID, + Lookup = {}, + Items = {}, + Count = 0, + } + + FuelTanks[ID] = Class + end + + for K, V in pairs(Data) do + Class[K] = V + end + end + + function ACF.RegisterFuelTank(ID, ClassID, Data) + if not ID then return end + if not ClassID then return end + if not Data then return end + if not FuelTanks[ClassID] then return end + + local Class = FuelTanks[ClassID] + local FuelTank = Class.Lookup[ID] if not FuelTank then FuelTank = { ID = ID, - EntClass = "acf_fueltank", + Class = Class, + ClassID = ClassID, + EntClass = "acf_engine", IsExplosive = true, } - FuelTanks[ID] = FuelTank + Class.Count = Class.Count + 1 + Class.Items[Class.Count] = FuelTank + Class.Lookup[ID] = FuelTank end for K, V in pairs(Data) do diff --git a/lua/acf/shared/fueltanks/basic.lua b/lua/acf/shared/fueltanks/basic.lua index 312189f75..690ddd409 100644 --- a/lua/acf/shared/fueltanks/basic.lua +++ b/lua/acf/shared/fueltanks/basic.lua @@ -353,401 +353,3 @@ ACF_DefineFuelTankSize( "Storage_Tank", { explosive = false, nolinks = true } ) - -do -- Fuel tanks - ACF.RegisterFuelTank("Tank_1x1x1", { --ID used in code - Name = "1x1x1", - Description = "Seriously consider walking.", - Model = "models/fueltank/fueltank_1x1x1.mdl", - SurfaceArea = 590.5, - Volume = 1019.9, - }) - - ACF.RegisterFuelTank("Tank_1x1x2", { - Name = "1x1x2", - Description = "Will keep a kart running all day.", - Model = "models/fueltank/fueltank_1x1x2.mdl", - SurfaceArea = 974, - Volume = 1983.1, - }) - - ACF.RegisterFuelTank("Tank_1x1x4", { - Name = "1x1x4", - Description = "Dinghy", - Model = "models/fueltank/fueltank_1x1x4.mdl", - SurfaceArea = 1777.4, - Volume = 3995.1, - }) - - ACF.RegisterFuelTank("Tank_1x2x1", { - Name = "1x2x1", - Description = "Will keep a kart running all day.", - Model = "models/fueltank/fueltank_1x2x1.mdl", - SurfaceArea = 995, - Volume = 2062.5, - }) - - ACF.RegisterFuelTank("Tank_1x2x2", { - Name = "1x2x2", - Description = "Dinghy", - Model = "models/fueltank/fueltank_1x2x2.mdl", - SurfaceArea = 1590.8, - Volume = 4070.9, - }) - - ACF.RegisterFuelTank("Tank_1x2x4", { - Name = "1x2x4", - Description = "Outboard motor.", - Model = "models/fueltank/fueltank_1x2x4.mdl", - SurfaceArea = 2796.6, - Volume = 8119.2, - }) - - ACF.RegisterFuelTank("Tank_1x4x1", { - Name = "1x4x1", - Description = "Dinghy", - Model = "models/fueltank/fueltank_1x4x1.mdl", - SurfaceArea = 1745.6, - Volume = 3962, - }) - - ACF.RegisterFuelTank("Tank_1x4x2", { - Name = "1x4x2", - Description = "Clown car.", - Model = "models/fueltank/fueltank_1x4x2.mdl", - SurfaceArea = 2753.9, - Volume = 8018, - }) - - ACF.RegisterFuelTank("Tank_1x4x4", { - Name = "1x4x4", - Description = "Fuel pancake.", - Model = "models/fueltank/fueltank_1x4x4.mdl", - SurfaceArea = 4761, - Volume = 16030.4, - }) - - ACF.RegisterFuelTank("Tank_1x6x1", { - Name = "1x6x1", - Description = "Lawn tractors.", - Model = "models/fueltank/fueltank_1x6x1.mdl", - SurfaceArea = 2535.3, - Volume = 5973.1, - }) - - ACF.RegisterFuelTank("Tank_1x6x2", { - Name = "1x6x2", - Description = "Small tractor tank.", - Model = "models/fueltank/fueltank_1x6x2.mdl", - SurfaceArea = 3954.1, - Volume = 12100.3, - }) - - ACF.RegisterFuelTank("Tank_1x6x4", { - Name = "1x6x4", - Description = "Fuel. Will keep you going for awhile.", - Model = "models/fueltank/fueltank_1x6x4.mdl", - SurfaceArea = 6743.3, - Volume = 24109.4, - }) - - ACF.RegisterFuelTank("Tank_1x8x1", { - Name = "1x8x1", - Description = "Clown car.", - Model = "models/fueltank/fueltank_1x8x1.mdl", - SurfaceArea = 3315.5, - Volume = 7962.4, - }) - - ACF.RegisterFuelTank("Tank_1x8x2", { - Name = "1x8x2", - Description = "Gas stations? We don't need no stinking gas stations!", - Model = "models/fueltank/fueltank_1x8x2.mdl", - SurfaceArea = 5113.7, - Volume = 16026.2, - }) - - ACF.RegisterFuelTank("Tank_1x8x4", { - Name = "1x8x4", - Description = "Beep beep.", - Model = "models/fueltank/fueltank_1x8x4.mdl", - SurfaceArea = 8696, - Volume = 31871, - }) - - ACF.RegisterFuelTank("Tank_2x2x1", { - Name = "2x2x1", - Description = "Dinghy", - Model = "models/fueltank/fueltank_2x2x1.mdl", - SurfaceArea = 1592.2, - Volume = 4285.2, - }) - - ACF.RegisterFuelTank("Tank_2x2x2", { - Name = "2x2x2", - Description = "Clown car.", - Model = "models/fueltank/fueltank_2x2x2.mdl", - SurfaceArea = 2360.4, - Volume = 8212.9, - }) - - ACF.RegisterFuelTank("Tank_2x2x4", { - Name = "2x2x4", - Description = "Mini Cooper.", - Model = "models/fueltank/fueltank_2x2x4.mdl", - SurfaceArea = 3988.6, - Volume = 16362, - }) - - ACF.RegisterFuelTank("Tank_2x4x1", { - Name = "2x4x1", - Description = "Good bit of go-juice.", - Model = "models/fueltank/fueltank_2x4x1.mdl", - SurfaceArea = 2808.8, - Volume = 8628, - }) - - ACF.RegisterFuelTank("Tank_2x4x2", { - Name = "2x4x2", - Description = "Mini Cooper.", - Model = "models/fueltank/fueltank_2x4x2.mdl", - SurfaceArea = 3996.1, - Volume = 16761.4, - }) - - ACF.RegisterFuelTank("Tank_2x4x4", { - Name = "2x4x4", - Description = "Land boat.", - Model = "models/fueltank/fueltank_2x4x4.mdl", - SurfaceArea = 6397.3, - Volume = 32854.4, - }) - - ACF.RegisterFuelTank("Tank_2x6x1", { - Name = "2x6x1", - Description = "Conformal fuel tank, fits narrow spaces.", - Model = "models/fueltank/fueltank_2x6x1.mdl", - SurfaceArea = 3861.4, - Volume = 12389.9, - }) - - ACF.RegisterFuelTank("Tank_2x6x2", { - Name = "2x6x2", - Description = "Compact car.", - Model = "models/fueltank/fueltank_2x6x2.mdl", - SurfaceArea = 5388, - Volume = 24127.7, - }) - - ACF.RegisterFuelTank("Tank_2x6x4", { - Name = "2x6x4", - Description = "Sedan.", - Model = "models/fueltank/fueltank_2x6x4.mdl", - SurfaceArea = 8485.6, - Volume = 47537.2, - }) - - ACF.RegisterFuelTank("Tank_2x8x1", { - Name = "2x8x1", - Description = "Conformal fuel tank, fits into tight spaces", - Model = "models/fueltank/fueltank_2x8x1.mdl", - SurfaceArea = 5094.5, - Volume = 16831.8, - }) - - ACF.RegisterFuelTank("Tank_2x8x2", { - Name = "2x8x2", - Description = "Truck.", - Model = "models/fueltank/fueltank_2x8x2.mdl", - SurfaceArea = 6980, - Volume = 32275.9, - }) - - ACF.RegisterFuelTank("Tank_2x8x4", { - Name = "2x8x4", - Description = "With great capacity, comes great responsibili--VROOOOM", - Model = "models/fueltank/fueltank_2x8x4.mdl", - SurfaceArea = 10898.2, - Volume = 63976, - }) - - ACF.RegisterFuelTank("Tank_4x4x1", { - Name = "4x4x1", - Description = "Sedan.", - Model = "models/fueltank/fueltank_4x4x1.mdl", - SurfaceArea = 4619.1, - Volume = 16539.8, - }) - - ACF.RegisterFuelTank("Tank_4x4x2", { - Name = "4x4x2", - Description = "Land boat.", - Model = "models/fueltank/fueltank_4x4x2.mdl", - SurfaceArea = 6071.4, - Volume = 32165.2, - }) - - ACF.RegisterFuelTank("Tank_4x4x4", { - Name = "4x4x4", - Description = "Popular with arsonists.", - Model = "models/fueltank/fueltank_4x4x4.mdl", - SurfaceArea = 9145.3, - Volume = 62900.1, - }) - - ACF.RegisterFuelTank("Tank_4x6x1", { - Name = "4x6x1", - Description = "Conformal fuel tank, fits in tight spaces.", - Model = "models/fueltank/fueltank_4x6x1.mdl", - SurfaceArea = 6553.6, - Volume = 24918.6, - }) - - ACF.RegisterFuelTank("Tank_4x6x2", { - Name = "4x6x2", - Description = "Fire juice.", - Model = "models/fueltank/fueltank_4x6x2.mdl", - SurfaceArea = 8425.3, - Volume = 48581.2, - }) - - ACF.RegisterFuelTank("Tank_4x6x4", { - Name = "4x6x4", - Description = "Trees are gay anyway.", - Model = "models/fueltank/fueltank_4x6x4.mdl", - SurfaceArea = 12200.6, - Volume = 94640, - }) - - ACF.RegisterFuelTank("Tank_4x8x1", { - Name = "4x8x1", - Description = "Arson material.", - Model = "models/fueltank/fueltank_4x8x1.mdl", - SurfaceArea = 8328.2, - Volume = 32541.9, - }) - - ACF.RegisterFuelTank("Tank_4x8x2", { - Name = "4x8x2", - Description = "What's a gas station?", - Model = "models/fueltank/fueltank_4x8x2.mdl", - SurfaceArea = 10419.5, - Volume = 63167.1, - }) - - ACF.RegisterFuelTank("Tank_4x8x4", { - Name = "4x8x4", - Description = "\'MURRICA FUCKYEAH!", - Model = "models/fueltank/fueltank_4x8x4.mdl", - SurfaceArea = 14993.3, - Volume = 123693.2, - }) - - ACF.RegisterFuelTank("Tank_6x6x1", { - Name = "6x6x1", - Description = "Got gas?", - Model = "models/fueltank/fueltank_6x6x1.mdl", - SurfaceArea = 9405.2, - Volume = 37278.5, - }) - - ACF.RegisterFuelTank("Tank_6x6x2", { - Name = "6x6x2", - Description = "Drive across the desert without a fuck to give.", - Model = "models/fueltank/fueltank_6x6x2.mdl", - SurfaceArea = 11514.5, - Volume = 73606.2, - }) - - ACF.RegisterFuelTank("Tank_6x6x4", { - Name = "6x6x4", - Description = "May contain Mesozoic ghosts.", - Model = "models/fueltank/fueltank_6x6x4.mdl", - SurfaceArea = 16028.8, - Volume = 143269, - }) - - ACF.RegisterFuelTank("Tank_6x8x1", { - Name = "6x8x1", - Description = "Conformal fuel tank, does what all its friends do.", - Model = "models/fueltank/fueltank_6x8x1.mdl", - SurfaceArea = 12131.1, - Volume = 48480.2, - }) - - ACF.RegisterFuelTank("Tank_6x8x2", { - Name = "6x8x2", - Description = "Certified 100% dinosaur juice.", - Model = "models/fueltank/fueltank_6x8x2.mdl", - SurfaceArea = 14403.8, - Volume = 95065.5, - }) - - ACF.RegisterFuelTank("Tank_6x8x4", { - Name = "6x8x4", - Description = "Will last you a while.", - Model = "models/fueltank/fueltank_6x8x4.mdl", - SurfaceArea = 19592.4, - Volume = 187296.4, - }) - - ACF.RegisterFuelTank("Tank_8x8x1", { - Name = "8x8x1", - Description = "Sloshy sloshy!", - Model = "models/fueltank/fueltank_8x8x1.mdl", - SurfaceArea = 15524.8, - Volume = 64794.2, - }) - - ACF.RegisterFuelTank("Tank_8x8x2", { - Name = "8x8x2", - Description = "What's global warming?", - Model = "models/fueltank/fueltank_8x8x2.mdl", - SurfaceArea = 18086.4, - Volume = 125868.9, - }) - - ACF.RegisterFuelTank("Tank_8x8x4", { - Name = "8x8x4", - Description = "Tank Tank.", - Model = "models/fueltank/fueltank_8x8x4.mdl", - SurfaceArea = 23957.6, - Volume = 246845.3, - }) - - ACF.RegisterFuelTank("Fuel_Drum", { - Name = "Fuel Drum", - Description = "Tends to explode when shot.", - Model = "models/props_c17/oildrum001_explosive.mdl", - SurfaceArea = 5128.9, - Volume = 26794.4, - }) - - ACF.RegisterFuelTank("Jerry_Can", { - Name = "Jerry Can", - Description = "Handy portable fuel container.", - Model = "models/props_junk/gascan001a.mdl", - SurfaceArea = 1839.7, - Volume = 4384.1,, - }) - - ACF.RegisterFuelTank("Transport_Tank", { - Name = "Transport Tank", - Description = "Disappointingly non-explosive.", - Model = "models/props_wasteland/horizontalcoolingtank04.mdl", - SurfaceArea = 127505.5, - Volume = 2102493.3, - IsExplosive = false, - Unlinkable = true, - }) - - ACF.RegisterFuelTank("Storage_Tank", { - Name = "Storage Tank", - Description = "Disappointingly non-explosive.", - Model = "models/props_wasteland/coolingtank02.mdl", - SurfaceArea = 144736.3, - Volume = 2609960, - IsExplosive = false, - Unlinkable = true, - }) -end diff --git a/lua/acf/shared/fueltanks/misc.lua b/lua/acf/shared/fueltanks/misc.lua new file mode 100644 index 000000000..770f9635a --- /dev/null +++ b/lua/acf/shared/fueltanks/misc.lua @@ -0,0 +1,42 @@ +ACF.RegisterFuelTankClass("FTS_M", { + Name = "Miscellaneous", + Description = "Guaranteed to improve engine performance by " .. (ACF.TorqueBoost - 1) * 100 .. "%", +}) + +do + ACF.RegisterFuelTank("Fuel_Drum","FTS_M", { + Name = "Fuel Drum", + Description = "Tends to explode when shot.", + Model = "models/props_c17/oildrum001_explosive.mdl", + SurfaceArea = 5128.9, + Volume = 26794.4, + }) + + ACF.RegisterFuelTank("Jerry_Can","FTS_M", { + Name = "Jerry Can", + Description = "Handy portable fuel container.", + Model = "models/props_junk/gascan001a.mdl", + SurfaceArea = 1839.7, + Volume = 4384.1, + }) + + ACF.RegisterFuelTank("Transport_Tank","FTS_M", { + Name = "Transport Tank", + Description = "Disappointingly non-explosive.", + Model = "models/props_wasteland/horizontalcoolingtank04.mdl", + SurfaceArea = 127505.5, + Volume = 2102493.3, + IsExplosive = false, + Unlinkable = true, + }) + + ACF.RegisterFuelTank("Storage_Tank","FTS_M", { + Name = "Storage Tank", + Description = "Disappointingly non-explosive.", + Model = "models/props_wasteland/coolingtank02.mdl", + SurfaceArea = 144736.3, + Volume = 2609960, + IsExplosive = false, + Unlinkable = true, + }) +end diff --git a/lua/acf/shared/fueltanks/size_eight.lua b/lua/acf/shared/fueltanks/size_eight.lua new file mode 100644 index 000000000..8de1a289f --- /dev/null +++ b/lua/acf/shared/fueltanks/size_eight.lua @@ -0,0 +1,30 @@ +ACF.RegisterFuelTankClass("FTS_8", { + Name = "Size 8 Container", + Description = "Guaranteed to improve engine performance by " .. (ACF.TorqueBoost - 1) * 100 .. "%", +}) + +do + ACF.RegisterFuelTank("Tank_8x8x1","FTS_8", { + Name = "8x8x1 Container", + Description = "Sloshy sloshy!", + Model = "models/fueltank/fueltank_8x8x1.mdl", + SurfaceArea = 15524.8, + Volume = 64794.2, + }) + + ACF.RegisterFuelTank("Tank_8x8x2","FTS_8", { + Name = "8x8x2 Container", + Description = "What's global warming?", + Model = "models/fueltank/fueltank_8x8x2.mdl", + SurfaceArea = 18086.4, + Volume = 125868.9, + }) + + ACF.RegisterFuelTank("Tank_8x8x4","FTS_8", { + Name = "8x8x4 Container", + Description = "Tank Tank.", + Model = "models/fueltank/fueltank_8x8x4.mdl", + SurfaceArea = 23957.6, + Volume = 246845.3, + }) +end diff --git a/lua/acf/shared/fueltanks/size_four.lua b/lua/acf/shared/fueltanks/size_four.lua new file mode 100644 index 000000000..773e2c02e --- /dev/null +++ b/lua/acf/shared/fueltanks/size_four.lua @@ -0,0 +1,78 @@ +ACF.RegisterFuelTankClass("FTS_4", { + Name = "Size 4 Container", + Description = "Guaranteed to improve engine performance by " .. (ACF.TorqueBoost - 1) * 100 .. "%", +}) + +do + ACF.RegisterFuelTank("Tank_4x4x1","FTS_4", { + Name = "4x4x1 Container", + Description = "Sedan.", + Model = "models/fueltank/fueltank_4x4x1.mdl", + SurfaceArea = 4619.1, + Volume = 16539.8, + }) + + ACF.RegisterFuelTank("Tank_4x4x2","FTS_4", { + Name = "4x4x2 Container", + Description = "Land boat.", + Model = "models/fueltank/fueltank_4x4x2.mdl", + SurfaceArea = 6071.4, + Volume = 32165.2, + }) + + ACF.RegisterFuelTank("Tank_4x4x4","FTS_4", { + Name = "4x4x4 Container", + Description = "Popular with arsonists.", + Model = "models/fueltank/fueltank_4x4x4.mdl", + SurfaceArea = 9145.3, + Volume = 62900.1, + }) + + ACF.RegisterFuelTank("Tank_4x6x1","FTS_4", { + Name = "4x6x1 Container", + Description = "Conformal fuel tank, fits in tight spaces.", + Model = "models/fueltank/fueltank_4x6x1.mdl", + SurfaceArea = 6553.6, + Volume = 24918.6, + }) + + ACF.RegisterFuelTank("Tank_4x6x2","FTS_4", { + Name = "4x6x2 Container", + Description = "Fire juice.", + Model = "models/fueltank/fueltank_4x6x2.mdl", + SurfaceArea = 8425.3, + Volume = 48581.2, + }) + + ACF.RegisterFuelTank("Tank_4x6x4","FTS_4", { + Name = "4x6x4 Container", + Description = "Trees are gay anyway.", + Model = "models/fueltank/fueltank_4x6x4.mdl", + SurfaceArea = 12200.6, + Volume = 94640, + }) + + ACF.RegisterFuelTank("Tank_4x8x1","FTS_4", { + Name = "4x8x1 Container", + Description = "Arson material.", + Model = "models/fueltank/fueltank_4x8x1.mdl", + SurfaceArea = 8328.2, + Volume = 32541.9, + }) + + ACF.RegisterFuelTank("Tank_4x8x2","FTS_4", { + Name = "4x8x2 Container", + Description = "What's a gas station?", + Model = "models/fueltank/fueltank_4x8x2.mdl", + SurfaceArea = 10419.5, + Volume = 63167.1, + }) + + ACF.RegisterFuelTank("Tank_4x8x4","FTS_4", { + Name = "4x8x4 Container", + Description = "\'MURRICA FUCKYEAH!", + Model = "models/fueltank/fueltank_4x8x4.mdl", + SurfaceArea = 14993.3, + Volume = 123693.2, + }) +end diff --git a/lua/acf/shared/fueltanks/size_one.lua b/lua/acf/shared/fueltanks/size_one.lua new file mode 100644 index 000000000..587c2df37 --- /dev/null +++ b/lua/acf/shared/fueltanks/size_one.lua @@ -0,0 +1,126 @@ +ACF.RegisterFuelTankClass("FTS_1", { + Name = "Size 1 Container", + Description = "Guaranteed to improve engine performance by " .. (ACF.TorqueBoost - 1) * 100 .. "%", +}) + +do + ACF.RegisterFuelTank("Tank_1x1x1","FTS_1", { + Name = "1x1x1 Container", + Description = "Seriously consider walking.", + Model = "models/fueltank/fueltank_1x1x1.mdl", + SurfaceArea = 590.5, + Volume = 1019.9, + }) + + ACF.RegisterFuelTank("Tank_1x1x2","FTS_1", { + Name = "1x1x2 Container", + Description = "Will keep a kart running all day.", + Model = "models/fueltank/fueltank_1x1x2.mdl", + SurfaceArea = 974, + Volume = 1983.1, + }) + + ACF.RegisterFuelTank("Tank_1x1x4","FTS_1", { + Name = "1x1x4 Container", + Description = "Dinghy", + Model = "models/fueltank/fueltank_1x1x4.mdl", + SurfaceArea = 1777.4, + Volume = 3995.1, + }) + + ACF.RegisterFuelTank("Tank_1x2x1","FTS_1", { + Name = "1x2x1 Container", + Description = "Will keep a kart running all day.", + Model = "models/fueltank/fueltank_1x2x1.mdl", + SurfaceArea = 995, + Volume = 2062.5, + }) + + ACF.RegisterFuelTank("Tank_1x2x2","FTS_1", { + Name = "1x2x2 Container", + Description = "Dinghy", + Model = "models/fueltank/fueltank_1x2x2.mdl", + SurfaceArea = 1590.8, + Volume = 4070.9, + }) + + ACF.RegisterFuelTank("Tank_1x2x4","FTS_1", { + Name = "1x2x4 Container", + Description = "Outboard motor.", + Model = "models/fueltank/fueltank_1x2x4.mdl", + SurfaceArea = 2796.6, + Volume = 8119.2, + }) + + ACF.RegisterFuelTank("Tank_1x4x1","FTS_1", { + Name = "1x4x1 Container", + Description = "Dinghy", + Model = "models/fueltank/fueltank_1x4x1.mdl", + SurfaceArea = 1745.6, + Volume = 3962, + }) + + ACF.RegisterFuelTank("Tank_1x4x2","FTS_1", { + Name = "1x4x2 Container", + Description = "Clown car.", + Model = "models/fueltank/fueltank_1x4x2.mdl", + SurfaceArea = 2753.9, + Volume = 8018, + }) + + ACF.RegisterFuelTank("Tank_1x4x4","FTS_1", { + Name = "1x4x4 Container", + Description = "Fuel pancake.", + Model = "models/fueltank/fueltank_1x4x4.mdl", + SurfaceArea = 4761, + Volume = 16030.4, + }) + + ACF.RegisterFuelTank("Tank_1x6x1","FTS_1", { + Name = "1x6x1 Container", + Description = "Lawn tractors.", + Model = "models/fueltank/fueltank_1x6x1.mdl", + SurfaceArea = 2535.3, + Volume = 5973.1, + }) + + ACF.RegisterFuelTank("Tank_1x6x2","FTS_1", { + Name = "1x6x2 Container", + Description = "Small tractor tank.", + Model = "models/fueltank/fueltank_1x6x2.mdl", + SurfaceArea = 3954.1, + Volume = 12100.3, + }) + + ACF.RegisterFuelTank("Tank_1x6x4","FTS_1", { + Name = "1x6x4 Container", + Description = "Fuel. Will keep you going for awhile.", + Model = "models/fueltank/fueltank_1x6x4.mdl", + SurfaceArea = 6743.3, + Volume = 24109.4, + }) + + ACF.RegisterFuelTank("Tank_1x8x1","FTS_1", { + Name = "1x8x1 Container", + Description = "Clown car.", + Model = "models/fueltank/fueltank_1x8x1.mdl", + SurfaceArea = 3315.5, + Volume = 7962.4, + }) + + ACF.RegisterFuelTank("Tank_1x8x2","FTS_1", { + Name = "1x8x2 Container", + Description = "Gas stations? We don't need no stinking gas stations!", + Model = "models/fueltank/fueltank_1x8x2.mdl", + SurfaceArea = 5113.7, + Volume = 16026.2, + }) + + ACF.RegisterFuelTank("Tank_1x8x4","FTS_1", { + Name = "1x8x4 Container", + Description = "Beep beep.", + Model = "models/fueltank/fueltank_1x8x4.mdl", + SurfaceArea = 8696, + Volume = 31871, + }) +end diff --git a/lua/acf/shared/fueltanks/size_six.lua b/lua/acf/shared/fueltanks/size_six.lua new file mode 100644 index 000000000..414a9403d --- /dev/null +++ b/lua/acf/shared/fueltanks/size_six.lua @@ -0,0 +1,54 @@ +ACF.RegisterFuelTankClass("FTS_6", { + Name = "Size 6 Container", + Description = "Guaranteed to improve engine performance by " .. (ACF.TorqueBoost - 1) * 100 .. "%", +}) + +do + ACF.RegisterFuelTank("Tank_6x6x1","FTS_6", { + Name = "6x6x1 Container", + Description = "Got gas?", + Model = "models/fueltank/fueltank_6x6x1.mdl", + SurfaceArea = 9405.2, + Volume = 37278.5, + }) + + ACF.RegisterFuelTank("Tank_6x6x2","FTS_6", { + Name = "6x6x2 Container", + Description = "Drive across the desert without a fuck to give.", + Model = "models/fueltank/fueltank_6x6x2.mdl", + SurfaceArea = 11514.5, + Volume = 73606.2, + }) + + ACF.RegisterFuelTank("Tank_6x6x4","FTS_6", { + Name = "6x6x4 Container", + Description = "May contain Mesozoic ghosts.", + Model = "models/fueltank/fueltank_6x6x4.mdl", + SurfaceArea = 16028.8, + Volume = 143269, + }) + + ACF.RegisterFuelTank("Tank_6x8x1","FTS_6", { + Name = "6x8x1 Container", + Description = "Conformal fuel tank, does what all its friends do.", + Model = "models/fueltank/fueltank_6x8x1.mdl", + SurfaceArea = 12131.1, + Volume = 48480.2, + }) + + ACF.RegisterFuelTank("Tank_6x8x2","FTS_6", { + Name = "6x8x2 Container", + Description = "Certified 100% dinosaur juice.", + Model = "models/fueltank/fueltank_6x8x2.mdl", + SurfaceArea = 14403.8, + Volume = 95065.5, + }) + + ACF.RegisterFuelTank("Tank_6x8x4","FTS_6", { + Name = "6x8x4 Container", + Description = "Will last you a while.", + Model = "models/fueltank/fueltank_6x8x4.mdl", + SurfaceArea = 19592.4, + Volume = 187296.4, + }) +end diff --git a/lua/acf/shared/fueltanks/size_two.lua b/lua/acf/shared/fueltanks/size_two.lua new file mode 100644 index 000000000..21fe192e0 --- /dev/null +++ b/lua/acf/shared/fueltanks/size_two.lua @@ -0,0 +1,102 @@ +ACF.RegisterFuelTankClass("FTS_2", { + Name = "Size 2 Container", + Description = "Guaranteed to improve engine performance by " .. (ACF.TorqueBoost - 1) * 100 .. "%", +}) + +do + ACF.RegisterFuelTank("Tank_2x2x1","FTS_2", { + Name = "2x2x1 Container", + Description = "Dinghy", + Model = "models/fueltank/fueltank_2x2x1.mdl", + SurfaceArea = 1592.2, + Volume = 4285.2, + }) + + ACF.RegisterFuelTank("Tank_2x2x2","FTS_2", { + Name = "2x2x2 Container", + Description = "Clown car.", + Model = "models/fueltank/fueltank_2x2x2.mdl", + SurfaceArea = 2360.4, + Volume = 8212.9, + }) + + ACF.RegisterFuelTank("Tank_2x2x4","FTS_2", { + Name = "2x2x4 Container", + Description = "Mini Cooper.", + Model = "models/fueltank/fueltank_2x2x4.mdl", + SurfaceArea = 3988.6, + Volume = 16362, + }) + + ACF.RegisterFuelTank("Tank_2x4x1","FTS_2", { + Name = "2x4x1 Container", + Description = "Good bit of go-juice.", + Model = "models/fueltank/fueltank_2x4x1.mdl", + SurfaceArea = 2808.8, + Volume = 8628, + }) + + ACF.RegisterFuelTank("Tank_2x4x2","FTS_2", { + Name = "2x4x2 Container", + Description = "Mini Cooper.", + Model = "models/fueltank/fueltank_2x4x2.mdl", + SurfaceArea = 3996.1, + Volume = 16761.4, + }) + + ACF.RegisterFuelTank("Tank_2x4x4","FTS_2", { + Name = "2x4x4 Container", + Description = "Land boat.", + Model = "models/fueltank/fueltank_2x4x4.mdl", + SurfaceArea = 6397.3, + Volume = 32854.4, + }) + + ACF.RegisterFuelTank("Tank_2x6x1","FTS_2", { + Name = "2x6x1 Container", + Description = "Conformal fuel tank, fits narrow spaces.", + Model = "models/fueltank/fueltank_2x6x1.mdl", + SurfaceArea = 3861.4, + Volume = 12389.9, + }) + + ACF.RegisterFuelTank("Tank_2x6x2","FTS_2", { + Name = "2x6x2 Container", + Description = "Compact car.", + Model = "models/fueltank/fueltank_2x6x2.mdl", + SurfaceArea = 5388, + Volume = 24127.7, + }) + + ACF.RegisterFuelTank("Tank_2x6x4","FTS_2", { + Name = "2x6x4 Container", + Description = "Sedan.", + Model = "models/fueltank/fueltank_2x6x4.mdl", + SurfaceArea = 8485.6, + Volume = 47537.2, + }) + + ACF.RegisterFuelTank("Tank_2x8x1","FTS_2", { + Name = "2x8x1 Container", + Description = "Conformal fuel tank, fits into tight spaces", + Model = "models/fueltank/fueltank_2x8x1.mdl", + SurfaceArea = 5094.5, + Volume = 16831.8, + }) + + ACF.RegisterFuelTank("Tank_2x8x2","FTS_2", { + Name = "2x8x2 Container", + Description = "Truck.", + Model = "models/fueltank/fueltank_2x8x2.mdl", + SurfaceArea = 6980, + Volume = 32275.9, + }) + + ACF.RegisterFuelTank("Tank_2x8x4","FTS_2", { + Name = "2x8x4 Container", + Description = "With great capacity, comes great responsibili--VROOOOM", + Model = "models/fueltank/fueltank_2x8x4.mdl", + SurfaceArea = 10898.2, + Volume = 63976, + }) +end From 4b15d3b730f2329126f04fce3ce3e6f46580a9b8 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Fri, 20 Mar 2020 03:04:45 -0300 Subject: [PATCH 040/279] Added engine type registration function - Added ACF.RegisterEngineType function to help developers add new engine types without much problems. --- lua/acf/base/sh_classes.lua | 27 ++++++++++++++++++- lua/acf/base/sh_round_functions.lua | 1 + lua/acf/shared/engine_types/electric.lua | 6 +++++ .../shared/engine_types/generic_diesel.lua | 6 +++++ .../shared/engine_types/generic_petrol.lua | 6 +++++ lua/acf/shared/engine_types/radial.lua | 6 +++++ lua/acf/shared/engine_types/turbine.lua | 6 +++++ 7 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 lua/acf/shared/engine_types/electric.lua create mode 100644 lua/acf/shared/engine_types/generic_diesel.lua create mode 100644 lua/acf/shared/engine_types/generic_petrol.lua create mode 100644 lua/acf/shared/engine_types/radial.lua create mode 100644 lua/acf/shared/engine_types/turbine.lua diff --git a/lua/acf/base/sh_classes.lua b/lua/acf/base/sh_classes.lua index 2b821c744..78ac79da9 100644 --- a/lua/acf/base/sh_classes.lua +++ b/lua/acf/base/sh_classes.lua @@ -230,7 +230,32 @@ do -- Engine registration functions end end -do -- Fuel tank registration function +do -- Engine type registration function + ACF.Classes.EngineTypes = ACF.Classes.EngineTypes or {} + + local Types = ACF.Classes.EngineTypes + + function ACF.RegisterEngineType(ID, Data) + if not ID then return end + if not Data then return end + + local Type = Types[ID] + + if not Type then + Type = { + ID = ID, + } + + Types[ID] = Type + end + + for K, V in pairs(Data) do + Type[K] = V + end + end +end + +do -- Fuel tank registration functions ACF.Classes.FuelTanks = ACF.Classes.FuelTanks or {} local FuelTanks = ACF.Classes.FuelTanks diff --git a/lua/acf/base/sh_round_functions.lua b/lua/acf/base/sh_round_functions.lua index d7a7dcc88..b7b70e8a9 100644 --- a/lua/acf/base/sh_round_functions.lua +++ b/lua/acf/base/sh_round_functions.lua @@ -55,6 +55,7 @@ local Ignore = { Radar = true, Rack = true, -- New/upcoming + EngineTypes = true, Components = true, AmmoTypes = true, FuelTanks = true, diff --git a/lua/acf/shared/engine_types/electric.lua b/lua/acf/shared/engine_types/electric.lua new file mode 100644 index 000000000..312c78833 --- /dev/null +++ b/lua/acf/shared/engine_types/electric.lua @@ -0,0 +1,6 @@ +ACF.RegisterEngineType("Electric", { + Name = "Generic Electric Engine", + Efficiency = 0.85, --percent efficiency converting chemical kw into mechanical kw + TorqueScale = 0.5, + HealthMult = 0.75, +}) diff --git a/lua/acf/shared/engine_types/generic_diesel.lua b/lua/acf/shared/engine_types/generic_diesel.lua new file mode 100644 index 000000000..f1a1e27d5 --- /dev/null +++ b/lua/acf/shared/engine_types/generic_diesel.lua @@ -0,0 +1,6 @@ +ACF.RegisterEngineType("GenericDiesel", { + Name = "Generic Diesel Engine", + Efficiency = 0.243, --up to 0.274 + TorqueScale = 0.35, + HealthMult = 0.5, +}) diff --git a/lua/acf/shared/engine_types/generic_petrol.lua b/lua/acf/shared/engine_types/generic_petrol.lua new file mode 100644 index 000000000..55e2286e6 --- /dev/null +++ b/lua/acf/shared/engine_types/generic_petrol.lua @@ -0,0 +1,6 @@ +ACF.RegisterEngineType("GenericPetrol", { + Name = "Generic Petrol Engine", + Efficiency = 0.304, --kg per kw hr + TorqueScale = 0.25, + HealthMult = 0.2, +}) diff --git a/lua/acf/shared/engine_types/radial.lua b/lua/acf/shared/engine_types/radial.lua new file mode 100644 index 000000000..1c7c8296f --- /dev/null +++ b/lua/acf/shared/engine_types/radial.lua @@ -0,0 +1,6 @@ +ACF.RegisterEngineType("Radial", { + Name = "Generic Radial Engine", + Efficiency = 0.4, -- 0.38 to 0.53 + TorqueScale = 0.3, + HealthMult = 0.3, +}) diff --git a/lua/acf/shared/engine_types/turbine.lua b/lua/acf/shared/engine_types/turbine.lua new file mode 100644 index 000000000..6abb95a71 --- /dev/null +++ b/lua/acf/shared/engine_types/turbine.lua @@ -0,0 +1,6 @@ +ACF.RegisterEngineType("Turbine", { + Name = "Generic Turbine", + Efficiency = 0.375, -- previously 0.231 + TorqueScale = 0.2, + HealthMult = 0.125, +}) From e87c458751f86040c7a10c6161b11dedd99fadae Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Fri, 20 Mar 2020 03:06:54 -0300 Subject: [PATCH 041/279] Added fuel type registration function - Added ACF.RegisterFuelType function to help developers add new fuel types to ACF. - Added missing Wankel engine type. --- lua/acf/base/sh_classes.lua | 25 +++++++++++++++++++++++++ lua/acf/base/sh_round_functions.lua | 1 + lua/acf/shared/engine_types/wankel.lua | 6 ++++++ lua/acf/shared/fuel_types/diesel.lua | 4 ++++ lua/acf/shared/fuel_types/electric.lua | 17 +++++++++++++++++ lua/acf/shared/fuel_types/petrol.lua | 4 ++++ 6 files changed, 57 insertions(+) create mode 100644 lua/acf/shared/engine_types/wankel.lua create mode 100644 lua/acf/shared/fuel_types/diesel.lua create mode 100644 lua/acf/shared/fuel_types/electric.lua create mode 100644 lua/acf/shared/fuel_types/petrol.lua diff --git a/lua/acf/base/sh_classes.lua b/lua/acf/base/sh_classes.lua index 78ac79da9..9c6ec7f27 100644 --- a/lua/acf/base/sh_classes.lua +++ b/lua/acf/base/sh_classes.lua @@ -310,3 +310,28 @@ do -- Fuel tank registration functions end end end + +do -- Fuel type registration function + ACF.Classes.FuelTypes = ACF.Classes.FuelTypes or {} + + local Types = ACF.Classes.FuelTypes + + function ACF.RegisterFuelType(ID, Data) + if not ID then return end + if not Data then return end + + local Type = Types[ID] + + if not Type then + Type = { + ID = ID, + } + + Types[ID] = Type + end + + for K, V in pairs(Data) do + Type[K] = V + end + end +end diff --git a/lua/acf/base/sh_round_functions.lua b/lua/acf/base/sh_round_functions.lua index b7b70e8a9..22032d487 100644 --- a/lua/acf/base/sh_round_functions.lua +++ b/lua/acf/base/sh_round_functions.lua @@ -59,6 +59,7 @@ local Ignore = { Components = true, AmmoTypes = true, FuelTanks = true, + FuelTypes = true, Gearboxes = true, Guidances = true, Engines = true, diff --git a/lua/acf/shared/engine_types/wankel.lua b/lua/acf/shared/engine_types/wankel.lua new file mode 100644 index 000000000..1fc873469 --- /dev/null +++ b/lua/acf/shared/engine_types/wankel.lua @@ -0,0 +1,6 @@ +ACF.RegisterEngineType("Wankel", { + Name = "Generic Wankel Engine", + Efficiency = 0.335, + TorqueScale = 0.2, + HealthMult = 0.125, +}) diff --git a/lua/acf/shared/fuel_types/diesel.lua b/lua/acf/shared/fuel_types/diesel.lua new file mode 100644 index 000000000..04f092787 --- /dev/null +++ b/lua/acf/shared/fuel_types/diesel.lua @@ -0,0 +1,4 @@ +ACF.RegisterFuelType("Diesel", { + Name = "Diesel Fuel", + Density = 0.745, +}) diff --git a/lua/acf/shared/fuel_types/electric.lua b/lua/acf/shared/fuel_types/electric.lua new file mode 100644 index 000000000..02f2ccf15 --- /dev/null +++ b/lua/acf/shared/fuel_types/electric.lua @@ -0,0 +1,17 @@ +ACF.RegisterFuelType("Electric", { + Name = "Lit-Ion Battery", + Density = 3.89, + ConsumptionText = function(PeakkW, _, TypeData) + local Text = "\n\nPeak Energy Consumption :\n%s kW - %s MJ/min" + local Rate = ACF.ElecRate * PeakkW / TypeData.Efficiency + + return Text:format(math.Round(Rate, 2), math.Round(Rate * 0.06, 2)) + end, + FuelTankText = function(Capacity, Mass) + local Text = "\n\nCharge : %s kW per hour - %s MJ\nMass : %s" + local kWh = math.Round(Capacity * ACF.LiIonED, 2) + local MJ = math.Round(Capacity * ACF.LiIonED * 3.6, 2) + + return Text:format(kWh, MJ, ACF.GetProperMass(Mass)) + end, +}) diff --git a/lua/acf/shared/fuel_types/petrol.lua b/lua/acf/shared/fuel_types/petrol.lua new file mode 100644 index 000000000..2b2e47558 --- /dev/null +++ b/lua/acf/shared/fuel_types/petrol.lua @@ -0,0 +1,4 @@ +ACF.RegisterFuelType("Petrol", { + Name = "Petrol Fuel", + Density = 0.832, +}) From 8f4fc4b7aa81299f978d8f090a33a4eeb519067d Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Fri, 20 Mar 2020 03:09:32 -0300 Subject: [PATCH 042/279] Modified engine fuel type especification - Fuel type especification on engine definitions will now use a lookup table with fuel type IDs registered with ACF.RegisterFuelType. - Multifuel fuel type is no longer a thing. --- lua/acf/shared/engines/b4.lua | 8 ++++---- lua/acf/shared/engines/b6.lua | 8 ++++---- lua/acf/shared/engines/electric.lua | 12 ++++++------ lua/acf/shared/engines/i2.lua | 4 ++-- lua/acf/shared/engines/i3.lua | 12 ++++++------ lua/acf/shared/engines/i4.lua | 12 ++++++------ lua/acf/shared/engines/i5.lua | 8 ++++---- lua/acf/shared/engines/i6.lua | 12 ++++++------ lua/acf/shared/engines/radial.lua | 8 ++++---- lua/acf/shared/engines/rotary.lua | 6 +++--- lua/acf/shared/engines/single.lua | 6 +++--- lua/acf/shared/engines/special.lua | 22 +++++++++++----------- lua/acf/shared/engines/turbine.lua | 24 ++++++++++++------------ lua/acf/shared/engines/v10.lua | 6 +++--- lua/acf/shared/engines/v12.lua | 14 +++++++------- lua/acf/shared/engines/v2.lua | 6 +++--- lua/acf/shared/engines/v4.lua | 4 ++-- lua/acf/shared/engines/v6.lua | 10 +++++----- lua/acf/shared/engines/v8.lua | 12 ++++++------ 19 files changed, 97 insertions(+), 97 deletions(-) diff --git a/lua/acf/shared/engines/b4.lua b/lua/acf/shared/engines/b4.lua index 749234862..a6dbdc3d6 100644 --- a/lua/acf/shared/engines/b4.lua +++ b/lua/acf/shared/engines/b4.lua @@ -79,7 +79,7 @@ do Description = "Small air cooled flat four, most commonly found in nazi insects", Model = "models/engines/b4small.mdl", Sound = "acf_engines/b4_petrolsmall.wav", - Fuel = "Petrol", + Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 60, Torque = 105, @@ -97,7 +97,7 @@ do Description = "Tuned up flat four, probably find this in things that go fast in a desert.", Model = "models/engines/b4small.mdl", Sound = "acf_engines/b4_petrolmedium.wav", - Fuel = "Petrol", + Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 125, Torque = 180, @@ -115,7 +115,7 @@ do Description = "Tiny military-grade multifuel. Heavy, but grunts hard.", Model = "models/engines/b4small.mdl", Sound = "acf_extra/vehiclefx/engines/coh/ba11.wav", - Fuel = "Multifuel", + Fuel = { Petrol = true, Diesel = true }, Type = "GenericDiesel", Mass = 135, Torque = 248, @@ -133,7 +133,7 @@ do Description = "Bored out fuckswindleton batshit flat four. Fuck yourself.", Model = "models/engines/b4med.mdl", Sound = "acf_engines/b4_petrollarge.wav", - Fuel = "Petrol", + Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 210, Torque = 252, diff --git a/lua/acf/shared/engines/b6.lua b/lua/acf/shared/engines/b6.lua index 22addad09..2d822f5ef 100644 --- a/lua/acf/shared/engines/b6.lua +++ b/lua/acf/shared/engines/b6.lua @@ -80,7 +80,7 @@ do Description = "Car sized flat six engine, sporty and light", Model = "models/engines/b6small.mdl", Sound = "acf_engines/b6_petrolsmall.wav", - Fuel = "Petrol", + Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 100, Torque = 136, @@ -98,7 +98,7 @@ do Description = "Sports car grade flat six, renown for their smooth operation and light weight", Model = "models/engines/b6med.mdl", Sound = "acf_engines/b6_petrolmedium.wav", - Fuel = "Petrol", + Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 240, Torque = 330, @@ -116,7 +116,7 @@ do Description = "Military-grade multifuel boxer engine. Although heavy, it is compact, durable, and has excellent performance under adverse conditions.", Model = "models/engines/b6med.mdl", Sound = "acf_engines/v8_diesel.wav", - Fuel = "Multifuel", + Fuel = { Petrol = true, Diesel = true }, Type = "GenericDiesel", Mass = 480, Torque = 565, @@ -134,7 +134,7 @@ do Description = "Monstrous aircraft-grade boxer with a high rev range biased powerband", Model = "models/engines/b6large.mdl", Sound = "acf_engines/b6_petrollarge.wav", - Fuel = "Petrol", + Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 725, Torque = 1100, diff --git a/lua/acf/shared/engines/electric.lua b/lua/acf/shared/engines/electric.lua index a884b3b10..63cafe4e6 100644 --- a/lua/acf/shared/engines/electric.lua +++ b/lua/acf/shared/engines/electric.lua @@ -149,7 +149,7 @@ do -- Electric Motors Description = "A small electric motor, loads of torque, but low power.", Model = "models/engines/emotorsmall.mdl", Sound = "acf_engines/electric_small.wav", - Fuel = "Electric", + Fuel = { Electric = true }, Type = "Electric", Mass = 250, Torque = 384, @@ -169,7 +169,7 @@ do -- Electric Motors Description = "A medium electric motor, loads of torque, but low power.", Model = "models/engines/emotormed.mdl", Sound = "acf_engines/electric_medium.wav", - Fuel = "Electric", + Fuel = { Electric = true }, Type = "Electric", Mass = 850, Torque = 1152, @@ -189,7 +189,7 @@ do -- Electric Motors Description = "A huge electric motor, loads of torque, but low power.", Model = "models/engines/emotorlarge.mdl", Sound = "acf_engines/electric_large.wav", - Fuel = "Electric", + Fuel = { Electric = true }, Type = "Electric", Mass = 1900, Torque = 3360, @@ -216,7 +216,7 @@ do -- Electric Standalone Motors Description = "A small standalone electric motor, loads of torque, but low power.", Model = "models/engines/emotor-standalone-sml.mdl", Sound = "acf_engines/electric_small.wav", - Fuel = "Electric", + Fuel = { Electric = true }, Type = "Electric", Mass = 125, Torque = 384, @@ -237,7 +237,7 @@ do -- Electric Standalone Motors Description = "A medium standalone electric motor, loads of torque, but low power.", Model = "models/engines/emotor-standalone-mid.mdl", Sound = "acf_engines/electric_medium.wav", - Fuel = "Electric", + Fuel = { Electric = true }, Type = "Electric", Mass = 575, Torque = 1152, @@ -258,7 +258,7 @@ do -- Electric Standalone Motors Description = "A huge standalone electric motor, loads of torque, but low power.", Model = "models/engines/emotor-standalone-big.mdl", Sound = "acf_engines/electric_large.wav", - Fuel = "Electric", + Fuel = { Electric = true }, Type = "Electric", Mass = 1500, Torque = 3360, diff --git a/lua/acf/shared/engines/i2.lua b/lua/acf/shared/engines/i2.lua index 51a91acf6..3f3a703c1 100644 --- a/lua/acf/shared/engines/i2.lua +++ b/lua/acf/shared/engines/i2.lua @@ -47,7 +47,7 @@ do Description = "For when a 3 banger is still too bulky for your micro-needs.", Model = "models/engines/inline2s.mdl", Sound = "acf_engines/i4_diesel2.wav", - Fuel = "Diesel", + Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 45, Torque = 105, @@ -65,7 +65,7 @@ do Description = "TORQUE.", Model = "models/engines/inline2b.mdl", Sound = "acf_engines/vtwin_large.wav", - Fuel = "Diesel", + Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 800, Torque = 2000, diff --git a/lua/acf/shared/engines/i3.lua b/lua/acf/shared/engines/i3.lua index 4a49f142b..524f5c15a 100644 --- a/lua/acf/shared/engines/i3.lua +++ b/lua/acf/shared/engines/i3.lua @@ -117,7 +117,7 @@ do -- Petrol Engines Description = "Tiny microcar engine, efficient but weak.", Model = "models/engines/inline3s.mdl", Sound = "acf_engines/i4_petrolsmall2.wav", - Fuel = "Petrol", + Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 40, Torque = 95, @@ -135,7 +135,7 @@ do -- Petrol Engines Description = "Short block engine for light utility use.", Model = "models/engines/inline3m.mdl", Sound = "acf_engines/i4_petrolmedium2.wav", - Fuel = "Petrol", + Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 170, Torque = 195, @@ -153,7 +153,7 @@ do -- Petrol Engines Description = "Short block light tank engine, likes sideways mountings.", Model = "models/engines/inline3b.mdl", Sound = "acf_engines/i4_petrollarge.wav", - Fuel = "Petrol", + Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 500, Torque = 715, @@ -173,7 +173,7 @@ do -- Diesel Engines Description = "ATV grade 3-banger, enormous rev band but a choppy idle, great for light utility work.", Model = "models/engines/inline3s.mdl", Sound = "acf_engines/i4_diesel2.wav", - Fuel = "Diesel", + Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 65, Torque = 150, @@ -191,7 +191,7 @@ do -- Diesel Engines Description = "Medium utility grade I3 diesel, for tractors", Model = "models/engines/inline3m.mdl", Sound = "acf_engines/i4_dieselmedium.wav", - Fuel = "Diesel", + Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 200, Torque = 290, @@ -209,7 +209,7 @@ do -- Diesel Engines Description = "Light tank duty engine, compact yet grunts hard.", Model = "models/engines/inline3b.mdl", Sound = "acf_engines/i4_diesellarge.wav", - Fuel = "Diesel", + Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 650, Torque = 1200, diff --git a/lua/acf/shared/engines/i4.lua b/lua/acf/shared/engines/i4.lua index f3c2d8c41..01f7cd81a 100644 --- a/lua/acf/shared/engines/i4.lua +++ b/lua/acf/shared/engines/i4.lua @@ -117,7 +117,7 @@ do -- Petrol Engines Description = "Small car engine, not a whole lot of git.", Model = "models/engines/inline4s.mdl", Sound = "acf_engines/i4_petrolsmall2.wav", - Fuel = "Petrol", + Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 50, Torque = 90, @@ -135,7 +135,7 @@ do -- Petrol Engines Description = "Large inline 4, sees most use in light trucks.", Model = "models/engines/inline4m.mdl", Sound = "acf_engines/i4_petrolmedium2.wav", - Fuel = "Petrol", + Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 200, Torque = 240, @@ -153,7 +153,7 @@ do -- Petrol Engines Description = "Giant, thirsty I4 petrol, most commonly used in boats.", Model = "models/engines/inline4l.mdl", Sound = "acf_engines/i4_petrollarge.wav", - Fuel = "Petrol", + Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 600, Torque = 850, @@ -173,7 +173,7 @@ do -- Diesel Engines Description = "Small and light diesel, for low power applications requiring a wide powerband.", Model = "models/engines/inline4s.mdl", Sound = "acf_engines/i4_diesel2.wav", - Fuel = "Diesel", + Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 90, Torque = 150, @@ -191,7 +191,7 @@ do -- Diesel Engines Description = "Light truck duty diesel, good overall grunt.", Model = "models/engines/inline4m.mdl", Sound = "acf_engines/i4_dieselmedium.wav", - Fuel = "Diesel", + Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 250, Torque = 320, @@ -209,7 +209,7 @@ do -- Diesel Engines Description = "Small boat sized diesel, with large amounts of torque.", Model = "models/engines/inline4l.mdl", Sound = "acf_engines/i4_diesellarge.wav", - Fuel = "Diesel", + Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 800, Torque = 1400, diff --git a/lua/acf/shared/engines/i5.lua b/lua/acf/shared/engines/i5.lua index 4c19127b2..65510a84b 100644 --- a/lua/acf/shared/engines/i5.lua +++ b/lua/acf/shared/engines/i5.lua @@ -83,7 +83,7 @@ do -- Petrol Engines Description = "Sedan-grade 5-cylinder, solid and dependable.", Model = "models/engines/inline5s.mdl", Sound = "acf_engines/i5_petrolsmall.wav", - Fuel = "Petrol", + Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 100, Torque = 125, @@ -101,7 +101,7 @@ do -- Petrol Engines Description = "Truck sized inline 5, strong with a good balance of revs and torque.", Model = "models/engines/inline5m.mdl", Sound = "acf_engines/i5_petrolmedium.wav", - Fuel = "Petrol", + Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 250, Torque = 275, @@ -121,7 +121,7 @@ do -- Diesel Engines Description = "Aging fuel-injected diesel, low in horsepower but very forgiving and durable.", Model = "models/engines/inline5s.mdl", Sound = "acf_engines/i5_dieselsmall2.wav", - Fuel = "Diesel", + Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 130, Torque = 180, @@ -139,7 +139,7 @@ do -- Diesel Engines Description = "Heavier duty diesel, found in things that work hard.", Model = "models/engines/inline5m.mdl", Sound = "acf_engines/i5_dieselmedium.wav", - Fuel = "Diesel", + Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 400, Torque = 440, diff --git a/lua/acf/shared/engines/i6.lua b/lua/acf/shared/engines/i6.lua index 0ac27ecc1..a2d5fa809 100644 --- a/lua/acf/shared/engines/i6.lua +++ b/lua/acf/shared/engines/i6.lua @@ -117,7 +117,7 @@ do -- Petrol Engines Description = "Car sized I6 petrol with power in the high revs.", Model = "models/engines/inline6s.mdl", Sound = "acf_engines/l6_petrolsmall2.wav", - Fuel = "Petrol", + Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 120, Torque = 130, @@ -135,7 +135,7 @@ do -- Petrol Engines Description = "Light truck duty I6, good for offroad applications.", Model = "models/engines/inline6m.mdl", Sound = "acf_engines/l6_petrolmedium.wav", - Fuel = "Petrol", + Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 300, Torque = 360, @@ -153,7 +153,7 @@ do -- Petrol Engines Description = "Heavy tractor duty petrol I6, decent overall powerband.", Model = "models/engines/inline6l.mdl", Sound = "acf_engines/l6_petrollarge2.wav", - Fuel = "Petrol", + Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 850, Torque = 960, @@ -173,7 +173,7 @@ do -- Diesel Engines Description = "Car sized I6 diesel, good, wide powerband.", Model = "models/engines/inline6s.mdl", Sound = "acf_engines/l6_dieselsmall.wav", - Fuel = "Diesel", + Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 150, Torque = 200, @@ -191,7 +191,7 @@ do -- Diesel Engines Description = "Truck duty I6, good overall powerband and torque.", Model = "models/engines/inline6m.mdl", Sound = "acf_engines/l6_dieselmedium4.wav", - Fuel = "Diesel", + Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 450, Torque = 520, @@ -209,7 +209,7 @@ do -- Diesel Engines Description = "Heavy duty diesel I6, used in generators and heavy movers.", Model = "models/engines/inline6l.mdl", Sound = "acf_engines/l6_diesellarge2.wav", - Fuel = "Diesel", + Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 1200, Torque = 1700, diff --git a/lua/acf/shared/engines/radial.lua b/lua/acf/shared/engines/radial.lua index 1dd9e3637..e19e180d2 100644 --- a/lua/acf/shared/engines/radial.lua +++ b/lua/acf/shared/engines/radial.lua @@ -80,7 +80,7 @@ do Description = "A tiny, old worn-out radial.", Model = "models/engines/radial7s.mdl", Sound = "acf_engines/r7_petrolsmall.wav", - Fuel = "Petrol", + Fuel = { Petrol = true }, Type = "Radial", Mass = 210, Torque = 310, @@ -98,7 +98,7 @@ do Description = "Mid range radial, thirsty and smooth.", Model = "models/engines/radial7m.mdl", Sound = "acf_engines/r7_petrolmedium.wav", - Fuel = "Petrol", + Fuel = { Petrol = true }, Type = "Radial", Mass = 385, Torque = 560, @@ -116,7 +116,7 @@ do Description = "Heavy and with a narrow powerband, but efficient, and well-optimized to cruising.", Model = "models/engines/radial7m.mdl", Sound = "acf_engines/r7_petrolmedium.wav", - Fuel = "Multifuel", + Fuel = { Petrol = true, Diesel = true }, Type = "GenericDiesel", Mass = 450, Torque = 800, @@ -134,7 +134,7 @@ do Description = "Massive American radial monster, destined for fighter aircraft and heavy tanks.", Model = "models/engines/radial7l.mdl", Sound = "acf_engines/r7_petrollarge.wav", - Fuel = "Petrol", + Fuel = { Petrol = true }, Type = "Radial", Mass = 952, Torque = 1615, diff --git a/lua/acf/shared/engines/rotary.lua b/lua/acf/shared/engines/rotary.lua index 0f8b98ae9..29b3b8aa1 100644 --- a/lua/acf/shared/engines/rotary.lua +++ b/lua/acf/shared/engines/rotary.lua @@ -63,7 +63,7 @@ do Description = "Small 2-rotor Wankel, suited for yard use.", Model = "models/engines/wankel_2_small.mdl", Sound = "acf_engines/wankel_small.wav", - Fuel = "Petrol", + Fuel = { Petrol = true }, Type = "Wankel", Mass = 50, Torque = 78, @@ -81,7 +81,7 @@ do Description = "Medium 2-rotor Wankel.", Model = "models/engines/wankel_2_med.mdl", Sound = "acf_engines/wankel_medium.wav", - Fuel = "Petrol", + Fuel = { Petrol = true }, Type = "Wankel", Mass = 140, Torque = 124, @@ -99,7 +99,7 @@ do Description = "High performance 3-rotor Wankel.", Model = "models/engines/wankel_3_med.mdl", Sound = "acf_engines/wankel_large.wav", - Fuel = "Petrol", + Fuel = { Petrol = true }, Type = "Wankel", Mass = 200, Torque = 188, diff --git a/lua/acf/shared/engines/single.lua b/lua/acf/shared/engines/single.lua index 897863177..a171a0bc4 100644 --- a/lua/acf/shared/engines/single.lua +++ b/lua/acf/shared/engines/single.lua @@ -62,7 +62,7 @@ do Description = "Tiny bike engine.", model = "models/engines/1cylsml.mdl", Sound = "acf_engines/i1_small.wav", - Fuel = "Petrol", + Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 15, Torque = 20, @@ -80,7 +80,7 @@ do Description = "Large single cylinder bike engine.", Model = "models/engines/1cylmed.mdl", Sound = "acf_engines/i1_medium.wav", - Fuel = "Petrol", + Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 20, Torque = 40, @@ -98,7 +98,7 @@ do Description = "Ridiculously large single cylinder engine, seriously what the fuck.", Model = "models/engines/1cylbig.mdl", Sound = "acf_engines/i1_large.wav", - Fuel = "Petrol", + Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 50, Torque = 90, diff --git a/lua/acf/shared/engines/special.lua b/lua/acf/shared/engines/special.lua index fd4f636e7..10de5b875 100644 --- a/lua/acf/shared/engines/special.lua +++ b/lua/acf/shared/engines/special.lua @@ -211,7 +211,7 @@ do -- Special Rotary Engines Description = "4 rotor racing Wankel, high revving and high strung.", Model = "models/engines/wankel_4_med.mdl", Sound = "acf_engines/wankel_large.wav", - Fuel = "Petrol", + Fuel = { Petrol = true }, Type = "Wankel", Mass = 260, Torque = 250, @@ -232,7 +232,7 @@ do -- Special I2 Engines Description = "Turbocharged inline twin engine that delivers surprising pep for its size.", Model = "models/engines/inline2s.mdl", Sound = "acf_extra/vehiclefx/engines/ponyengine.wav", - Fuel = "Petrol", + Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 60, Torque = 116, @@ -253,7 +253,7 @@ do -- Special I4 Engines Description = "Tiny I4 designed for racing bikes. Doesn't pack much torque, but revs ludicrously high.", Model = "models/engines/inline4s.mdl", Sound = "acf_extra/vehiclefx/engines/l4/mini_onhigh.wav", - Fuel = "Petrol", + Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 78, Torque = 68, @@ -273,7 +273,7 @@ do -- Special I4 Engines Description = "Supercharged racing 4 cylinder, most of the power in the high revs.", Model = "models/engines/inline4s.mdl", Sound = "acf_engines/i4_special.wav", - Fuel = "Petrol", + Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 150, Torque = 176, @@ -294,7 +294,7 @@ do -- Special V4 Engines Description = "Naturally aspirated rally-tuned V4 with enlarged bore and stroke.", Model = "models/engines/v4s.mdl", Sound = "acf_extra/vehiclefx/engines/l4/elan_onlow.wav", - Fuel = "Petrol", + Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 92, Torque = 124.8, @@ -315,7 +315,7 @@ do -- Special I6 Engines Description = "Large racing straight six, powerful and high revving, but lacking in torque.", Model = "models/engines/inline6m.mdl", Sound = "acf_engines/l6_special.wav", - Fuel = "Petrol", + Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 180, Torque = 224, @@ -336,7 +336,7 @@ do -- Special V6 Engines Description = "Although the cast iron engine block is fairly weighty, this tiny v6 makes up for it with impressive power. The unique V angle allows uncharacteristically high RPM for a V6.", Model = "models/engines/v6small.mdl", Sound = "acf_extra/vehiclefx/engines/l6/capri_onmid.wav", - Fuel = "Petrol", + Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 134, Torque = 172, @@ -357,7 +357,7 @@ do -- Special V8 Engines Description = "Racing V8, very high revving and loud", Model = "models/engines/v8s.mdl", Sound = "acf_engines/v8_special.wav", - Fuel = "Petrol", + Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 180, Torque = 200, @@ -376,7 +376,7 @@ do -- Special V8 Engines Description = "Very high revving, glorious v8 of ear rapetasticalness.", Model = "models/engines/v8m.mdl", Sound = "acf_engines/v8_special2.wav", - Fuel = "Petrol", + Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 400, Torque = 340, @@ -397,7 +397,7 @@ do -- Special V10 Engines Description = "Extreme performance v10", Model = "models/engines/v10sml.mdl", Sound = "acf_engines/v10_special.wav", - Fuel = "Petrol", + Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 300, Torque = 320, @@ -418,7 +418,7 @@ do -- Special V12 Engines Description = "A purpose-built racing v12, not known for longevity.", Model = "models/engines/v12s.mdl", Sound = "acf_extra/vehiclefx/engines/v12/gtb4_onmid.wav", - Fuel = "Petrol", + Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 175, Torque = 248, diff --git a/lua/acf/shared/engines/turbine.lua b/lua/acf/shared/engines/turbine.lua index 77e58c30d..e616831a3 100644 --- a/lua/acf/shared/engines/turbine.lua +++ b/lua/acf/shared/engines/turbine.lua @@ -266,7 +266,7 @@ do -- Forward-facing Gas Turbines Description = "A small gas turbine, high power and a very wide powerband.", Model = "models/engines/gasturbine_s.mdl", Sound = "acf_engines/turbine_small.wav", - Fuel = "Multifuel", + Fuel = { Petrol = true, Diesel = true }, Type = "Turbine", Mass = 200, Torque = 550, @@ -287,7 +287,7 @@ do -- Forward-facing Gas Turbines Description = "A medium gas turbine, moderate power but a very wide powerband.", Model = "models/engines/gasturbine_m.mdl", Sound = "acf_engines/turbine_medium.wav", - Fuel = "Multifuel", + Fuel = { Petrol = true, Diesel = true }, Type = "Turbine", Mass = 400, Torque = 813, @@ -308,7 +308,7 @@ do -- Forward-facing Gas Turbines Description = "A large gas turbine, powerful with a wide powerband.", Model = "models/engines/gasturbine_l.mdl", Sound = "acf_engines/turbine_large.wav", - Fuel = "Multifuel", + Fuel = { Petrol = true, Diesel = true }, Type = "Turbine", Mass = 1100, Torque = 1990, @@ -331,7 +331,7 @@ do -- Transaxial Gas Turbines Description = "A small gas turbine, high power and a very wide powerband. Outputs to the side instead of rear.", Model = "models/engines/turbine_s.mdl", Sound = "acf_engines/turbine_small.wav", - Fuel = "Multifuel", + Fuel = { Petrol = true, Diesel = true }, Type = "Turbine", Mass = 160, Torque = 440, @@ -353,7 +353,7 @@ do -- Transaxial Gas Turbines Description = "A medium gas turbine, moderate power but a very wide powerband. Outputs to the side instead of rear.", Model = "models/engines/turbine_m.mdl", Sound = "acf_engines/turbine_medium.wav", - Fuel = "Multifuel", + Fuel = { Petrol = true, Diesel = true }, Type = "Turbine", Mass = 320, Torque = 650, @@ -375,7 +375,7 @@ do -- Transaxial Gas Turbines Description = "A large gas turbine, powerful with a wide powerband. Outputs to the side instead of rear.", Model = "models/engines/turbine_l.mdl", Sound = "acf_engines/turbine_large.wav", - Fuel = "Multifuel", + Fuel = { Petrol = true, Diesel = true }, Type = "Turbine", Mass = 880, Torque = 1592, @@ -404,7 +404,7 @@ do -- Forward-facing Ground Gas Turbines Description = "A small gas turbine, fitted with ground-use air filters and tuned for ground use.", Model = "models/engines/gasturbine_s.mdl", Sound = "acf_engines/turbine_small.wav", - Fuel = "Multifuel", + Fuel = { Petrol = true, Diesel = true }, Type = "Radial", Mass = 350, Torque = 800, @@ -425,7 +425,7 @@ do -- Forward-facing Ground Gas Turbines Description = "A medium gas turbine, fitted with ground-use air filters and tuned for ground use.", Model = "models/engines/gasturbine_m.mdl", Sound = "acf_engines/turbine_medium.wav", - Fuel = "Multifuel", + Fuel = { Petrol = true, Diesel = true }, Type = "Radial", --This is done to give proper fuel consumption and make the turbines not instant-torque from idle Mass = 600, Torque = 1200, @@ -447,7 +447,7 @@ do -- Forward-facing Ground Gas Turbines Description = "A large gas turbine, fitted with ground-use air filters and tuned for ground use.", Model = "models/engines/gasturbine_l.mdl", Sound = "acf_engines/turbine_large.wav", - Fuel = "Multifuel", + Fuel = { Petrol = true, Diesel = true }, Type = "Radial", Mass = 1650, Torque = 4000, @@ -471,7 +471,7 @@ do -- Transaxial Ground Gas Turbines Description = "A small gas turbine fitted with ground-use air filters and tuned for ground use. Outputs to the side instead of rear.", Model = "models/engines/turbine_s.mdl", Sound = "acf_engines/turbine_small.wav", - Fuel = "Multifuel", + Fuel = { Petrol = true, Diesel = true }, Type = "Radial", Mass = 280, Torque = 600, @@ -493,7 +493,7 @@ do -- Transaxial Ground Gas Turbines Description = "A medium gas turbine fitted with ground-use air filters and tuned for ground use. Outputs to the side instead of rear.", Model = "models/engines/turbine_m.mdl", Sound = "acf_engines/turbine_medium.wav", - Fuel = "Multifuel", + Fuel = { Petrol = true, Diesel = true }, Type = "Radial", Mass = 480, Torque = 900, @@ -516,7 +516,7 @@ do -- Transaxial Ground Gas Turbines Description = "A large gas turbine fitted with ground-use air filters and tuned for ground use. Outputs to the side instead of rear.", Model = "models/engines/turbine_l.mdl", Sound = "acf_engines/turbine_large.wav", - Fuel = "Multifuel", + Fuel = { Petrol = true, Diesel = true }, Type = "Radial", Mass = 1320, Torque = 3000, diff --git a/lua/acf/shared/engines/v10.lua b/lua/acf/shared/engines/v10.lua index fd19e5f23..a1bc480b9 100644 --- a/lua/acf/shared/engines/v10.lua +++ b/lua/acf/shared/engines/v10.lua @@ -61,7 +61,7 @@ do Description = "Small-block V-10 gasoline engine, great for powering a hot rod lincoln", Model = "models/engines/v10sml.mdl", Sound = "acf_engines/v10_petrolsmall.wav", - Fuel = "Petrol", + Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 160, Torque = 288, @@ -79,7 +79,7 @@ do Description = "Beefy 10-cylinder gas engine, gets 9 kids to soccer practice", Model = "models/engines/v10med.mdl", Sound = "acf_engines/v10_petrolmedium.wav", - Fuel = "Petrol", + Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 300, Torque = 490, @@ -97,7 +97,7 @@ do Description = "Heavy multifuel V-10, gearbox-shredding torque but very heavy.", Model = "models/engines/v10big.mdl", Sound = "acf_engines/v10_diesellarge.wav", - Fuel = "Multifuel", + Fuel = { Petrol = true, Diesel = true }, Type = "GenericDiesel", Mass = 1600, Torque = 2605, diff --git a/lua/acf/shared/engines/v12.lua b/lua/acf/shared/engines/v12.lua index 010094c51..bf2ce4aee 100644 --- a/lua/acf/shared/engines/v12.lua +++ b/lua/acf/shared/engines/v12.lua @@ -134,7 +134,7 @@ do -- Petrol Engines Description = "An elderly racecar engine; low on torque, but plenty of power", Model = "models/engines/v12s.mdl", Sound = "acf_engines/v12_petrolsmall.wav", - Fuel = "Petrol", + Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 188, Torque = 235, @@ -152,7 +152,7 @@ do -- Petrol Engines Description = "A high end V12; primarily found in very expensive cars", Model = "models/engines/v12m.mdl", Sound = "acf_engines/v12_petrolmedium.wav", - Fuel = "Petrol", + Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 360, Torque = 500, @@ -170,7 +170,7 @@ do -- Petrol Engines Description = "Thirsty gasoline v12, good torque and power for medium applications.", Model = "models/engines/v12m.mdl", Sound = "acf_engines/v12_special.wav", - Fuel = "Petrol", + Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 520, Torque = 660, @@ -188,7 +188,7 @@ do -- Petrol Engines Description = "A large, thirsty gasoline V12, found in early cold war tanks", Model = "models/engines/v12l.mdl", Sound = "acf_engines/v12_petrollarge.wav", - Fuel = "Petrol", + Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 1350, Torque = 1925, @@ -208,7 +208,7 @@ do -- Diesel Engines Description = "Reliable truck-duty diesel; a lot of smooth torque", Model = "models/engines/v12s.mdl", Sound = "acf_engines/v12_dieselsmall.wav", - Fuel = "Diesel", + Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 305, Torque = 375, @@ -226,7 +226,7 @@ do -- Diesel Engines Description = "High torque light-tank V12, used mainly for vehicles that require balls", Model = "models/engines/v12m.mdl", Sound = "acf_engines/v12_dieselmedium.wav", - Fuel = "Diesel", + Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 600, Torque = 750, @@ -244,7 +244,7 @@ do -- Diesel Engines Description = "AVDS-1790-2 tank engine; massively powerful, but enormous and heavy", Model = "models/engines/v12l.mdl", Sound = "acf_engines/v12_diesellarge.wav", - Fuel = "Diesel", + Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 1800, Torque = 3560, diff --git a/lua/acf/shared/engines/v2.lua b/lua/acf/shared/engines/v2.lua index f0fe48dc0..525a36278 100644 --- a/lua/acf/shared/engines/v2.lua +++ b/lua/acf/shared/engines/v2.lua @@ -62,7 +62,7 @@ do -- Petrol Engines Description = "Twin cylinder bike engine, torquey for its size", Model = "models/engines/v-twins2.mdl", Sound = "acf_engines/vtwin_small.wav", - Fuel = "Petrol", + Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 30, Torque = 50, @@ -80,7 +80,7 @@ do -- Petrol Engines Description = "Large displacement vtwin engine", Model = "models/engines/v-twinm2.mdl", Sound = "acf_engines/vtwin_medium.wav", - Fuel = "Petrol", + Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 50, Torque = 85, @@ -98,7 +98,7 @@ do -- Petrol Engines Description = "Huge fucking Vtwin 'MURRICA FUCK YEAH", Model = "models/engines/v-twinl2.mdl", Sound = "acf_engines/vtwin_large.wav", - Fuel = "Petrol", + Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 100, Torque = 160, diff --git a/lua/acf/shared/engines/v4.lua b/lua/acf/shared/engines/v4.lua index d7fe6992d..94cc061d4 100644 --- a/lua/acf/shared/engines/v4.lua +++ b/lua/acf/shared/engines/v4.lua @@ -47,7 +47,7 @@ do -- Diesel Engines Description = "Torquey little lunchbox; for those smaller vehicles that don't agree with petrol powerbands", Model = "models/engines/v4s.mdl", Sound = "acf_engines/i4_diesel2.wav", - Fuel = "Diesel", + Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 110, Torque = 165, @@ -65,7 +65,7 @@ do -- Diesel Engines Description = "Compact cube of git; for moderate utility applications", Model = "models/engines/v4m.mdl", Sound = "acf_engines/i4_dieselmedium.wav", - Fuel = "Diesel", + Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 275, Torque = 480, diff --git a/lua/acf/shared/engines/v6.lua b/lua/acf/shared/engines/v6.lua index d96925848..453ed216d 100644 --- a/lua/acf/shared/engines/v6.lua +++ b/lua/acf/shared/engines/v6.lua @@ -97,7 +97,7 @@ do -- Petrol Engines Description = "Meaty Car sized V6, lots of torque.", Model = "models/engines/v6small.mdl", Sound = "acf_engines/v6_petrolsmall.wav", - Fuel = "Petrol", + Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 190, Torque = 253, @@ -115,7 +115,7 @@ do -- Petrol Engines Description = "Heavy duty 6V71 v6, throatier than an LA whore, but loaded with torque.", Model = "models/engines/v6med.mdl", Sound = "acf_engines/v6_petrolmedium.wav", - Fuel = "Petrol", + Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 360, Torque = 472, @@ -133,7 +133,7 @@ do -- Petrol Engines Description = "Fuck duty V6, guts ripped from god himself diluted in salt and shaped into an engine.", Model = "models/engines/v6large.mdl", Sound = "acf_engines/v6_petrollarge.wav", - Fuel = "Petrol", + Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 675, Torque = 1445, @@ -153,7 +153,7 @@ do -- Diesel Engines Description = "Light AFV-grade two-stroke diesel, high output but heavy.", Model = "models/engines/v6med.mdl", Sound = "acf_engines/i5_dieselmedium.wav", - Fuel = "Diesel", + Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 520, Torque = 485, @@ -171,7 +171,7 @@ do -- Diesel Engines Description = "Powerful military-grade large V6, with impressive output. Well suited to medium-sized AFVs.", Model = "models/engines/v6large.mdl", Sound = "acf_engines/v6_diesellarge.wav", - Fuel = "Diesel", + Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 900, Torque = 1767, diff --git a/lua/acf/shared/engines/v8.lua b/lua/acf/shared/engines/v8.lua index 4cd6c90e1..7d81119bd 100644 --- a/lua/acf/shared/engines/v8.lua +++ b/lua/acf/shared/engines/v8.lua @@ -117,7 +117,7 @@ do -- Petrol Engines Description = "Car sized petrol engine, good power and mid range torque", Model = "models/engines/v8s.mdl", Sound = "acf_engines/v8_petrolsmall.wav", - Fuel = "Petrol", + Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 260, Torque = 320, @@ -135,7 +135,7 @@ do -- Petrol Engines Description = "Thirsty, giant V8, for medium applications", Model = "models/engines/v8m.mdl", Sound = "acf_engines/v8_petrolmedium.wav", - Fuel = "Petrol", + Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 400, Torque = 460, @@ -153,7 +153,7 @@ do -- Petrol Engines Description = "American gasoline tank V8, good overall power and torque and fairly lightweight", Model = "models/engines/v8l.mdl", Sound = "acf_engines/v8_petrollarge.wav", - Fuel = "Petrol", + Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 850, Torque = 1458, @@ -173,7 +173,7 @@ do -- Diesel Engines Description = "Light duty diesel v8, good for light vehicles that require a lot of torque", Model = "models/engines/v8s.mdl", Sound = "acf_engines/v8_dieselsmall.wav", - Fuel = "Diesel", + Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 320, Torque = 415, @@ -191,7 +191,7 @@ do -- Diesel Engines Description = "Redneck chariot material. Truck duty V8 diesel, has a good, wide powerband", Model = "models/engines/v8m.mdl", Sound = "acf_engines/v8_dieselmedium2.wav", - Fuel = "Diesel", + Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 520, Torque = 700, @@ -209,7 +209,7 @@ do -- Diesel Engines Description = "Heavy duty diesel V8, used in heavy construction equipment and tanks", Model = "models/engines/v8l.mdl", Sound = "acf_engines/v8_diesellarge.wav", - Fuel = "Diesel", + Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 1200, Torque = 2300, From 3d86cbefd6ff85dcf4ba1fbd4c2f51ccebc3995c Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Fri, 20 Mar 2020 03:10:56 -0300 Subject: [PATCH 043/279] Added fuel tank selection to engine menu - Engine menu now has the controls needed to select a fuel tank. - Adapted existing controls of the engine menu to the latest class related changes. --- lua/acf/client/menu_items/engines_menu.lua | 126 +++++++++++++++++---- 1 file changed, 104 insertions(+), 22 deletions(-) diff --git a/lua/acf/client/menu_items/engines_menu.lua b/lua/acf/client/menu_items/engines_menu.lua index efaf3b68b..66f6a14a9 100644 --- a/lua/acf/client/menu_items/engines_menu.lua +++ b/lua/acf/client/menu_items/engines_menu.lua @@ -1,7 +1,7 @@ +local EngineTypes = ACF.Classes.EngineTypes +local FuelTypes = ACF.Classes.FuelTypes local FuelTanks = ACF.Classes.FuelTanks local Engines = ACF.Classes.Engines -local FuelDensity = ACF.FuelDensity -local Efficiency = ACF.Efficiency local Selected = {} local Sorted = {} @@ -40,7 +40,7 @@ local function UpdateEngineStats(Label, Data) local MaxPower = RPM.PeakMax local RPMText = "Idle RPM : %s RPM\nPowerband : %s-%s RPM\nRedline : %s RPM\nMass : %s" - local Text = "" + local LabelText = "" -- Electric motors and turbines get peak power in middle of rpm range if Data.IsElectric then @@ -50,34 +50,32 @@ local function UpdateEngineStats(Label, Data) MaxPower = PeakkWRPM end - Text = Text .. RPMText:format(RPM.Idle, MinPower, MaxPower, RPM.Limit, ACF.GetProperMass(Data.Mass)) + LabelText = LabelText .. RPMText:format(RPM.Idle, MinPower, MaxPower, RPM.Limit, ACF.GetProperMass(Data.Mass)) local TorqueText = "\nPeak Torque : %s n/m - %s ft-lb" local PowerText = "\nPeak Power : %s kW - %s HP @ %s RPM" - local FuelText = "\n\nFuel Type : %s%s%s" local Consumption, Power = "", "" local Boost = Data.RequiresFuel and ACF.TorqueBoost or 1 - local Fuel = Data.Fuel - if Fuel == "Electric" then - local ElecText = "\nPeak Energy Consumption :\n%s kW - %s MJ/min" - local ElecRate = ACF.ElecRate * PeakkW / Efficiency[Data.Type] + for K in pairs(Data.Fuel) do + if not FuelTypes[K] then continue end - Consumption = ElecText:format(math.Round(ElecRate, 2), math.Round(ElecRate * 0.06, 2)) - else - local ConsumptionText = "\n%s Consumption :\n%s L/min - %s gal/min @ %s RPM" + local Type = EngineTypes[Data.Type] + local Fuel = FuelTypes[K] + local AddText = "" - if Fuel == "Multifuel" or Fuel == "Diesel" then - local FuelRate = ACF.FuelRate * Efficiency[Data.Type] * ACF.TorqueBoost * PeakkW / (60 * FuelDensity.Diesel) + if Fuel.ConsumptionText then + AddText = Fuel.ConsumptionText(PeakkW, PeakkWRPM, Type, Fuel) + else + local Text = "\n\n%s Consumption :\n%s L/min - %s gal/min @ %s RPM" + local Rate = ACF.FuelRate * Type.Efficiency * ACF.TorqueBoost * PeakkW / (60 * Fuel.Density) - Consumption = Consumption .. ConsumptionText:format("Diesel", math.Round(FuelRate, 2), math.Round(FuelRate * 0.264, 2), PeakkWRPM) + AddText = Text:format(Fuel.Name, math.Round(Rate, 2), math.Round(Rate * 0.264, 2), PeakkWRPM) end - if Fuel == "Multifuel" or Fuel == "Petrol" then - local FuelRate = ACF.FuelRate * Efficiency[Data.Type] * ACF.TorqueBoost * PeakkW / (60 * FuelDensity.Petrol) + Consumption = Consumption .. AddText - Consumption = Consumption .. ConsumptionText:format("Petrol", math.Round(FuelRate, 2), math.Round(FuelRate * 0.264, 2), PeakkWRPM) - end + Data.Fuel[K] = Fuel -- Replace once engines use the proper class functions end Power = Power .. "\n" .. PowerText:format(math.floor(PeakkW * Boost), math.floor(PeakkW * Boost * 1.34), PeakkWRPM) @@ -90,9 +88,9 @@ local function UpdateEngineStats(Label, Data) Power = Power .. TorqueText:format(math.floor(Data.Torque * ACF.TorqueBoost), math.floor(Data.Torque * ACF.TorqueBoost * 0.73)) end - Text = Text .. FuelText:format(Fuel, Consumption, Power) + LabelText = LabelText .. Consumption .. Power - Label:SetText(Text) + Label:SetText(LabelText) end local function CreateMenu(Menu) @@ -102,7 +100,12 @@ local function CreateMenu(Menu) local EngineDesc = Menu:AddLabel() local EngineStats = Menu:AddLabel() + Menu:AddTitle("Fuel Settings") + + local FuelClass = Menu:AddComboBox() local FuelList = Menu:AddComboBox() + local FuelType = Menu:AddComboBox() + local FuelDesc = Menu:AddLabel() ACF.WriteValue("PrimaryClass", "acf_engine") ACF.WriteValue("SecondaryClass", "acf_fueltank") @@ -136,10 +139,89 @@ local function CreateMenu(Menu) EngineDesc:SetText((ClassDesc and (ClassDesc .. "\n\n") or "") .. Data.Description) UpdateEngineStats(EngineStats, Data) + + LoadSortedList(FuelType, Data.Fuel, "ID") + end + + function FuelClass:OnSelect(Index, _, Data) + if self.Selected == Data then return end + + self.Selected = Data + + local Choices = Sorted[FuelTanks] + Selected[Choices] = Index + + LoadSortedList(FuelList, Data.Items, "ID") + end + + function FuelList:OnSelect(Index, _, Data) + if self.Selected == Data then return end + + self.Selected = Data + + local ClassData = FuelClass.Selected + local ClassDesc = ClassData.Description + local Choices = Sorted[ClassData.Items] + Selected[Choices] = Index + + self.Description = (ClassDesc and (ClassDesc .. "\n\n") or "") .. Data.Description + + ACF.WriteValue("FuelTank", Data.ID) + + FuelType:UpdateFuelText() + end + + function FuelType:OnSelect(Index, _, Data) + if self.Selected == Data then return end + + self.Selected = Data + + local ClassData = EngineList.Selected + local Choices = Sorted[ClassData.Fuel] + Selected[Choices] = Index + + ACF.WriteValue("FuelType", Data.ID) + + self:UpdateFuelText() + end + + function FuelType:UpdateFuelText() + if not self.Selected then return end + if not FuelList.Selected then return end + + local FuelTank = FuelList.Selected + local FuelText = FuelList.Description + local TextFunc = self.Selected.FuelTankText + + local Wall = 0.03937 --wall thickness in inches (1mm) + local Volume = FuelTank.Volume - (FuelTank.SurfaceArea * Wall) -- total volume of tank (cu in), reduced by wall thickness + local Capacity = Volume * ACF.CuIToLiter * ACF.TankVolumeMul * 0.4774 --internal volume available for fuel in liters, with magic realism number + local EmptyMass = FuelTank.SurfaceArea * Wall * 16.387 * 0.0079 -- total wall volume * cu in to cc * density of steel (kg/cc) + local Mass = EmptyMass + Capacity * self.Selected.Density -- weight of tank + weight of fuel + + if TextFunc then + FuelText = FuelText .. TextFunc(Capacity, Mass, EmptyMass) + else + local Text = "\n\nCapacity : %s L - %s gal\nFull Mass : %s\nEmpty Mass : %s" + local Liters = math.Round(Capacity, 2) + local Gallons = math.Round(Capacity * 0.264172, 2) + + FuelText = FuelText .. Text:format(Liters, Gallons, ACF.GetProperMass(Mass), ACF.GetProperMass(EmptyMass)) + end + + if not FuelTank.IsExplosive then + FuelText = FuelText .. "\n\nThis fuel tank won't explode if damaged." + end + + if FuelTank.Unlinkable then + FuelText = FuelText .. "\n\nThis fuel tank cannot be linked to other ACF entities." + end + + FuelDesc:SetText(FuelText) end LoadSortedList(EngineClass, Engines, "ID") - LoadSortedList(FuelList, FuelTanks, "ID") + LoadSortedList(FuelClass, FuelTanks, "ID") end ACF.AddOptionItem("Entities", "Engines", "car", CreateMenu) From f3f30bf8d74a9c9f14018388697a69ecf7c0ef9e Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Tue, 24 Mar 2020 04:29:53 -0300 Subject: [PATCH 044/279] Added gearbox registration functions - Added ACF.RegisterGearboxClass and ACF.RegisterGearbox functions - Ported all existing gearboxes to the new functions. --- lua/acf/base/sh_classes.lua | 56 +++++++ lua/acf/shared/gearboxes/3-auto.lua | 193 ++++++++++++++++++++++ lua/acf/shared/gearboxes/4-speed.lua | 161 ++++++++++++++++++ lua/acf/shared/gearboxes/5-auto.lua | 193 ++++++++++++++++++++++ lua/acf/shared/gearboxes/6-speed.lua | 159 ++++++++++++++++++ lua/acf/shared/gearboxes/7-auto.lua | 193 ++++++++++++++++++++++ lua/acf/shared/gearboxes/8-speed.lua | 159 ++++++++++++++++++ lua/acf/shared/gearboxes/clutch.lua | 46 ++++++ lua/acf/shared/gearboxes/cvt.lua | 176 +++++++++++++++++++- lua/acf/shared/gearboxes/differential.lua | 130 +++++++++++++++ lua/acf/shared/gearboxes/doublediff.lua | 45 ++++- lua/acf/shared/gearboxes/transfer.lua | 72 ++++++++ 12 files changed, 1581 insertions(+), 2 deletions(-) create mode 100644 lua/acf/shared/gearboxes/3-auto.lua create mode 100644 lua/acf/shared/gearboxes/5-auto.lua create mode 100644 lua/acf/shared/gearboxes/7-auto.lua diff --git a/lua/acf/base/sh_classes.lua b/lua/acf/base/sh_classes.lua index 9c6ec7f27..9ba0df439 100644 --- a/lua/acf/base/sh_classes.lua +++ b/lua/acf/base/sh_classes.lua @@ -335,3 +335,59 @@ do -- Fuel type registration function end end end + +do -- Gearbox registration functions + ACF.Classes.Gearboxes = ACF.Classes.Gearboxes or {} + + local Gearboxes = ACF.Classes.Gearboxes + + function ACF.RegisterGearboxClass(ID, Data) + if not ID then return end + if not Data then return end + + local Class = Gearboxes[ID] + + if not Class then + Class = { + ID = ID, + Lookup = {}, + Items = {}, + Count = 0, + } + + Gearboxes[ID] = Class + end + + for K, V in pairs(Data) do + Class[K] = V + end + end + + function ACF.RegisterGearbox(ID, ClassID, Data) + if not ID then return end + if not ClassID then return end + if not Data then return end + if not Gearboxes[ClassID] then return end + + local Class = Gearboxes[ClassID] + local Gearbox = Class.Lookup[ID] + + if not Gearbox then + Gearbox = { + ID = ID, + Class = Class, + ClassID = ClassID, + EntClass = "acf_gearbox", + Sound = "vehicles/junker/jnk_fourth_cruise_loop2.wav", + } + + Class.Count = Class.Count + 1 + Class.Items[Class.Count] = Gearbox + Class.Lookup[ID] = Gearbox + end + + for K, V in pairs(Data) do + Gearbox[K] = V + end + end +end diff --git a/lua/acf/shared/gearboxes/3-auto.lua b/lua/acf/shared/gearboxes/3-auto.lua new file mode 100644 index 000000000..d67181701 --- /dev/null +++ b/lua/acf/shared/gearboxes/3-auto.lua @@ -0,0 +1,193 @@ +-- Weight +local wmul = 1.5 +local Gear3SW = 60 * wmul +local Gear3MW = 120 * wmul +local Gear3LW = 240 * wmul + +-- Torque Rating +local Gear3ST = 675 +local Gear3MT = 2125 +local Gear3LT = 10000 + +-- Straight through bonuses +local StWB = 0.75 --straight weight bonus mulitplier +local StTB = 1.25 --straight torque bonus multiplier + +-- Shift Time +local ShiftS = 0.25 +local ShiftM = 0.35 +local ShiftL = 0.5 + +ACF.RegisterGearboxClass("3-Auto", { + Name = "3-Speed Automatic", + Gears = { + Min = 0, + Max = 3, + } +}) + +do -- Inline Gearboxes + ACF.RegisterGearbox("3Gear-A-L-S", "3-Auto", { + Name = "3-Speed Auto, Inline, Small", + Description = "A small, and light 3 speed automatic inline gearbox, with a somewhat limited max torque rating", + Model = "models/engines/linear_s.mdl", + Mass = Gear3SW, + Switch = ShiftS, + MaxTorque = Gear3ST, + Automatic = true, + }) + + ACF.RegisterGearbox("3Gear-A-L-M", "3-Auto", { + Name = "3-Speed Auto, Inline, Medium", + Description = "A medium sized, 3 speed automatic inline gearbox", + Model = "models/engines/linear_m.mdl", + Mass = Gear3MW, + Switch = ShiftM, + MaxTorque = Gear3MT, + Automatic = true, + }) + + ACF.RegisterGearbox("3Gear-A-L-L", "3-Auto", { + Name = "3-Speed Auto, Inline, Large", + Description = "A large, heavy and sturdy 3 speed inline gearbox", + Model = "models/engines/linear_l.mdl", + Mass = Gear3LW, + Switch = ShiftL, + MaxTorque = Gear3LT, + Automatic = true, + }) +end + +do -- Inline Dual Clutch Gearboxes + ACF.RegisterGearbox("3Gear-A-LD-S", "3-Auto", { + Name = "3-Speed Auto, Inline, Small, Dual Clutch", + Description = "A small, and light 3 speed automatic inline gearbox, with a somewhat limited max torque rating", + Model = "models/engines/linear_s.mdl", + Mass = Gear3SW, + Switch = ShiftS, + MaxTorque = Gear3ST, + Automatic = true, + DualClutch = true, + }) + + ACF.RegisterGearbox("3Gear-A-LD-M", "3-Auto", { + Name = "3-Speed Auto, Inline, Medium, Dual Clutch", + Description = "A medium sized, 3 speed automatic inline gearbox", + Model = "models/engines/linear_m.mdl", + Mass = Gear3MW, + Switch = ShiftM, + MaxTorque = Gear3MT, + Automatic = true, + DualClutch = true, + }) + + ACF.RegisterGearbox("3Gear-A-LD-L", "3-Auto", { + Name = "3-Speed Auto, Inline, Large, Dual Clutch", + Description = "A large, heavy and sturdy 3 speed automatic inline gearbox", + Model = "models/engines/linear_l.mdl", + Mass = Gear3LW, + Switch = ShiftL, + MaxTorque = Gear3LT, + Automatic = true, + DualClutch = true, + }) +end + +do -- Transaxial Gearboxes + ACF.RegisterGearbox("3Gear-A-T-S", "3-Auto", { + Name = "3-Speed Auto, Transaxial, Small", + Description = "A small, and light 3 speed automatic gearbox, with a somewhat limited max torque rating", + Model = "models/engines/transaxial_s.mdl", + Mass = Gear3SW, + Switch = ShiftS, + MaxTorque = Gear3ST, + Automatic = true, + }) + + ACF.RegisterGearbox("3Gear-A-T-M", "3-Auto", { + Name = "3-Speed Auto, Transaxial, Medium", + Description = "A medium sized, 3 speed automatic gearbox", + Model = "models/engines/transaxial_m.mdl", + Mass = Gear3MW, + Switch = ShiftM, + MaxTorque = Gear3MT, + Automatic = true, + }) + + ACF.RegisterGearbox("3Gear-A-T-L", "3-Auto", { + Name = "3-Speed Auto, Transaxial, Large", + Description = "A large, heavy and sturdy 3 speed automatic gearbox", + Model = "models/engines/transaxial_l.mdl", + Mass = Gear3LW, + Switch = ShiftL, + MaxTorque = Gear3LT, + Automatic = true, + }) +end + +do -- Transaxial Dual Clutch Gearboxes + ACF.RegisterGearbox("3Gear-A-TD-S", "3-Auto", { + Name = "3-Speed Auto, Transaxial, Small, Dual Clutch", + Description = "A small, and light 3 speed automatic gearbox, with a somewhat limited max torque rating", + Model = "models/engines/transaxial_s.mdl", + Mass = Gear3SW, + Switch = ShiftS, + MaxTorque = Gear3ST, + Automatic = true, + DualClutch = true, + }) + + ACF.RegisterGearbox("3Gear-A-TD-M", "3-Auto", { + Name = "3-Speed Auto, Transaxial, Medium, Dual Clutch", + Description = "A medium sized, 3 speed automatic gearbox", + Model = "models/engines/transaxial_m.mdl", + Mass = Gear3MW, + Switch = ShiftM, + MaxTorque = Gear3MT, + Automatic = true, + DualClutch = true, + }) + + ACF.RegisterGearbox("3Gear-A-TD-L", "3-Auto", { + Name = "3-Speed Auto, Transaxial, Large, Dual Clutch", + Description = "A large, heavy and sturdy 3 speed automatic gearbox", + Model = "models/engines/transaxial_l.mdl", + Mass = Gear3LW, + Switch = ShiftL, + MaxTorque = Gear3LT, + Automatic = true, + DualClutch = true, + }) +end + +do -- Straight-through Gearboxes + ACF.RegisterGearbox("3Gear-A-ST-S", "3-Auto", { + Name = "3-Speed Auto, Straight, Small", + Description = "A small straight-through automatic gearbox", + Model = "models/engines/t5small.mdl", + Mass = math.floor(Gear3SW * StWB), + Switch = ShiftS, + MaxTorque = math.floor(Gear3ST * StTB), + Automatic = true, + }) + + ACF.RegisterGearbox("3Gear-A-ST-M", "3-Auto", { + Name = "3-Speed Auto, Straight, Medium", + Description = "A medium sized, 3 speed automatic straight-through gearbox.", + Model = "models/engines/t5med.mdl", + Mass = math.floor(Gear3MW * StWB), + Switch = ShiftM, + MaxTorque = math.floor(Gear3MT * StTB), + Automatic = true, + }) + + ACF.RegisterGearbox("3Gear-A-ST-L", "3-Auto", { + Name = "3-Speed Auto, Straight, Large", + Description = "A large sized, 3 speed automatic straight-through gearbox.", + Model = "models/engines/t5large.mdl", + Mass = math.floor(Gear3LW * StWB), + Switch = ShiftL, + MaxTorque = math.floor(Gear3LT * StTB), + Automatic = true, + }) +end diff --git a/lua/acf/shared/gearboxes/4-speed.lua b/lua/acf/shared/gearboxes/4-speed.lua index dbf9d575f..10c555d46 100644 --- a/lua/acf/shared/gearboxes/4-speed.lua +++ b/lua/acf/shared/gearboxes/4-speed.lua @@ -313,3 +313,164 @@ ACF_DefineGearbox( "4Gear-ST-L", { [ -1 ] = 0.5 } } ) + +-- The dual clutch allows you to apply power and brake each side independently + +ACF.RegisterGearboxClass("4-Speed", { + Name = "4-Speed Gearbox", + Gears = { + Min = 0, + Max = 4, + } +}) + +do -- Inline Gearboxes + ACF.RegisterGearbox("4Gear-L-S", "4-Speed", "4-Speed", { + Name = "4-Speed, Inline, Small", + Description = "A small, and light 4 speed inline gearbox, with a somewhat limited max torque rating.", + Model = "models/engines/linear_s.mdl", + Mass = Gear4SW, + Switch = 0.15, + MaxTorque = Gear4ST, + }) + + ACF.RegisterGearbox("4Gear-L-M", "4-Speed", { + Name = "4-Speed, Inline, Medium", + Description = "A medium sized, 4 speed inline gearbox.", + Model = "models/engines/linear_m.mdl", + Mass = Gear4MW, + Switch = 0.2, + MaxTorque = Gear4MT, + }) + + ACF.RegisterGearbox("4Gear-L-L", "4-Speed", { + Name = "4-Speed, Inline, Large", + Description = "A large, heavy and sturdy 4 speed inline gearbox.", + Model = "models/engines/linear_l.mdl", + Mass = Gear4LW, + Switch = 0.3, + MaxTorque = Gear4LT, + }) +end + +do -- Inline Dual Clutch Gearboxes + ACF.RegisterGearbox("4Gear-LD-S", "4-Speed", { + Name = "4-Speed, Inline, Small, Dual Clutch", + Description = "A small, and light 4 speed inline gearbox, with a somewhat limited max torque rating.", + Model = "models/engines/linear_s.mdl", + Mass = Gear4SW, + Switch = 0.15, + MaxTorque = Gear4ST, + DualClutch = true, + }) + + ACF.RegisterGearbox("4Gear-LD-M", "4-Speed", { + Name = "4-Speed, Inline, Medium, Dual Clutch", + Description = "A medium sized, 4 speed inline gearbox.", + Model = "models/engines/linear_m.mdl", + Mass = Gear4MW, + Switch = 0.2, + MaxTorque = Gear4MT, + DualClutch = true, + }) + + ACF.RegisterGearbox("4Gear-LD-L", "4-Speed", { + Name = "4-Speed, Inline, Large, Dual Clutch", + Description = "A large, heavy and sturdy 4 speed inline gearbox.", + Model = "models/engines/linear_l.mdl", + Mass = Gear4LW, + Switch = 0.3, + MaxTorque = Gear4LT, + DualClutch = true, + }) +end + +do -- Transaxial Gearboxes + ACF.RegisterGearbox("4Gear-T-S", "4-Speed", { + Name = "4-Speed, Transaxial, Small", + Description = "A small, and light 4 speed gearbox, with a somewhat limited max torque rating.", + Model = "models/engines/transaxial_s.mdl", + Mass = Gear4SW, + Switch = 0.15, + MaxTorque = Gear4ST, + }) + + ACF.RegisterGearbox("4Gear-T-M", "4-Speed", { + Name = "4-Speed, Transaxial, Medium", + Description = "A medium sized, 4 speed gearbox.", + Model = "models/engines/transaxial_m.mdl", + Mass = Gear4MW, + Switch = 0.2, + MaxTorque = Gear4MT, + }) + + ACF.RegisterGearbox("4Gear-T-L", "4-Speed", { + Name = "4-Speed, Transaxial, Large", + Description = "A large, heavy and sturdy 4 speed gearbox.", + Model = "models/engines/transaxial_l.mdl", + Mass = Gear4LW, + Switch = 0.3, + MaxTorque = Gear4LT, + }) +end + +do -- Transaxial Dual Clutch Gearboxes + ACF.RegisterGearbox("4Gear-TD-S", "4-Speed", { + Name = "4-Speed, Transaxial, Small, Dual Clutch", + Description = "A small, and light 4 speed gearbox, with a somewhat limited max torque rating.", + Model = "models/engines/transaxial_s.mdl", + Mass = Gear4SW, + Switch = 0.15, + MaxTorque = Gear4ST, + DualClutch = true, + }) + + ACF.RegisterGearbox("4Gear-TD-M", "4-Speed", { + Name = "4-Speed, Transaxial, Medium, Dual Clutch", + Description = "A medium sized, 4 speed gearbox.", + Model = "models/engines/transaxial_m.mdl", + Mass = Gear4MW, + Switch = 0.2, + MaxTorque = Gear4MT, + DualClutch = true, + }) + + ACF.RegisterGearbox("4Gear-TD-L", "4-Speed", { + Name = "4-Speed, Transaxial, Large, Dual Clutch", + Description = "A large, heavy and sturdy 4 speed gearbox.", + Model = "models/engines/transaxial_l.mdl", + Mass = Gear4LW, + Switch = 0.3, + MaxTorque = Gear4LT, + DualClutch = true, + }) +end + +do -- Straight-through Gearboxes + ACF.RegisterGearbox("4Gear-ST-S", "4-Speed", { + Name = "4-Speed, Straight, Small", + Description = "A small straight-through gearbox.", + Model = "models/engines/t5small.mdl", + Mass = math.floor(Gear4SW * StWB), + Switch = 0.15, + MaxTorque = math.floor(Gear4ST * StTB), + }) + + ACF.RegisterGearbox("4Gear-ST-M", "4-Speed", { + Name = "4-Speed, Straight, Medium", + Description = "A medium sized, 4 speed straight-through gearbox.", + Model = "models/engines/t5med.mdl", + Mass = math.floor(Gear4MW * StWB), + Switch = 0.2, + MaxTorque = math.floor(Gear4MT * StTB), + }) + + ACF.RegisterGearbox("4Gear-ST-L", "4-Speed", { + Name = "4-Speed, Straight, Large", + Description = "A large sized, 4 speed straight-through gearbox.", + Model = "models/engines/t5large.mdl", + Mass = math.floor(Gear4LW * StWB), + Switch = 0.3, + MaxTorque = math.floor(Gear4LT * StTB), + }) +end diff --git a/lua/acf/shared/gearboxes/5-auto.lua b/lua/acf/shared/gearboxes/5-auto.lua new file mode 100644 index 000000000..c8d91a759 --- /dev/null +++ b/lua/acf/shared/gearboxes/5-auto.lua @@ -0,0 +1,193 @@ +-- Weight +local wmul = 1.5 +local Gear5SW = 80 * wmul +local Gear5MW = 160 * wmul +local Gear5LW = 320 * wmul + +-- Torque Rating +local Gear5ST = 550 +local Gear5MT = 1700 +local Gear5LT = 10000 + +-- Straight through bonuses +local StWB = 0.75 --straight weight bonus mulitplier +local StTB = 1.25 --straight torque bonus multiplier + +-- Shift Time +local ShiftS = 0.25 +local ShiftM = 0.35 +local ShiftL = 0.5 + +ACF.RegisterGearboxClass("5-Auto", { + Name = "5-Speed Automatic", + Gears = { + Min = 0, + Max = 5, + } +}) + +do -- Inline Gearboxes + ACF.RegisterGearbox("5Gear-A-L-S", "5-Auto", { + Name = "5-Speed Auto, Inline, Small", + Description = "A small, and light 5 speed automatic inline gearbox, with a somewhat limited max torque rating", + Model = "models/engines/linear_s.mdl", + Mass = Gear5SW, + Switch = ShiftS, + MaxTorque = Gear5ST, + Automatic = true, + }) + + ACF.RegisterGearbox("5Gear-A-L-M", "5-Auto", { + Name = "5-Speed Auto, Inline, Medium", + Description = "A medium sized, 5 speed automatic inline gearbox", + Model = "models/engines/linear_m.mdl", + Mass = Gear5MW, + Switch = ShiftM, + MaxTorque = Gear5MT, + Automatic = true, + }) + + ACF.RegisterGearbox("5Gear-A-L-L", "5-Auto", { + Name = "5-Speed Auto, Inline, Large", + Description = "A large, heavy and sturdy 5 speed inline gearbox", + Model = "models/engines/linear_l.mdl", + Mass = Gear5LW, + Switch = ShiftL, + MaxTorque = Gear5LT, + Automatic = true, + }) +end + +do -- Inline Dual Clutch Gearboxes + ACF.RegisterGearbox("5Gear-A-LD-S", "5-Auto", { + Name = "5-Speed Auto, Inline, Small, Dual Clutch", + Description = "A small, and light 5 speed automatic inline gearbox, with a somewhat limited max torque rating", + Model = "models/engines/linear_s.mdl", + Mass = Gear5SW, + Switch = ShiftS, + MaxTorque = Gear5ST, + Automatic = true, + DualClutch = true, + }) + + ACF.RegisterGearbox("5Gear-A-LD-M", "5-Auto", { + Name = "5-Speed Auto, Inline, Medium, Dual Clutch", + Description = "A medium sized, 5 speed automatic inline gearbox", + Model = "models/engines/linear_m.mdl", + Mass = Gear5MW, + Switch = ShiftM, + MaxTorque = Gear5MT, + Automatic = true, + DualClutch = true, + }) + + ACF.RegisterGearbox("5Gear-A-LD-L", "5-Auto", { + Name = "5-Speed Auto, Inline, Large, Dual Clutch", + Description = "A large, heavy and sturdy 5 speed automatic inline gearbox", + Model = "models/engines/linear_l.mdl", + Mass = Gear5LW, + Switch = ShiftL, + MaxTorque = Gear5LT, + Automatic = true, + DualClutch = true, + }) +end + +do -- Transaxial Gearboxes + ACF.RegisterGearbox("5Gear-A-T-S", "5-Auto", { + Name = "5-Speed Auto, Transaxial, Small", + Description = "A small, and light 5 speed automatic gearbox, with a somewhat limited max torque rating", + Model = "models/engines/transaxial_s.mdl", + Mass = Gear5SW, + Switch = ShiftS, + MaxTorque = Gear5ST, + Automatic = true, + }) + + ACF.RegisterGearbox("5Gear-A-T-M", "5-Auto", { + Name = "5-Speed Auto, Transaxial, Medium", + Description = "A medium sized, 5 speed automatic gearbox", + Model = "models/engines/transaxial_m.mdl", + Mass = Gear5MW, + Switch = ShiftM, + MaxTorque = Gear5MT, + Automatic = true, + }) + + ACF.RegisterGearbox("5Gear-A-T-L", "5-Auto", { + Name = "5-Speed Auto, Transaxial, Large", + Description = "A large, heavy and sturdy 5 speed automatic gearbox", + Model = "models/engines/transaxial_l.mdl", + Mass = Gear5LW, + Switch = ShiftL, + MaxTorque = Gear5LT, + Automatic = true, + }) +end + +do -- Transaxial Dual Clutch Gearboxes + ACF.RegisterGearbox("5Gear-A-TD-S", "5-Auto", { + Name = "5-Speed Auto, Transaxial, Small, Dual Clutch", + Description = "A small, and light 5 speed automatic gearbox, with a somewhat limited max torque rating", + Model = "models/engines/transaxial_s.mdl", + Mass = Gear5SW, + Switch = ShiftS, + MaxTorque = Gear5ST, + Automatic = true, + DualClutch = true, + }) + + ACF.RegisterGearbox("5Gear-A-TD-M", "5-Auto", { + Name = "5-Speed Auto, Transaxial, Medium, Dual Clutch", + Description = "A medium sized, 5 speed automatic gearbox", + Model = "models/engines/transaxial_m.mdl", + Mass = Gear5MW, + Switch = ShiftM, + MaxTorque = Gear5MT, + Automatic = true, + DualClutch = true, + }) + + ACF.RegisterGearbox("5Gear-A-TD-L", "5-Auto", { + Name = "5-Speed Auto, Transaxial, Large, Dual Clutch", + Description = "A large, heavy and sturdy 5 speed automatic gearbox", + Model = "models/engines/transaxial_l.mdl", + Mass = Gear5LW, + Switch = ShiftL, + MaxTorque = Gear5LT, + Automatic = true, + DualClutch = true, + }) +end + +do -- Straight-through Gearboxes + ACF.RegisterGearbox("5Gear-A-ST-S", "5-Auto", { + Name = "5-Speed Auto, Straight, Small", + Description = "A small straight-through automatic gearbox", + Model = "models/engines/t5small.mdl", + Mass = math.floor(Gear5SW * StWB), + Switch = ShiftS, + MaxTorque = math.floor(Gear5ST * StTB), + Automatic = true, + }) + + ACF.RegisterGearbox("5Gear-A-ST-M", "5-Auto", { + Name = "5-Speed Auto, Straight, Medium", + Description = "A medium sized, 5 speed automatic straight-through gearbox.", + Model = "models/engines/t5med.mdl", + Mass = math.floor(Gear5MW * StWB), + Switch = ShiftM, + MaxTorque = math.floor(Gear5MT * StTB), + Automatic = true, + }) + + ACF.RegisterGearbox("5Gear-A-ST-L", "5-Auto", { + Name = "5-Speed Auto, Straight, Large", + Description = "A large sized, 5 speed automatic straight-through gearbox.", + Model = "models/engines/t5large.mdl", + Mass = math.floor(Gear5LW * StWB), + Switch = ShiftL, + MaxTorque = math.floor(Gear5LT * StTB), + Automatic = true, + }) +end diff --git a/lua/acf/shared/gearboxes/6-speed.lua b/lua/acf/shared/gearboxes/6-speed.lua index ab845af61..e52004b80 100644 --- a/lua/acf/shared/gearboxes/6-speed.lua +++ b/lua/acf/shared/gearboxes/6-speed.lua @@ -343,3 +343,162 @@ ACF_DefineGearbox( "6Gear-ST-L", { [ -1 ] = 0.5 } } ) + +ACF.RegisterGearboxClass("6-Speed", { + Name = "6-Speed Gearbox", + Gears = { + Min = 0, + Max = 6, + } +}) + +do -- Inline Gearboxes + ACF.RegisterGearbox("6Gear-L-S", "6-Speed", { + Name = "6-Speed, Inline, Small", + Description = "A small and light 6 speed inline gearbox, with a limited max torque rating.", + Model = "models/engines/linear_s.mdl", + Mass = Gear6SW, + Switch = 0.15, + MaxTorque = Gear6ST, + }) + + ACF.RegisterGearbox("6Gear-L-M", "6-Speed", { + Name = "6-Speed, Inline, Medium", + Description = "A medium duty 6 speed inline gearbox with a limited torque rating.", + Model = "models/engines/linear_m.mdl", + Mass = Gear6MW, + Switch = 0.2, + MaxTorque = Gear6MT, + }) + + ACF.RegisterGearbox("6Gear-L-L", "6-Speed", { + Name = "6-Speed, Inline, Large", + Description = "Heavy duty 6 speed inline gearbox, however not as resilient as a 4 speed.", + Model = "models/engines/linear_l.mdl", + Mass = Gear6LW, + Switch = 0.3, + MaxTorque = Gear6LT, + }) +end + +do -- Inline Dual Clutch Gearboxes + ACF.RegisterGearbox("6Gear-LD-S", "6-Speed", { + Name = "6-Speed, Inline, Small, Dual Clutch", + Description = "A small and light 6 speed inline gearbox, with a limited max torque rating.", + Model = "models/engines/linear_s.mdl", + Mass = Gear6SW, + Switch = 0.15, + MaxTorque = Gear6ST, + DualClutch = true, + }) + + ACF.RegisterGearbox("6Gear-LD-M", "6-Speed", { + Name = "6-Speed, Inline, Medium, Dual Clutch", + Description = "A a medium duty 6 speed inline gearbox. The added gears reduce torque capacity substantially.", + Model = "models/engines/linear_m.mdl", + Mass = Gear6MW, + Switch = 0.2, + MaxTorque = Gear6MT, + DualClutch = true, + }) + + ACF.RegisterGearbox("6Gear-LD-L", "6-Speed", { + Name = "6-Speed, Inline, Large, Dual Clutch", + Description = "Heavy duty 6 speed inline gearbox, however not as resilient as a 4 speed.", + Model = "models/engines/linear_l.mdl", + Mass = Gear6LW, + Switch = 0.3, + MaxTorque = Gear6LT, + DualClutch = true, + }) +end + +do -- Transaxial Gearboxes + ACF.RegisterGearbox("6Gear-T-S", "6-Speed", { + Name = "6-Speed, Transaxial, Small", + Description = "A small and light 6 speed gearbox, with a limited max torque rating.", + Model = "models/engines/transaxial_s.mdl", + Mass = Gear6SW, + Switch = 0.15, + MaxTorque = Gear6ST, + }) + + ACF.RegisterGearbox("6Gear-T-M", "6-Speed", { + Name = "6-Speed, Transaxial, Medium", + Description = "A medium duty 6 speed gearbox with a limited torque rating.", + Model = "models/engines/transaxial_m.mdl", + Mass = Gear6MW, + Switch = 0.2, + MaxTorque = Gear6MT, + }) + + ACF.RegisterGearbox("6Gear-T-L", "6-Speed", { + Name = "6-Speed, Transaxial, Large", + Description = "Heavy duty 6 speed gearbox, however not as resilient as a 4 speed.", + Model = "models/engines/transaxial_l.mdl", + Mass = Gear6LW, + Switch = 0.3, + MaxTorque = Gear6LT, + }) +end + +do -- Transaxial Dual Clutch + ACF.RegisterGearbox("6Gear-TD-S", "6-Speed", { + Name = "6-Speed, Transaxial, Small, Dual Clutch", + Description = "A small and light 6 speed gearbox, with a limited max torque rating.", + Model = "models/engines/transaxial_s.mdl", + Mass = Gear6SW, + Switch = 0.15, + MaxTorque = Gear6ST, + DualClutch = true, + }) + + ACF.RegisterGearbox("6Gear-TD-M", "6-Speed", { + Name = "6-Speed, Transaxial, Medium, Dual Clutch", + Description = "A a medium duty 6 speed gearbox. The added gears reduce torque capacity substantially.", + Model = "models/engines/transaxial_m.mdl", + Mass = Gear6MW, + Switch = 0.2, + MaxTorque = Gear6MT, + DualClutch = true, + }) + + ACF.RegisterGearbox("6Gear-TD-L", "6-Speed", { + Name = "6-Speed, Transaxial, Large, Dual Clutch", + Description = "Heavy duty 6 speed gearbox, however not as resilient as a 4 speed.", + Model = "models/engines/transaxial_l.mdl", + Mass = Gear6LW, + Switch = 0.3, + MaxTorque = Gear6LT, + DualClutch = true, + }) +end + +do -- Straight-through Gearboxes + ACF.RegisterGearbox("6Gear-ST-S", "6-Speed", { + Name = "6-Speed, Straight, Small", + Description = "A small and light 6 speed straight-through gearbox.", + Model = "models/engines/t5small.mdl", + Mass = math.floor(Gear6SW * StWB), + Switch = 0.15, + MaxTorque = math.floor(Gear6ST * StTB), + }) + + ACF.RegisterGearbox("6Gear-ST-M", "6-Speed", { + Name = "6-Speed, Straight, Medium", + Description = "A medium 6 speed straight-through gearbox.", + Model = "models/engines/t5med.mdl", + Mass = math.floor(Gear6MW * StWB), + Switch = 0.2, + MaxTorque = math.floor(Gear6MT * StTB), + }) + + ACF.RegisterGearbox("6Gear-ST-L", "6-Speed", { + Name = "6-Speed, Straight, Large", + Description = "A large 6 speed straight-through gearbox.", + Model = "models/engines/t5large.mdl", + Mass = math.floor(Gear6LW * StWB), + Switch = 0.3, + MaxTorque = math.floor(Gear6LT * StTB), + }) +end diff --git a/lua/acf/shared/gearboxes/7-auto.lua b/lua/acf/shared/gearboxes/7-auto.lua new file mode 100644 index 000000000..085bc3960 --- /dev/null +++ b/lua/acf/shared/gearboxes/7-auto.lua @@ -0,0 +1,193 @@ +-- Weight +local wmul = 1.5 +local Gear7SW = 100 * wmul +local Gear7MW = 200 * wmul +local Gear7LW = 400 * wmul + +-- Torque Rating +local Gear7ST = 425 +local Gear7MT = 1250 +local Gear7LT = 10000 + +-- Straight through bonuses +local StWB = 0.75 --straight weight bonus mulitplier +local StTB = 1.25 --straight torque bonus multiplier + +-- Shift Time +local ShiftS = 0.25 +local ShiftM = 0.35 +local ShiftL = 0.5 + +ACF.RegisterGearboxClass("7-Auto", { + Name = "7-Speed Automatic", + Gears = { + Min = 0, + Max = 7, + } +}) + +do -- Inline Gearboxes + ACF.RegisterGearbox("7Gear-A-L-S", "7-Auto", { + Name = "7-Speed Auto, Inline, Small", + Description = "A small, and light 7 speed automatic inline gearbox, with a somewhat limited max torque rating", + Model = "models/engines/linear_s.mdl", + Mass = Gear7SW, + Switch = ShiftS, + MaxTorque = Gear7ST, + Automatic = true, + }) + + ACF.RegisterGearbox("7Gear-A-L-M", "7-Auto", { + Name = "7-Speed Auto, Inline, Medium", + Description = "A medium sized, 7 speed automatic inline gearbox", + Model = "models/engines/linear_m.mdl", + Mass = Gear7MW, + Switch = ShiftM, + MaxTorque = Gear7MT, + Automatic = true, + }) + + ACF.RegisterGearbox("7Gear-A-L-L", "7-Auto", { + Name = "7-Speed Auto, Inline, Large", + Description = "A large, heavy and sturdy 7 speed inline gearbox", + Model = "models/engines/linear_l.mdl", + Mass = Gear7LW, + Switch = ShiftL, + MaxTorque = Gear7LT, + Automatic = true, + }) +end + +do -- Inline Dual Clutch Gearboxes + ACF.RegisterGearbox("7Gear-A-LD-S", "7-Auto", { + Name = "7-Speed Auto, Inline, Small, Dual Clutch", + Description = "A small, and light 7 speed automatic inline gearbox, with a somewhat limited max torque rating", + Model = "models/engines/linear_s.mdl", + Mass = Gear7SW, + Switch = ShiftS, + MaxTorque = Gear7ST, + Automatic = true, + DualClutch = true, + }) + + ACF.RegisterGearbox("7Gear-A-LD-M", "7-Auto", { + Name = "7-Speed Auto, Inline, Medium, Dual Clutch", + Description = "A medium sized, 7 speed automatic inline gearbox", + Model = "models/engines/linear_m.mdl", + Mass = Gear7MW, + Switch = ShiftM, + MaxTorque = Gear7MT, + Automatic = true, + DualClutch = true, + }) + + ACF.RegisterGearbox("7Gear-A-LD-L", "7-Auto", { + Name = "7-Speed Auto, Inline, Large, Dual Clutch", + Description = "A large, heavy and sturdy 7 speed automatic inline gearbox", + Model = "models/engines/linear_l.mdl", + Mass = Gear7LW, + Switch = ShiftL, + MaxTorque = Gear7LT, + Automatic = true, + DualClutch = true, + }) +end + +do -- Transaxial Gearboxes + ACF.RegisterGearbox("7Gear-A-T-S", "7-Auto", { + Name = "7-Speed Auto, Transaxial, Small", + Description = "A small, and light 7 speed automatic gearbox, with a somewhat limited max torque rating", + Model = "models/engines/transaxial_s.mdl", + Mass = Gear7SW, + Switch = ShiftS, + MaxTorque = Gear7ST, + Automatic = true, + }) + + ACF.RegisterGearbox("7Gear-A-T-M", "7-Auto", { + Name = "7-Speed Auto, Transaxial, Medium", + Description = "A medium sized, 7 speed automatic gearbox", + Model = "models/engines/transaxial_m.mdl", + Mass = Gear7MW, + Switch = ShiftM, + MaxTorque = Gear7MT, + Automatic = true, + }) + + ACF.RegisterGearbox("7Gear-A-T-L", "7-Auto", { + Name = "7-Speed Auto, Transaxial, Large", + Description = "A large, heavy and sturdy 7 speed automatic gearbox", + Model = "models/engines/transaxial_l.mdl", + Mass = Gear7LW, + Switch = ShiftL, + MaxTorque = Gear7LT, + Automatic = true, + }) +end + +do -- Transaxial Dual Clutch Gearboxes + ACF.RegisterGearbox("7Gear-A-TD-S", "7-Auto", { + Name = "7-Speed Auto, Transaxial, Small, Dual Clutch", + Description = "A small, and light 7 speed automatic gearbox, with a somewhat limited max torque rating", + Model = "models/engines/transaxial_s.mdl", + Mass = Gear7SW, + Switch = ShiftS, + MaxTorque = Gear7ST, + Automatic = true, + DualClutch = true, + }) + + ACF.RegisterGearbox("7Gear-A-TD-M", "7-Auto", { + Name = "7-Speed Auto, Transaxial, Medium, Dual Clutch", + Description = "A medium sized, 7 speed automatic gearbox", + Model = "models/engines/transaxial_m.mdl", + Mass = Gear7MW, + Switch = ShiftM, + MaxTorque = Gear7MT, + Automatic = true, + DualClutch = true, + }) + + ACF.RegisterGearbox("7Gear-A-TD-L", "7-Auto", { + Name = "7-Speed Auto, Transaxial, Large, Dual Clutch", + Description = "A large, heavy and sturdy 7 speed automatic gearbox", + Model = "models/engines/transaxial_l.mdl", + Mass = Gear7LW, + Switch = ShiftL, + MaxTorque = Gear7LT, + Automatic = true, + DualClutch = true, + }) +end + +do -- Straight-through Gearboxes + ACF.RegisterGearbox("7Gear-A-ST-S", "7-Auto", { + Name = "7-Speed Auto, Straight, Small", + Description = "A small straight-through automatic gearbox", + Model = "models/engines/t5small.mdl", + Mass = math.floor(Gear7SW * StWB), + Switch = ShiftS, + MaxTorque = math.floor(Gear7ST * StTB), + Automatic = true, + }) + + ACF.RegisterGearbox("7Gear-A-ST-M", "7-Auto", { + Name = "7-Speed Auto, Straight, Medium", + Description = "A medium sized, 7 speed automatic straight-through gearbox.", + Model = "models/engines/t5med.mdl", + Mass = math.floor(Gear7MW * StWB), + Switch = ShiftM, + MaxTorque = math.floor(Gear7MT * StTB), + Automatic = true, + }) + + ACF.RegisterGearbox("7Gear-A-ST-L", "7-Auto", { + Name = "7-Speed Auto, Straight, Large", + Description = "A large sized, 7 speed automatic straight-through gearbox.", + Model = "models/engines/t5large.mdl", + Mass = math.floor(Gear7LW * StWB), + Switch = ShiftL, + MaxTorque = math.floor(Gear7LT * StTB), + Automatic = true, + }) +end diff --git a/lua/acf/shared/gearboxes/8-speed.lua b/lua/acf/shared/gearboxes/8-speed.lua index f20262f39..d9eb230eb 100644 --- a/lua/acf/shared/gearboxes/8-speed.lua +++ b/lua/acf/shared/gearboxes/8-speed.lua @@ -373,3 +373,162 @@ ACF_DefineGearbox( "8Gear-ST-L", { [ -1 ] = 0.5 } } ) + +ACF.RegisterGearboxClass("8-Speed", { + Name = "8-Speed Gearbox", + Gears = { + Min = 0, + Max = 8, + } +}) + +do -- Inline Gearboxes + ACF.RegisterGearbox("8Gear-L-S", "8-Speed", { + Name = "8-Speed, Inline, Small", + Description = "A small and light 8 speed gearbox.", + Model = "models/engines/linear_s.mdl", + Mass = Gear8SW, + Switch = 0.15, + MaxTorque = Gear8ST, + }) + + ACF.RegisterGearbox("8Gear-L-M", "8-Speed", { + Name = "8-Speed, Inline, Medium", + Description = "A medium duty 8 speed gearbox..", + Model = "models/engines/linear_m.mdl", + Mass = Gear8MW, + Switch = 0.2, + MaxTorque = Gear8MT, + }) + + ACF.RegisterGearbox("8Gear-L-L", "8-Speed", { + Name = "8-Speed, Inline, Large", + Description = "Heavy duty 8 speed gearbox, however rather heavy.", + Model = "models/engines/linear_l.mdl", + Mass = Gear8LW, + Switch = 0.3, + MaxTorque = Gear8LT, + }) +end + +do -- Inline Dual Clutch Gearboxes + ACF.RegisterGearbox("8Gear-LD-S", "8-Speed", { + Name = "8-Speed, Inline, Small, Dual Clutch", + Description = "A small and light 8 speed gearbox The dual clutch allows you to apply power and brake each side independently\n\nThe Final Drive slider is a multiplier applied to all the other gear ratios", + Model = "models/engines/linear_s.mdl", + Mass = Gear8SW, + Switch = 0.15, + MaxTorque = Gear8ST, + DualClutch = true, + }) + + ACF.RegisterGearbox("8Gear-LD-M", "8-Speed", { + Name = "8-Speed, Inline, Medium, Dual Clutch", + Description = "A a medium duty 8 speed gearbox. The dual clutch allows you to apply power and brake each side independently\n\nThe Final Drive slider is a multiplier applied to all the other gear ratios", + Model = "models/engines/linear_m.mdl", + Mass = Gear8MW, + Switch = 0.2, + MaxTorque = Gear8MT, + DualClutch = true, + }) + + ACF.RegisterGearbox("8Gear-LD-L", "8-Speed", { + Name = "8-Speed, Inline, Large, Dual Clutch", + Description = "Heavy duty 8 speed gearbox. The dual clutch allows you to apply power and brake each side independently\n\nThe Final Drive slider is a multiplier applied to all the other gear ratios", + Model = "models/engines/linear_l.mdl", + Mass = Gear8LW, + Switch = 0.3, + MaxTorque = Gear8LT, + DualClutch = true, + }) +end + +do -- Transaxial Gearboxes + ACF.RegisterGearbox("8Gear-T-S", "8-Speed", { + Name = "8-Speed, Transaxial, Small", + Description = "A small and light 8 speed gearbox..", + Model = "models/engines/transaxial_s.mdl", + Mass = Gear8SW, + Switch = 0.15, + MaxTorque = Gear8ST, + }) + + ACF.RegisterGearbox("8Gear-T-M", "8-Speed", { + Name = "8-Speed, Transaxial, Medium", + Description = "A medium duty 8 speed gearbox..", + Model = "models/engines/transaxial_m.mdl", + Mass = Gear8MW, + Switch = 0.2, + MaxTorque = Gear8MT, + }) + + ACF.RegisterGearbox("8Gear-T-L", "8-Speed", { + Name = "8-Speed, Transaxial, Large", + Description = "Heavy duty 8 speed gearbox, however rather heavy.", + Model = "models/engines/transaxial_l.mdl", + Mass = Gear8LW, + Switch = 0.3, + MaxTorque = Gear8LT, + }) +end + +do -- Transaxial Dual Clutch Gearboxes + ACF.RegisterGearbox("8Gear-TD-S", "8-Speed", { + Name = "8-Speed, Transaxial, Small, Dual Clutch", + Description = "A small and light 8 speed gearbox The dual clutch allows you to apply power and brake each side independently\n\nThe Final Drive slider is a multiplier applied to all the other gear ratios", + Model = "models/engines/transaxial_s.mdl", + Mass = Gear8SW, + Switch = 0.15, + MaxTorque = Gear8ST, + DualClutch = true, + }) + + ACF.RegisterGearbox("8Gear-TD-M", "8-Speed", { + Name = "8-Speed, Transaxial, Medium, Dual Clutch", + Description = "A a medium duty 8 speed gearbox. The dual clutch allows you to apply power and brake each side independently\n\nThe Final Drive slider is a multiplier applied to all the other gear ratios", + Model = "models/engines/transaxial_m.mdl", + Mass = Gear8MW, + Switch = 0.2, + MaxTorque = Gear8MT, + DualClutch = true, + }) + + ACF.RegisterGearbox("8Gear-TD-L", "8-Speed", { + Name = "8-Speed, Transaxial, Large, Dual Clutch", + Description = "Heavy duty 8 speed gearbox. The dual clutch allows you to apply power and brake each side independently\n\nThe Final Drive slider is a multiplier applied to all the other gear ratios", + Model = "models/engines/transaxial_l.mdl", + Mass = Gear8LW, + Switch = 0.3, + MaxTorque = Gear8LT, + DualClutch = true, + }) +end + +do -- Straight-through Gearboxes + ACF.RegisterGearbox("8Gear-ST-S", "8-Speed", { + Name = "8-Speed, Straight, Small", + Description = "A small and light 8 speed straight-through gearbox.", + Model = "models/engines/t5small.mdl", + Mass = math.floor(Gear8SW * StWB), + Switch = 0.15, + MaxTorque = math.floor(Gear8ST * StTB), + }) + + ACF.RegisterGearbox("8Gear-ST-M", "8-Speed", { + Name = "8-Speed, Straight, Medium", + Description = "A medium 8 speed straight-through gearbox.", + Model = "models/engines/t5med.mdl", + Mass = math.floor(Gear8MW * StWB), + Switch = 0.2, + MaxTorque = math.floor(Gear8MT * StTB), + }) + + ACF.RegisterGearbox("8Gear-ST-L", "8-Speed", { + Name = "8-Speed, Straight, Large", + Description = "A large 8 speed straight-through gearbox.", + Model = "models/engines/t5large.mdl", + Mass = math.floor(Gear8LW * StWB), + Switch = 0.3, + MaxTorque = math.floor(Gear8LT * StTB), + }) +end diff --git a/lua/acf/shared/gearboxes/clutch.lua b/lua/acf/shared/gearboxes/clutch.lua index 8425fa2d8..8bf4fca36 100644 --- a/lua/acf/shared/gearboxes/clutch.lua +++ b/lua/acf/shared/gearboxes/clutch.lua @@ -85,3 +85,49 @@ ACF_DefineGearbox( "Clutch-S-L", { [ -1 ] = 1 } } ) + +ACF.RegisterGearboxClass("Clutch", { + Name = "Clutch", + Gears = { + Min = 1, + Max = 1, + } +}) + +do -- Straight-through Gearboxes + ACF.RegisterGearbox("Clutch-S-T", "Clutch", { + Name = "Clutch, Straight, Tiny", + Description = CDesc, + Model = "models/engines/flywheelclutcht.mdl", + Mass = CTW, + Switch = 0.1, + MaxTorque = CTT, + }) + + ACF.RegisterGearbox("Clutch-S-S", "Clutch", { + Name = "Clutch, Straight, Small", + Description = CDesc, + Model = "models/engines/flywheelclutchs.mdl", + Mass = CSW, + Switch = 0.15, + MaxTorque = CST, + }) + + ACF.RegisterGearbox("Clutch-S-M", "Clutch", { + Name = "Clutch, Straight, Medium", + Description = CDesc, + Model = "models/engines/flywheelclutchm.mdl", + Mass = CMW, + Switch = 0.2, + MaxTorque = CMT, + }) + + ACF.RegisterGearbox("Clutch-S-L", "Clutch", { + Name = "Clutch, Straight, Large", + Description = CDesc, + Model = "models/engines/flywheelclutchb.mdl", + Mass = CLW, + Switch = 0.3, + MaxTorque = CLT, + }) +end diff --git a/lua/acf/shared/gearboxes/cvt.lua b/lua/acf/shared/gearboxes/cvt.lua index 911f32632..5134f23d0 100644 --- a/lua/acf/shared/gearboxes/cvt.lua +++ b/lua/acf/shared/gearboxes/cvt.lua @@ -321,4 +321,178 @@ ACF_DefineGearbox("CVT-ST-L", { [1] = 0, [2] = -0.1 } -}) \ No newline at end of file +}) + +ACF.RegisterGearboxClass("CVT", { + Name = "CVT", + Gears = { + Min = 0, + Max = 2, + } +}) + +do -- Inline Gearboxes + ACF.RegisterGearbox("CVT-L-S", "CVT", { + Name = "CVT, Inline, Small", + Description = "A light duty inline CVT.", + Model = "models/engines/linear_s.mdl", + Mass = GearCVTSW, + Switch = 0.15, + MaxTorque = GearCVTST, + CVT = true, + }) + + ACF.RegisterGearbox("CVT-L-M", "CVT", { + Name = "CVT, Inline, Medium", + Description = "A medium inline CVT.", + Model = "models/engines/linear_m.mdl", + Mass = GearCVTMW, + Switch = 0.2, + MaxTorque = GearCVTMT, + CVT = true, + }) + + ACF.RegisterGearbox("CVT-L-L", "CVT", { + Name = "CVT, Inline, Large", + Description = "A massive inline CVT designed for high torque applications.", + Model = "models/engines/linear_l.mdl", + Mass = GearCVTLW, + Switch = 0.3, + MaxTorque = GearCVTLT, + CVT = true, + }) +end + +do -- Inline Dual Clutch Gearboxes + ACF.RegisterGearbox("CVT-LD-S", "CVT", { + Name = "CVT, Inline, Small, Dual Clutch", + Description = "A light duty inline CVT. The dual clutch allows you to apply power and brake each side independently.", + Model = "models/engines/linear_s.mdl", + Mass = GearCVTSW, + Switch = 0.15, + MaxTorque = GearCVTST, + DualClutch = true, + CVT = true, + }) + + ACF.RegisterGearbox("CVT-LD-M", "CVT", { + Name = "CVT, Inline, Medium, Dual Clutch", + Description = "A medium inline CVT. The dual clutch allows you to apply power and brake each side independently.", + Model = "models/engines/linear_m.mdl", + Mass = GearCVTMW, + Switch = 0.2, + MaxTorque = GearCVTMT, + DualClutch = true, + CVT = true, + }) + + ACF.RegisterGearbox("CVT-LD-L", "CVT", { + Name = "CVT, Inline, Large, Dual Clutch", + Description = "A massive inline CVT designed for high torque applications. The dual clutch allows you to apply power and brake each side independently.", + Model = "models/engines/linear_l.mdl", + Mass = GearCVTLW, + Switch = 0.3, + MaxTorque = GearCVTLT, + DualClutch = true, + CVT = true, + }) +end + +do -- Transaxial Gearboxes + ACF.RegisterGearbox("CVT-T-S", "CVT", { + Name = "CVT, Transaxial, Small", + Description = "A light duty CVT.", + Model = "models/engines/transaxial_s.mdl", + Mass = GearCVTSW, + Switch = 0.15, + MaxTorque = GearCVTST, + CVT = true, + }) + + ACF.RegisterGearbox("CVT-T-M", "CVT", { + Name = "CVT, Transaxial, Medium", + Description = "A medium CVT.", + Model = "models/engines/transaxial_m.mdl", + Mass = GearCVTMW, + Switch = 0.2, + MaxTorque = GearCVTMT, + CVT = true, + }) + + ACF.RegisterGearbox("CVT-T-L", "CVT", { + Name = "CVT, Transaxial, Large", + Description = "A massive CVT designed for high torque applications.", + Model = "models/engines/transaxial_l.mdl", + Mass = GearCVTLW, + Switch = 0.3, + MaxTorque = GearCVTLT, + CVT = true, + }) +end + +do -- Transaxial Dual Clutch Gearboxes + ACF.RegisterGearbox("CVT-TD-S", "CVT", { + Name = "CVT, Transaxial, Small, Dual Clutch", + Description = "A light duty CVT. The dual clutch allows you to apply power and brake each side independently.", + Model = "models/engines/transaxial_s.mdl", + Mass = GearCVTSW, + Switch = 0.15, + MaxTorque = GearCVTST, + DualClutch = true, + CVT = true, + }) + + ACF.RegisterGearbox("CVT-TD-M", "CVT", { + Name = "CVT, Transaxial, Medium, Dual Clutch", + Description = "A medium CVT. The dual clutch allows you to apply power and brake each side independently.", + Model = "models/engines/transaxial_m.mdl", + Mass = GearCVTMW, + Switch = 0.2, + MaxTorque = GearCVTMT, + DualClutch = true, + CVT = true, + }) + + ACF.RegisterGearbox("CVT-TD-L", "CVT", { + Name = "CVT, Transaxial, Large, Dual Clutch", + Description = "A massive CVT designed for high torque applications. The dual clutch allows you to apply power and brake each side independently.", + Model = "models/engines/transaxial_l.mdl", + Mass = GearCVTLW, + Switch = 0.3, + MaxTorque = GearCVTLT, + DualClutch = true, + CVT = true, + }) +end + +do -- Straight-through Gearboxes + ACF.RegisterGearbox("CVT-ST-S", "CVT", { + Name = "CVT, Straight, Small", + Description = "A light duty straight-through CVT.", + Model = "models/engines/t5small.mdl", + Mass = math.floor(GearCVTSW * StWB), + Switch = 0.15, + MaxTorque = math.floor(GearCVTST * StTB), + CVT = true, + }) + + ACF.RegisterGearbox("CVT-ST-M", "CVT", { + Name = "CVT, Straight, Medium", + Description = "A medium straight-through CVT.", + Model = "models/engines/t5med.mdl", + Mass = math.floor(GearCVTMW * StWB), + Switch = 0.2, + MaxTorque = math.floor(GearCVTMT * StTB), + CVT = true, + }) + + ACF.RegisterGearbox("CVT-ST-L", "CVT", { + Name = "CVT, Straight, Large", + Description = "A massive straight-through CVT designed for high torque applications.", + Model = "models/engines/t5large.mdl", + Mass = math.floor(GearCVTLW * StWB), + Switch = 0.3, + MaxTorque = math.floor(GearCVTLT * StTB), + CVT = true, + }) +end diff --git a/lua/acf/shared/gearboxes/differential.lua b/lua/acf/shared/gearboxes/differential.lua index 2ca8e6fff..4148f9b08 100644 --- a/lua/acf/shared/gearboxes/differential.lua +++ b/lua/acf/shared/gearboxes/differential.lua @@ -222,3 +222,133 @@ ACF_DefineGearbox( "1Gear-TD-L", { [ -1 ] = 1 } } ) + +ACF.RegisterGearboxClass("Differential", { + Name = "Differential", + Gears = { + Min = 1, + Max = 1, + } +}) + +do -- Inline Gearboxes + ACF.RegisterGearbox("1Gear-L-S", "Differential", { + Name = "Differential, Inline, Small", + Description = "Small differential, used to connect power from gearbox to wheels", + Model = "models/engines/linear_s.mdl", + Mass = Gear1SW, + Switch = 0.3, + MaxTorque = 25000, + }) + + ACF.RegisterGearbox("1Gear-L-M", "Differential", { + Name = "Differential, Inline, Medium", + Description = "Medium duty differential", + Model = "models/engines/linear_m.mdl", + Mass = Gear1MW, + Switch = 0.4, + MaxTorque = 50000, + }) + + ACF.RegisterGearbox("1Gear-L-L", "Differential", { + Name = "Differential, Inline, Large", + Description = "Heavy duty differential, for the heaviest of engines", + Model = "models/engines/linear_l.mdl", + Mass = Gear1LW, + Switch = 0.6, + MaxTorque = 100000, + }) +end + +do -- Inline Dual Clutch Gearboxes + ACF.RegisterGearbox("1Gear-LD-S", "Differential", { + Name = "Differential, Inline, Small, Dual Clutch", + Description = "Small differential, used to connect power from gearbox to wheels", + Model = "models/engines/linear_s.mdl", + Mass = Gear1SW, + Switch = 0.3, + MaxTorque = 25000, + DualClutch = true, + }) + + ACF.RegisterGearbox("1Gear-LD-M", "Differential", { + Name = "Differential, Inline, Medium, Dual Clutch", + Description = "Medium duty differential", + Model = "models/engines/linear_m.mdl", + Mass = Gear1MW, + Switch = 0.4, + MaxTorque = 50000, + DualClutch = true, + }) + + ACF.RegisterGearbox("1Gear-LD-L", "Differential", { + Name = "Differential, Inline, Large, Dual Clutch", + Description = "Heavy duty differential, for the heaviest of engines", + Model = "models/engines/linear_l.mdl", + Mass = Gear1LW, + Switch = 0.6, + MaxTorque = 100000, + DualClutch = true, + }) +end + +do -- Transaxial Gearboxes + ACF.RegisterGearbox("1Gear-T-S", "Differential", { + Name = "Differential, Small", + Description = "Small differential, used to connect power from gearbox to wheels", + Model = "models/engines/transaxial_s.mdl", + Mass = Gear1SW, + Switch = 0.3, + MaxTorque = 25000, + }) + + ACF.RegisterGearbox("1Gear-T-M", "Differential", { + Name = "Differential, Medium", + Description = "Medium duty differential", + Model = "models/engines/transaxial_m.mdl", + Mass = Gear1MW, + Switch = 0.4, + MaxTorque = 50000, + }) + + ACF.RegisterGearbox("1Gear-T-L", "Differential", { + Name = "Differential, Large", + Description = "Heavy duty differential, for the heaviest of engines", + Model = "models/engines/transaxial_l.mdl", + Mass = Gear1LW, + Switch = 0.6, + MaxTorque = 100000, + }) +end + +do -- Transaxial Dual Clutch Gearboxes + ACF.RegisterGearbox("1Gear-TD-S", "Differential", { + Name = "Differential, Small, Dual Clutch", + Description = "Small differential, used to connect power from gearbox to wheels", + Model = "models/engines/transaxial_s.mdl", + Mass = Gear1SW, + Switch = 0.3, + MaxTorque = 25000, + DualClutch = true, + }) + + ACF.RegisterGearbox("1Gear-TD-M", "Differential", { + Name = "Differential, Medium, Dual Clutch", + Description = "Medium duty differential", + Model = "models/engines/transaxial_m.mdl", + Mass = Gear1MW, + Switch = 0.4, + MaxTorque = 50000, + DualClutch = true, + }) + + ACF.RegisterGearbox("1Gear-TD-L", "Differential", { + Name = "Differential, Large, Dual Clutch", + Description = "Heavy duty differential, for the heaviest of engines", + Model = "models/engines/transaxial_l.mdl", + Mass = Gear1LW, + Switch = 0.6, + MaxTorque = 100000, + DualClutch = true, + }) +end diff --git a/lua/acf/shared/gearboxes/doublediff.lua b/lua/acf/shared/gearboxes/doublediff.lua index c398315cc..e26e3ca7a 100644 --- a/lua/acf/shared/gearboxes/doublediff.lua +++ b/lua/acf/shared/gearboxes/doublediff.lua @@ -66,4 +66,47 @@ ACF_DefineGearbox("DoubleDiff-T-L", { [1] = 1, [-1] = 1 } -}) \ No newline at end of file +}) + +ACF.RegisterGearboxClass("DoubleDiff", { + Name = "Regenerative Steering", + Gears = { + Min = 1, + Max = 1, + } +}) + +do -- Inline Gearboxes + ACF.RegisterGearbox("DoubleDiff-T-S", "DoubleDiff", { + Name = "Double Differential, Small", + Description = "A light duty regenerative steering transmission.", + Model = "models/engines/transaxial_s.mdl", + Mass = GearDDSW, + Switch = 0.2, + MaxTorque = GearDDST, + DualClutch = true, + DoubleDiff = true, + }) + + ACF.RegisterGearbox("DoubleDiff-T-M", "DoubleDiff", { + Name = "Double Differential, Medium", + Description = "A medium regenerative steering transmission.", + Model = "models/engines/transaxial_m.mdl", + Mass = GearDDMW, + Switch = 0.35, + MaxTorque = GearDDMT, + DualClutch = true, + DoubleDiff = true, + }) + + ACF.RegisterGearbox("DoubleDiff-T-L", "DoubleDiff", { + Name = "Double Differential, Large", + Description = "A heavy regenerative steering transmission.", + Model = "models/engines/transaxial_l.mdl", + Mass = GearDDLW, + Switch = 0.5, + MaxTorque = GearDDLT, + DualClutch = true, + DoubleDiff = true, + }) +end diff --git a/lua/acf/shared/gearboxes/transfer.lua b/lua/acf/shared/gearboxes/transfer.lua index 853d16875..a7d7c0bca 100644 --- a/lua/acf/shared/gearboxes/transfer.lua +++ b/lua/acf/shared/gearboxes/transfer.lua @@ -122,3 +122,75 @@ ACF_DefineGearbox( "2Gear-T-L", { [ -1 ] = 1 } } ) + +ACF.RegisterGearboxClass("Transfer", { + Name = "Transfer Case", + Gears = { + Min = 1, + Max = 2, + } +}) + +do -- Inline Gearboxes + ACF.RegisterGearbox("2Gear-L-S", "Transfer", { + Name = "Transfer case, Inline, Small", + Description = "2 speed gearbox, useful for low/high range and tank turning", + Model = "models/engines/linear_s.mdl", + Mass = Gear2SW, + Switch = 0.3, + MaxTorque = 25000, + DualClutch = true, + }) + + ACF.RegisterGearbox("2Gear-L-M", "Transfer", { + Name = "Transfer case, Inline, Medium", + Description = "2 speed gearbox, useful for low/high range and tank turning", + Model = "models/engines/linear_m.mdl", + Mass = Gear2MW, + Switch = 0.4, + MaxTorque = 50000, + DualClutch = true, + }) + + ACF.RegisterGearbox("2Gear-L-L", "Transfer", { + Name = "Transfer case, Inline, Large", + Description = "2 speed gearbox, useful for low/high range and tank turning", + Model = "models/engines/linear_l.mdl", + Mass = Gear2LW, + Switch = 0.6, + MaxTorque = 100000, + DualClutch = true, + }) +end + +do -- Transaxial Gearboxes + ACF.RegisterGearbox("2Gear-T-S", "Transfer", { + Name = "Transfer case, Small", + Description = "2 speed gearbox, useful for low/high range and tank turning", + Model = "models/engines/transaxial_s.mdl", + Mass = Gear2SW, + Switch = 0.3, + MaxTorque = 25000, + DualClutch = true, + }) + + ACF.RegisterGearbox("2Gear-T-M", "Transfer", { + Name = "Transfer case, Medium", + Description = "2 speed gearbox, useful for low/high range and tank turning", + Model = "models/engines/transaxial_m.mdl", + Mass = Gear2MW, + Switch = 0.4, + MaxTorque = 50000, + DualClutch = true, + }) + + ACF.RegisterGearbox("2Gear-T-L", "Transfer", { + Name = "Transfer case, Large", + Description = "2 speed gearbox, useful for low/high range and tank turning", + Model = "models/engines/transaxial_l.mdl", + Mass = Gear2LW, + Switch = 0.6, + MaxTorque = 100000, + DualClutch = true, + }) +end From 3c0a34b8feb34b4a20b7ef87aafd82b6663c5437 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Tue, 24 Mar 2020 04:30:11 -0300 Subject: [PATCH 045/279] Added base gearbox menu --- lua/acf/client/menu_items/gearboxes_menu.lua | 81 ++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 lua/acf/client/menu_items/gearboxes_menu.lua diff --git a/lua/acf/client/menu_items/gearboxes_menu.lua b/lua/acf/client/menu_items/gearboxes_menu.lua new file mode 100644 index 000000000..7c6fe5683 --- /dev/null +++ b/lua/acf/client/menu_items/gearboxes_menu.lua @@ -0,0 +1,81 @@ +local Gearboxes = ACF.Classes.Gearboxes +local Selected = {} +local Sorted = {} + +local function LoadSortedList(Panel, List, Member) + local Choices = Sorted[List] + + if not Choices then + Choices = {} + + local Count = 0 + for _, V in pairs(List) do + Count = Count + 1 + Choices[Count] = V + end + + table.SortByMember(Choices, Member, true) + + Sorted[List] = Choices + Selected[Choices] = 1 + end + + Panel:Clear() + + for _, V in pairs(Choices) do + Panel:AddChoice(V.Name, V) + end + + Panel:ChooseOptionID(Selected[Choices]) +end + +local function CreateMenu(Menu) + local GearboxClass = Menu:AddComboBox() + local GearboxList = Menu:AddComboBox() + local GearboxName = Menu:AddTitle() + local GearboxDesc = Menu:AddLabel() + + ACF.WriteValue("PrimaryClass", "acf_gearbox") + ACF.WriteValue("SecondaryClass", "N/A") + + function GearboxClass:OnSelect(Index, _, Data) + if self.Selected == Data then return end + + self.Selected = Data + + local Choices = Sorted[Gearboxes] + Selected[Choices] = Index + + ACF.WriteValue("GearboxClass", Data.ID) + + LoadSortedList(GearboxList, Data.Items, "ID") + end + + function GearboxList:OnSelect(Index, _, Data) + if self.Selected == Data then return end + + self.Selected = Data + + local ClassData = EngineClass.Selected + local Choices = Sorted[ClassData.Items] + Selected[Choices] = Index + + ACF.WriteValue("Gearbox", Data.ID) + + GearboxName:SetText(Data.Name) + GearboxDesc:SetText(Data.Description) + + Menu:ClearTemporal(self) + Menu:StartTemporal(self) + + if Data.SetupMenu then + Data.SetupMenu(Menu) + end + + Menu:EndTemporal(self) + end + + LoadSortedList(GearboxClass, Gearboxes, "ID") +end + +ACF.AddOptionItem("Entities", "Gearboxes", "cog", CreateMenu) From 5fb9f644971dc82a9e711ae1e774f8ef35ad04e2 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Wed, 25 Mar 2020 05:36:19 -0300 Subject: [PATCH 046/279] Refactorized basic class registration functions - Added ACF.AddSimpleClass, ACF.AddClassGroup and ACF.AddGroupedClass in order to help reduce the amount of repeated code when creating new basic class registration functions. - Added sensor and components registration functions. --- lua/acf/base/sh_classes.lua | 348 +++++++++++++++--------------------- 1 file changed, 143 insertions(+), 205 deletions(-) diff --git a/lua/acf/base/sh_classes.lua b/lua/acf/base/sh_classes.lua index 9ba0df439..f8ae2d679 100644 --- a/lua/acf/base/sh_classes.lua +++ b/lua/acf/base/sh_classes.lua @@ -1,3 +1,85 @@ +do -- Basic class registration functions + function ACF.AddSimpleClass(ID, Destiny, Data) + if not ID then return end + if not Data then return end + if not Destiny then return end + + local Class = Destiny[ID] + + if not Class then + Class = { + ID = ID, + } + + Destiny[ID] = Class + end + + for K, V in pairs(Data) do + Class[K] = V + end + + return Class + end + + function ACF.AddClassGroup(ID, Destiny, Data) + if not ID then return end + if not Data then return end + if not Destiny then return end + + local Group = Destiny[ID] + + if not Group then + Group = { + ID = ID, + Lookup = {}, + Items = {}, + Count = 0, + } + + Destiny[ID] = Group + end + + for K, V in pairs(Data) do + Group[K] = V + end + + return Group + end + + function ACF.AddGroupedClass(ID, GroupID, Destiny, Data) + if not ID then return end + if not Data then return end + if not GroupID then return end + if not Destiny then return end + if not Destiny[GroupID] then return end + + local Group = Destiny[GroupID] + local Class = Group.Lookup[ID] + + if not Class then + Class = { + ID = ID, + Class = Group, + ClassID = GroupID, + } + + Group.Count = Group.Count + 1 + Group.Lookup[ID] = Class + Group.Items[Group.Count] = Class + end + + for K, V in pairs(Data) do + Class[K] = V + end + + return Class + end +end + +local AddSimpleClass = ACF.AddSimpleClass +local AddClassGroup = ACF.AddClassGroup +local AddGroupedClass = ACF.AddGroupedClass + do -- Class registration function local Classes = {} local Queued = {} @@ -81,60 +163,27 @@ do -- Weapon registration functions local Weapons = ACF.Classes.Weapons function ACF.RegisterWeaponClass(ID, Data) - if not ID then return end - if not Data then return end - - local Class = Weapons[ID] + local Group = AddClassGroup(ID, Weapons, Data) - if not Class then - Class = { - ID = ID, - Lookup = {}, - Items = {}, - Count = 0, - } - - Weapons[ID] = Class - end - - for K, V in pairs(Data) do - Class[K] = V + if Group.MuzzleFlash then + PrecacheParticleSystem(Group.MuzzleFlash) end - if Class.MuzzleFlash then - PrecacheParticleSystem(Class.MuzzleFlash) - end + return Group end function ACF.RegisterWeapon(ID, ClassID, Data) - if not ID then return end - if not ClassID then return end - if not Data then return end - if not Weapons[ClassID] then return end - - local Class = Weapons[ClassID] - local Weapon = Class.Lookup[ID] + local Class = AddGroupedClass(ID, ClassID, Weapons, Data) - if not Weapon then - Weapon = { - ID = ID, - Class = Class, - ClassID = ClassID, - EntClass = "acf_gun", - } - - Class.Count = Class.Count + 1 - Class.Items[Class.Count] = Weapon - Class.Lookup[ID] = Weapon + if not Class.EntClass then + Class.EntClass = "acf_gun" end - for K, V in pairs(Data) do - Weapon[K] = V + if Class.MuzzleFlash then + PrecacheParticleSystem(Class.MuzzleFlash) end - if Weapon.MuzzleFlash then - PrecacheParticleSystem(Weapon.MuzzleFlash) - end + return Class end end @@ -144,23 +193,13 @@ do -- Ammo crate registration function local Crates = ACF.Classes.Crates function ACF.RegisterCrate(ID, Data) - if not ID then return end - if not Data then return end - - local Crate = Crates[ID] + local Class = AddSimpleClass(ID, Crates, Data) - if not Crate then - Crate = { - ID = ID, - EntClass = "acf_ammo", - } - - Crates[ID] = Crate + if not Class.EntClass then + Class.EntClass = "acf_ammo" end - for K, V in pairs(Data) do - Crate[K] = V - end + return Class end end @@ -181,52 +220,17 @@ do -- Engine registration functions local Engines = ACF.Classes.Engines function ACF.RegisterEngineClass(ID, Data) - if not ID then return end - if not Data then return end - - local Class = Engines[ID] - - if not Class then - Class = { - ID = ID, - Lookup = {}, - Items = {}, - Count = 0, - } - - Engines[ID] = Class - end - - for K, V in pairs(Data) do - Class[K] = V - end + return AddClassGroup(ID, Engines, Data) end function ACF.RegisterEngine(ID, ClassID, Data) - if not ID then return end - if not ClassID then return end - if not Data then return end - if not Engines[ClassID] then return end + local Class = AddGroupedClass(ID, ClassID, Engines, Data) - local Class = Engines[ClassID] - local Engine = Class.Lookup[ID] - - if not Engine then - Engine = { - ID = ID, - Class = Class, - ClassID = ClassID, - EntClass = "acf_engine", - } - - Class.Count = Class.Count + 1 - Class.Items[Class.Count] = Engine - Class.Lookup[ID] = Engine + if not Class.EntClass then + Class.EntClass = "acf_engine" end - for K, V in pairs(Data) do - Engine[K] = V - end + return Class end end @@ -236,22 +240,7 @@ do -- Engine type registration function local Types = ACF.Classes.EngineTypes function ACF.RegisterEngineType(ID, Data) - if not ID then return end - if not Data then return end - - local Type = Types[ID] - - if not Type then - Type = { - ID = ID, - } - - Types[ID] = Type - end - - for K, V in pairs(Data) do - Type[K] = V - end + return AddSimpleClass(ID, Types, Data) end end @@ -261,53 +250,21 @@ do -- Fuel tank registration functions local FuelTanks = ACF.Classes.FuelTanks function ACF.RegisterFuelTankClass(ID, Data) - if not ID then return end - if not Data then return end - - local Class = FuelTanks[ID] - - if not Class then - Class = { - ID = ID, - Lookup = {}, - Items = {}, - Count = 0, - } - - FuelTanks[ID] = Class - end - - for K, V in pairs(Data) do - Class[K] = V - end + return AddClassGroup(ID, FuelTanks, Data) end function ACF.RegisterFuelTank(ID, ClassID, Data) - if not ID then return end - if not ClassID then return end - if not Data then return end - if not FuelTanks[ClassID] then return end + local Class = AddGroupedClass(ID, ClassID, FuelTanks, Data) - local Class = FuelTanks[ClassID] - local FuelTank = Class.Lookup[ID] - - if not FuelTank then - FuelTank = { - ID = ID, - Class = Class, - ClassID = ClassID, - EntClass = "acf_engine", - IsExplosive = true, - } - - Class.Count = Class.Count + 1 - Class.Items[Class.Count] = FuelTank - Class.Lookup[ID] = FuelTank + if not Class.EntClass then + Class.EntClass = "acf_engine" end - for K, V in pairs(Data) do - FuelTank[K] = V + if Class.IsExplosive == nil then + Class.IsExplosive = true end + + return Class end end @@ -317,22 +274,7 @@ do -- Fuel type registration function local Types = ACF.Classes.FuelTypes function ACF.RegisterFuelType(ID, Data) - if not ID then return end - if not Data then return end - - local Type = Types[ID] - - if not Type then - Type = { - ID = ID, - } - - Types[ID] = Type - end - - for K, V in pairs(Data) do - Type[K] = V - end + return AddSimpleClass(ID, Types, Data) end end @@ -342,52 +284,48 @@ do -- Gearbox registration functions local Gearboxes = ACF.Classes.Gearboxes function ACF.RegisterGearboxClass(ID, Data) - if not ID then return end - if not Data then return end - - local Class = Gearboxes[ID] + return AddClassGroup(ID, Gearboxes, Data) + end - if not Class then - Class = { - ID = ID, - Lookup = {}, - Items = {}, - Count = 0, - } + function ACF.RegisterGearbox(ID, ClassID, Data) + local Class = AddGroupedClass(ID, ClassID, Gearboxes, Data) - Gearboxes[ID] = Class + if not Class.EntClass then + Class.EntClass = "acf_gearbox" end - for K, V in pairs(Data) do - Class[K] = V + if not Class.Sound then + Class.Sound = "vehicles/junker/jnk_fourth_cruise_loop2.wav" end + + return Class end +end - function ACF.RegisterGearbox(ID, ClassID, Data) - if not ID then return end - if not ClassID then return end - if not Data then return end - if not Gearboxes[ClassID] then return end +do -- Component registration functions + ACF.Classes.Components = ACF.Classes.Components or {} - local Class = Gearboxes[ClassID] - local Gearbox = Class.Lookup[ID] + local Components = ACF.Classes.Components - if not Gearbox then - Gearbox = { - ID = ID, - Class = Class, - ClassID = ClassID, - EntClass = "acf_gearbox", - Sound = "vehicles/junker/jnk_fourth_cruise_loop2.wav", - } + function ACF.RegisterComponentClass(ID, Data) + return AddClassGroup(ID, Components, Data) + end - Class.Count = Class.Count + 1 - Class.Items[Class.Count] = Gearbox - Class.Lookup[ID] = Gearbox - end + function ACF.RegisterComponent(ID, ClassID, Data) + return AddGroupedClass(ID, ClassID, Components, Data) + end +end - for K, V in pairs(Data) do - Gearbox[K] = V - end +do -- Sensor registration functions + ACF.Classes.Sensors = ACF.Classes.Sensors or {} + + local Sensors = ACF.Classes.Sensors + + function ACF.RegisterSensorClass(ID, Data) + return AddClassGroup(ID, Sensors, Data) + end + + function ACF.RegisterSensor(ID, ClassID, Data) + return AddGroupedClass(ID, ClassID, Sensors, Data) end end From f24a415cde7e949a79c21906b1236930661eb614 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Wed, 25 Mar 2020 05:38:52 -0300 Subject: [PATCH 047/279] Added Components and Sensors tool menus - Added component menu. - Added sensor menu. - Fixed a typo inside the gearbox menu. - Fixed 17.2L I6 and 4-Speed, Inline, Small gearbox not being registered correctly. --- lua/acf/client/menu_items/components_menu.lua | 87 +++++++++++++++++++ lua/acf/client/menu_items/gearboxes_menu.lua | 6 +- lua/acf/client/menu_items/sensors_menu.lua | 87 +++++++++++++++++++ lua/acf/shared/engines/i6.lua | 2 +- lua/acf/shared/gearboxes/4-speed.lua | 2 +- 5 files changed, 179 insertions(+), 5 deletions(-) create mode 100644 lua/acf/client/menu_items/components_menu.lua create mode 100644 lua/acf/client/menu_items/sensors_menu.lua diff --git a/lua/acf/client/menu_items/components_menu.lua b/lua/acf/client/menu_items/components_menu.lua new file mode 100644 index 000000000..72a374724 --- /dev/null +++ b/lua/acf/client/menu_items/components_menu.lua @@ -0,0 +1,87 @@ +local Components = ACF.Classes.Components +local Selected = {} +local Sorted = {} + +local function LoadSortedList(Panel, List, Member) + local Choices = Sorted[List] + + if not Choices then + Choices = {} + + local Count = 0 + for _, V in pairs(List) do + Count = Count + 1 + Choices[Count] = V + end + + table.SortByMember(Choices, Member, true) + + Sorted[List] = Choices + Selected[Choices] = 1 + end + + Panel:Clear() + + for _, V in pairs(Choices) do + Panel:AddChoice(V.Name, V) + end + + Panel:ChooseOptionID(Selected[Choices]) +end + +local function CreateMenu(Menu) + ACF.WriteValue("PrimaryClass", "N/A") + ACF.WriteValue("SecondaryClass", "N/A") + + if not next(Components) then + Menu:AddTitle("No Components Registered") + Menu:AddLabel("No components have been registered. If this is incorrect, check your console for errors and contact the server owner.") + return + end + + local ComponentClass = Menu:AddComboBox() + local ComponentList = Menu:AddComboBox() + local ComponentName = Menu:AddTitle() + local ComponentDesc = Menu:AddLabel() + + function ComponentClass:OnSelect(Index, _, Data) + if self.Selected == Data then return end + + self.Selected = Data + + local Choices = Sorted[Components] + Selected[Choices] = Index + + ACF.WriteValue("ComponentClass", Data.ID) + + LoadSortedList(ComponentList, Data.Items, "ID") + end + + function ComponentList:OnSelect(Index, _, Data) + if self.Selected == Data then return end + + self.Selected = Data + + local ClassData = ComponentClass.Selected + local Choices = Sorted[ClassData.Items] + Selected[Choices] = Index + + ACF.WriteValue("Component", Data.ID) + + ComponentName:SetText(Data.Name) + ComponentDesc:SetText(Data.Description or "No description provided.") + + Menu:ClearTemporal(self) + Menu:StartTemporal(self) + + if Data.CreateMenu then + Data:CreateMenu(Menu) + end + + Menu:EndTemporal(self) + end + + LoadSortedList(ComponentClass, Components, "ID") +end + +ACF.AddOptionItem("Entities", "Components", "drive", CreateMenu) diff --git a/lua/acf/client/menu_items/gearboxes_menu.lua b/lua/acf/client/menu_items/gearboxes_menu.lua index 7c6fe5683..cf07659e5 100644 --- a/lua/acf/client/menu_items/gearboxes_menu.lua +++ b/lua/acf/client/menu_items/gearboxes_menu.lua @@ -56,7 +56,7 @@ local function CreateMenu(Menu) self.Selected = Data - local ClassData = EngineClass.Selected + local ClassData = GearboxClass.Selected local Choices = Sorted[ClassData.Items] Selected[Choices] = Index @@ -68,8 +68,8 @@ local function CreateMenu(Menu) Menu:ClearTemporal(self) Menu:StartTemporal(self) - if Data.SetupMenu then - Data.SetupMenu(Menu) + if Data.CreateMenu then + Data:CreateMenu(Menu) end Menu:EndTemporal(self) diff --git a/lua/acf/client/menu_items/sensors_menu.lua b/lua/acf/client/menu_items/sensors_menu.lua new file mode 100644 index 000000000..a3647529a --- /dev/null +++ b/lua/acf/client/menu_items/sensors_menu.lua @@ -0,0 +1,87 @@ +local Sensors = ACF.Classes.Sensors +local Selected = {} +local Sorted = {} + +local function LoadSortedList(Panel, List, Member) + local Choices = Sorted[List] + + if not Choices then + Choices = {} + + local Count = 0 + for _, V in pairs(List) do + Count = Count + 1 + Choices[Count] = V + end + + table.SortByMember(Choices, Member, true) + + Sorted[List] = Choices + Selected[Choices] = 1 + end + + Panel:Clear() + + for _, V in pairs(Choices) do + Panel:AddChoice(V.Name, V) + end + + Panel:ChooseOptionID(Selected[Choices]) +end + +local function CreateMenu(Menu) + ACF.WriteValue("PrimaryClass", "N/A") + ACF.WriteValue("SecondaryClass", "N/A") + + if not next(Sensors) then + Menu:AddTitle("No Sensors Registered") + Menu:AddLabel("No sensors have been registered. If this is incorrect, check your console for errors and contact the server owner.") + return + end + + local SensorClass = Menu:AddComboBox() + local SensorList = Menu:AddComboBox() + local SensorName = Menu:AddTitle() + local SensorDesc = Menu:AddLabel() + + function SensorClass:OnSelect(Index, _, Data) + if self.Selected == Data then return end + + self.Selected = Data + + local Choices = Sorted[Sensors] + Selected[Choices] = Index + + ACF.WriteValue("SensorClass", Data.ID) + + LoadSortedList(SensorList, Data.Items, "ID") + end + + function SensorList:OnSelect(Index, _, Data) + if self.Selected == Data then return end + + self.Selected = Data + + local ClassData = SensorClass.Selected + local Choices = Sorted[ClassData.Items] + Selected[Choices] = Index + + ACF.WriteValue("Sensor", Data.ID) + + SensorName:SetText(Data.Name) + SensorDesc:SetText(Data.Description or "No description provided.") + + Menu:ClearTemporal(self) + Menu:StartTemporal(self) + + if Data.CreateMenu then + Data:CreateMenu(Menu) + end + + Menu:EndTemporal(self) + end + + LoadSortedList(SensorClass, Sensors, "ID") +end + +ACF.AddOptionItem("Entities", "Sensors", "transmit", CreateMenu) diff --git a/lua/acf/shared/engines/i6.lua b/lua/acf/shared/engines/i6.lua index a2d5fa809..ade866b00 100644 --- a/lua/acf/shared/engines/i6.lua +++ b/lua/acf/shared/engines/i6.lua @@ -148,7 +148,7 @@ do -- Petrol Engines } }) - ACF.RegisterEngine( "17.2-I6", { + ACF.RegisterEngine("17.2-I6", "I6", { Name = "17.2L I6 Petrol", Description = "Heavy tractor duty petrol I6, decent overall powerband.", Model = "models/engines/inline6l.mdl", diff --git a/lua/acf/shared/gearboxes/4-speed.lua b/lua/acf/shared/gearboxes/4-speed.lua index 10c555d46..4f9c0a123 100644 --- a/lua/acf/shared/gearboxes/4-speed.lua +++ b/lua/acf/shared/gearboxes/4-speed.lua @@ -325,7 +325,7 @@ ACF.RegisterGearboxClass("4-Speed", { }) do -- Inline Gearboxes - ACF.RegisterGearbox("4Gear-L-S", "4-Speed", "4-Speed", { + ACF.RegisterGearbox("4Gear-L-S", "4-Speed", { Name = "4-Speed, Inline, Small", Description = "A small, and light 4 speed inline gearbox, with a somewhat limited max torque rating.", Model = "models/engines/linear_s.mdl", From 83e4543babaa7aaa648b7b3472ac9594fd931fe7 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Thu, 26 Mar 2020 07:58:27 -0300 Subject: [PATCH 048/279] Added manual and CVT gearboxes menu --- lua/acf/client/menu_items/gearboxes_menu.lua | 158 ++++++++++++++++++- lua/acf/shared/gearboxes/3-auto.lua | 5 +- lua/acf/shared/gearboxes/4-speed.lua | 4 +- lua/acf/shared/gearboxes/5-auto.lua | 3 +- lua/acf/shared/gearboxes/6-speed.lua | 3 +- lua/acf/shared/gearboxes/7-auto.lua | 3 +- lua/acf/shared/gearboxes/8-speed.lua | 3 +- lua/acf/shared/gearboxes/clutch.lua | 3 +- lua/acf/shared/gearboxes/cvt.lua | 8 +- lua/acf/shared/gearboxes/differential.lua | 3 +- lua/acf/shared/gearboxes/doublediff.lua | 3 +- lua/acf/shared/gearboxes/transfer.lua | 3 +- 12 files changed, 182 insertions(+), 17 deletions(-) diff --git a/lua/acf/client/menu_items/gearboxes_menu.lua b/lua/acf/client/menu_items/gearboxes_menu.lua index cf07659e5..b48597f49 100644 --- a/lua/acf/client/menu_items/gearboxes_menu.lua +++ b/lua/acf/client/menu_items/gearboxes_menu.lua @@ -68,8 +68,8 @@ local function CreateMenu(Menu) Menu:ClearTemporal(self) Menu:StartTemporal(self) - if Data.CreateMenu then - Data:CreateMenu(Menu) + if ClassData.CreateMenu then + ClassData:CreateMenu(Data, Menu) end Menu:EndTemporal(self) @@ -79,3 +79,157 @@ local function CreateMenu(Menu) end ACF.AddOptionItem("Entities", "Gearboxes", "cog", CreateMenu) + +do -- Default Menus + local Values = {} + local CVTData = { + { + Name = "Gear 2", + Variable = "Gear2", + Min = -1, + Max = 1, + Decimals = 2, + Default = -0.1, + }, + { + Name = "Min Target RPM", + Variable = "MinRPM", + Min = 1, + Max = 10000, + Decimals = 0, + Default = 3000, + }, + { + Name = "Max Target RPM", + Variable = "MaxRPM", + Min = 1, + Max = 10000, + Decimals = 0, + Default = 5000, + }, + { + Name = "Final Drive", + Variable = "FinalDrive", + Min = -1, + Max = 1, + Decimals = 2, + Default = 1, + }, + } + + function ACF.ManualGearboxMenu(Class, Data, Menu) + local Text = "Mass : %s\nDefault Gear : Gear %s\nTorque Rating : %s n/m - %s fl-lb" + local Mass = ACF.GetProperMass(Data.Mass) + local Gears = Class.Gears + local Torque = math.floor(Data.MaxTorque * 0.73) + + Menu:AddLabel(Text:format(Mass, Gears.Default or Gears.Min, Data.MaxTorque, Torque)) + + if Data.DualClutch then + Menu:AddLabel("The dual clutch allows you to apply power and brake each side independently.") + end + + Menu:AddTitle("Gear Settings") + + Values[Class.ID] = Values[Class.ID] or {} + + local ValuesData = Values[Class.ID] + + for I = math.max(1, Gears.Min), Gears.Max do + local Variable = "Gear" .. I + local Control = Menu:AddSlider("Gear " .. I, -1, 1, 2) + Control:SetDataVar(Variable, "OnValueChanged") + Control:SetValueFunction(function(Panel) + local Value = math.Round(ACF.ReadNumber("Gear" .. I), 2) + + if ValuesData["Gear" .. I] then + ValuesData["Gear" .. I] = Value + end + + Panel:SetValue(Value) + + return Value + end) + + local Default = ValuesData[Variable] + + if not Default then + Default = math.Clamp(I * 0.1, -1, 1) + + ValuesData[Variable] = Default + end + + ACF.WriteValue(Variable, Default) + end + + local FinalDrive = Menu:AddSlider("Final Drive", -1, 1, 2) + FinalDrive:SetDataVar("FinalDrive", "OnValueChanged") + FinalDrive:SetValueFunction(function(Panel) + local Value = math.Round(ACF.ReadNumber("FinalDrive"), 2) + + if ValuesData.FinalDrive then + ValuesData.FinalDrive = Value + end + + Panel:SetValue(Value) + + return Value + end) + + if not ValuesData.FinalDrive then + ValuesData.FinalDrive = 1 + end + + ACF.WriteValue("FinalDrive", ValuesData.FinalDrive) + end + + function ACF.CVTGearboxMenu(Class, Data, Menu) + local Text = "Mass : %s\nDefault Gear : Gear %s\nTorque Rating : %s n/m - %s fl-lb" + local Mass = ACF.GetProperMass(Data.Mass) + local Gears = Class.Gears + local Torque = math.floor(Data.MaxTorque * 0.73) + + Menu:AddLabel(Text:format(Mass, Gears.Default or Gears.Min, Data.MaxTorque, Torque)) + + if Data.DualClutch then + Menu:AddLabel("The dual clutch allows you to apply power and brake each side independently.") + end + + Values[Class.ID] = Values[Class.ID] or {} + + local ValuesData = Values[Class.ID] + + ACF.WriteValue("Gear1", 0.01) + + for _, GearData in ipairs(CVTData) do + local Control = Menu:AddSlider(GearData.Name, GearData.Min, GearData.Max, GearData.Decimals) + Control:SetDataVar(GearData.Variable, "OnValueChanged") + Control:SetValueFunction(function(Panel) + local Variable = GearData.Variable + local Value = math.Round(ACF.ReadNumber(Variable), GearData.Decimals) + + if ValuesData[Variable] then + ValuesData[Variable] = Value + end + + Panel:SetValue(Value) + + return Value + end) + + local Default = ValuesData[GearData.Variable] + + if not Default then + Default = GearData.Default + + ValuesData[GearData.Variable] = Default + end + + ACF.WriteValue(Variable, Default) + end + end + + --function ACF.AutomaticGearboxMenu(Class, Data, Menu) + + --end +end diff --git a/lua/acf/shared/gearboxes/3-auto.lua b/lua/acf/shared/gearboxes/3-auto.lua index d67181701..9eaf51010 100644 --- a/lua/acf/shared/gearboxes/3-auto.lua +++ b/lua/acf/shared/gearboxes/3-auto.lua @@ -19,11 +19,12 @@ local ShiftM = 0.35 local ShiftL = 0.5 ACF.RegisterGearboxClass("3-Auto", { - Name = "3-Speed Automatic", + Name = "3-Speed Automatic", + CreateMenu = ACF.AutomaticGearboxMenu, Gears = { Min = 0, Max = 3, - } + }, }) do -- Inline Gearboxes diff --git a/lua/acf/shared/gearboxes/4-speed.lua b/lua/acf/shared/gearboxes/4-speed.lua index 4f9c0a123..2fee5cf4a 100644 --- a/lua/acf/shared/gearboxes/4-speed.lua +++ b/lua/acf/shared/gearboxes/4-speed.lua @@ -314,10 +314,10 @@ ACF_DefineGearbox( "4Gear-ST-L", { } } ) --- The dual clutch allows you to apply power and brake each side independently ACF.RegisterGearboxClass("4-Speed", { - Name = "4-Speed Gearbox", + Name = "4-Speed Gearbox", + CreateMenu = ACF.ManualGearboxMenu, Gears = { Min = 0, Max = 4, diff --git a/lua/acf/shared/gearboxes/5-auto.lua b/lua/acf/shared/gearboxes/5-auto.lua index c8d91a759..c0755a1ca 100644 --- a/lua/acf/shared/gearboxes/5-auto.lua +++ b/lua/acf/shared/gearboxes/5-auto.lua @@ -19,7 +19,8 @@ local ShiftM = 0.35 local ShiftL = 0.5 ACF.RegisterGearboxClass("5-Auto", { - Name = "5-Speed Automatic", + Name = "5-Speed Automatic", + CreateMenu = ACF.AutomaticGearboxMenu, Gears = { Min = 0, Max = 5, diff --git a/lua/acf/shared/gearboxes/6-speed.lua b/lua/acf/shared/gearboxes/6-speed.lua index e52004b80..5fbcf201d 100644 --- a/lua/acf/shared/gearboxes/6-speed.lua +++ b/lua/acf/shared/gearboxes/6-speed.lua @@ -345,7 +345,8 @@ ACF_DefineGearbox( "6Gear-ST-L", { } ) ACF.RegisterGearboxClass("6-Speed", { - Name = "6-Speed Gearbox", + Name = "6-Speed Gearbox", + CreateMenu = ACF.ManualGearboxMenu, Gears = { Min = 0, Max = 6, diff --git a/lua/acf/shared/gearboxes/7-auto.lua b/lua/acf/shared/gearboxes/7-auto.lua index 085bc3960..9f0c3b785 100644 --- a/lua/acf/shared/gearboxes/7-auto.lua +++ b/lua/acf/shared/gearboxes/7-auto.lua @@ -19,7 +19,8 @@ local ShiftM = 0.35 local ShiftL = 0.5 ACF.RegisterGearboxClass("7-Auto", { - Name = "7-Speed Automatic", + Name = "7-Speed Automatic", + CreateMenu = ACF.AutomaticGearboxMenu, Gears = { Min = 0, Max = 7, diff --git a/lua/acf/shared/gearboxes/8-speed.lua b/lua/acf/shared/gearboxes/8-speed.lua index d9eb230eb..ae8af62f2 100644 --- a/lua/acf/shared/gearboxes/8-speed.lua +++ b/lua/acf/shared/gearboxes/8-speed.lua @@ -375,7 +375,8 @@ ACF_DefineGearbox( "8Gear-ST-L", { } ) ACF.RegisterGearboxClass("8-Speed", { - Name = "8-Speed Gearbox", + Name = "8-Speed Gearbox", + CreateMenu = ACF.ManualGearboxMenu, Gears = { Min = 0, Max = 8, diff --git a/lua/acf/shared/gearboxes/clutch.lua b/lua/acf/shared/gearboxes/clutch.lua index 8bf4fca36..642388edc 100644 --- a/lua/acf/shared/gearboxes/clutch.lua +++ b/lua/acf/shared/gearboxes/clutch.lua @@ -87,7 +87,8 @@ ACF_DefineGearbox( "Clutch-S-L", { } ) ACF.RegisterGearboxClass("Clutch", { - Name = "Clutch", + Name = "Clutch", + CreateMenu = ACF.ManualGearboxMenu, Gears = { Min = 1, Max = 1, diff --git a/lua/acf/shared/gearboxes/cvt.lua b/lua/acf/shared/gearboxes/cvt.lua index 5134f23d0..2fb195cc7 100644 --- a/lua/acf/shared/gearboxes/cvt.lua +++ b/lua/acf/shared/gearboxes/cvt.lua @@ -324,10 +324,12 @@ ACF_DefineGearbox("CVT-ST-L", { }) ACF.RegisterGearboxClass("CVT", { - Name = "CVT", + Name = "CVT", + CreateMenu = ACF.CVTGearboxMenu, Gears = { - Min = 0, - Max = 2, + Min = 0, + Max = 2, + Default = 1, } }) diff --git a/lua/acf/shared/gearboxes/differential.lua b/lua/acf/shared/gearboxes/differential.lua index 4148f9b08..36c4b7412 100644 --- a/lua/acf/shared/gearboxes/differential.lua +++ b/lua/acf/shared/gearboxes/differential.lua @@ -224,7 +224,8 @@ ACF_DefineGearbox( "1Gear-TD-L", { } ) ACF.RegisterGearboxClass("Differential", { - Name = "Differential", + Name = "Differential", + CreateMenu = ACF.ManualGearboxMenu, Gears = { Min = 1, Max = 1, diff --git a/lua/acf/shared/gearboxes/doublediff.lua b/lua/acf/shared/gearboxes/doublediff.lua index e26e3ca7a..64fbed8d0 100644 --- a/lua/acf/shared/gearboxes/doublediff.lua +++ b/lua/acf/shared/gearboxes/doublediff.lua @@ -69,7 +69,8 @@ ACF_DefineGearbox("DoubleDiff-T-L", { }) ACF.RegisterGearboxClass("DoubleDiff", { - Name = "Regenerative Steering", + Name = "Regenerative Steering", + CreateMenu = ACF.ManualGearboxMenu, Gears = { Min = 1, Max = 1, diff --git a/lua/acf/shared/gearboxes/transfer.lua b/lua/acf/shared/gearboxes/transfer.lua index a7d7c0bca..2ffff9163 100644 --- a/lua/acf/shared/gearboxes/transfer.lua +++ b/lua/acf/shared/gearboxes/transfer.lua @@ -124,7 +124,8 @@ ACF_DefineGearbox( "2Gear-T-L", { } ) ACF.RegisterGearboxClass("Transfer", { - Name = "Transfer Case", + Name = "Transfer Case", + CreateMenu = ACF.ManualGearboxMenu, Gears = { Min = 1, Max = 2, From dbab7cd3cd813215398e6994871cb0a9cf7815af Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Thu, 26 Mar 2020 20:34:03 -0300 Subject: [PATCH 049/279] Fixed manual and CVT menu class data storage - Manual and CVT gearbox menus will now properly store and retrieve each slider value they had. --- lua/acf/client/menu_items/gearboxes_menu.lua | 64 ++++++++++---------- 1 file changed, 31 insertions(+), 33 deletions(-) diff --git a/lua/acf/client/menu_items/gearboxes_menu.lua b/lua/acf/client/menu_items/gearboxes_menu.lua index b48597f49..bf6edaf27 100644 --- a/lua/acf/client/menu_items/gearboxes_menu.lua +++ b/lua/acf/client/menu_items/gearboxes_menu.lua @@ -137,31 +137,37 @@ do -- Default Menus for I = math.max(1, Gears.Min), Gears.Max do local Variable = "Gear" .. I + local Default = ValuesData[Variable] + + if not Default then + Default = math.Clamp(I * 0.1, -1, 1) + + ValuesData[Variable] = Default + end + + ACF.WriteValue(Variable, Default) + local Control = Menu:AddSlider("Gear " .. I, -1, 1, 2) Control:SetDataVar(Variable, "OnValueChanged") Control:SetValueFunction(function(Panel) - local Value = math.Round(ACF.ReadNumber("Gear" .. I), 2) + local Value = math.Round(ACF.ReadNumber(Variable), 2) - if ValuesData["Gear" .. I] then - ValuesData["Gear" .. I] = Value + if ValuesData[Variable] then + ValuesData[Variable] = Value end Panel:SetValue(Value) return Value end) + end - local Default = ValuesData[Variable] - - if not Default then - Default = math.Clamp(I * 0.1, -1, 1) - - ValuesData[Variable] = Default - end - - ACF.WriteValue(Variable, Default) + if not ValuesData.FinalDrive then + ValuesData.FinalDrive = 1 end + ACF.WriteValue("FinalDrive", ValuesData.FinalDrive) + local FinalDrive = Menu:AddSlider("Final Drive", -1, 1, 2) FinalDrive:SetDataVar("FinalDrive", "OnValueChanged") FinalDrive:SetValueFunction(function(Panel) @@ -175,12 +181,6 @@ do -- Default Menus return Value end) - - if not ValuesData.FinalDrive then - ValuesData.FinalDrive = 1 - end - - ACF.WriteValue("FinalDrive", ValuesData.FinalDrive) end function ACF.CVTGearboxMenu(Class, Data, Menu) @@ -202,30 +202,28 @@ do -- Default Menus ACF.WriteValue("Gear1", 0.01) for _, GearData in ipairs(CVTData) do + local Variable = GearData.Variable + local Default = ValuesData[Variable] + + if not Default then + Default = GearData.Default + + ValuesData[Variable] = Default + end + + ACF.WriteValue(Variable, Default) + local Control = Menu:AddSlider(GearData.Name, GearData.Min, GearData.Max, GearData.Decimals) - Control:SetDataVar(GearData.Variable, "OnValueChanged") + Control:SetDataVar(Variable, "OnValueChanged") Control:SetValueFunction(function(Panel) - local Variable = GearData.Variable local Value = math.Round(ACF.ReadNumber(Variable), GearData.Decimals) - if ValuesData[Variable] then - ValuesData[Variable] = Value - end + ValuesData[Variable] = Value Panel:SetValue(Value) return Value end) - - local Default = ValuesData[GearData.Variable] - - if not Default then - Default = GearData.Default - - ValuesData[GearData.Variable] = Default - end - - ACF.WriteValue(Variable, Default) end end From e07219a97bbedbf07fc9d4684adfd25999e7ed6d Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Thu, 26 Mar 2020 20:39:03 -0300 Subject: [PATCH 050/279] Removed reduntant conditions --- lua/acf/client/menu_items/gearboxes_menu.lua | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/lua/acf/client/menu_items/gearboxes_menu.lua b/lua/acf/client/menu_items/gearboxes_menu.lua index bf6edaf27..16011d757 100644 --- a/lua/acf/client/menu_items/gearboxes_menu.lua +++ b/lua/acf/client/menu_items/gearboxes_menu.lua @@ -152,9 +152,7 @@ do -- Default Menus Control:SetValueFunction(function(Panel) local Value = math.Round(ACF.ReadNumber(Variable), 2) - if ValuesData[Variable] then - ValuesData[Variable] = Value - end + ValuesData[Variable] = Value Panel:SetValue(Value) @@ -173,9 +171,7 @@ do -- Default Menus FinalDrive:SetValueFunction(function(Panel) local Value = math.Round(ACF.ReadNumber("FinalDrive"), 2) - if ValuesData.FinalDrive then - ValuesData.FinalDrive = Value - end + ValuesData.FinalDrive = Value Panel:SetValue(Value) From ae707d74ac11a41e7755aa5762bcf20f9a858961 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sun, 29 Mar 2020 02:25:43 -0300 Subject: [PATCH 051/279] Added PANEL:AddNumberWang to ACF Panel - Added PANEL:AddNumberWang function to the ACF Panel. Creates a number wang on the right with a label on the left side. - Fixed a really specific error that only seems to happen with DNumberWang panels. --- lua/acf/base/util/cl_util.lua | 2 ++ lua/vgui/acf_panel.lua | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/lua/acf/base/util/cl_util.lua b/lua/acf/base/util/cl_util.lua index 513ffaab1..78f7f49ff 100644 --- a/lua/acf/base/util/cl_util.lua +++ b/lua/acf/base/util/cl_util.lua @@ -308,6 +308,8 @@ do -- Tool data functions -- First we'll process the panels that set the value of this key if SetterPanels then for Panel in pairs(SetterPanels) do + if not Panel.OldSetFunc then continue end + local NewValue = Value if Panel.ValueFunction then diff --git a/lua/vgui/acf_panel.lua b/lua/vgui/acf_panel.lua index 7ef810098..8b8b33b9d 100644 --- a/lua/vgui/acf_panel.lua +++ b/lua/vgui/acf_panel.lua @@ -156,6 +156,24 @@ function PANEL:AddSlider(Title, Min, Max, Decimals) return Panel end +function PANEL:AddNumberWang(Label, Min, Max, Decimals) + local Base = self:AddPanel("ACF_Panel") + + local Wang = Base:Add("DNumberWang") + Wang:SetDecimals(Decimals or 0) + Wang:SetMinMax(Min, Max) + Wang:SetTall(20) + Wang:Dock(RIGHT) + + local Text = Base:Add("DLabel") + Text:SetText(Label or "Text") + Text:SetFont("ACF_Control") + Text:SetDark(true) + Text:Dock(TOP) + + return Wang, Text +end + function PANEL:PerformLayout() self:SizeToChildren(true, true) end From 5a4a2a0cbc4d96dda8aa7cd0686e7f94a043bc8f Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sun, 29 Mar 2020 02:28:12 -0300 Subject: [PATCH 052/279] Added gearbox menus - Added ACF.ManualGearboxMenu function to create a generic menu for manual gearboxes. - Added ACF.CVTGearboxMenu function to create a generic menu for CVT gearboxes. - Added ACF.AutomaticGearboxMenu function to create a generic menu for automatic gearboxes. - Removed default gear value from CVT gearbox class definition. --- lua/acf/client/menu_items/gearboxes_menu.lua | 435 ++++++++++++++----- lua/acf/shared/gearboxes/cvt.lua | 1 - 2 files changed, 331 insertions(+), 105 deletions(-) diff --git a/lua/acf/client/menu_items/gearboxes_menu.lua b/lua/acf/client/menu_items/gearboxes_menu.lua index 16011d757..4f1ad50e1 100644 --- a/lua/acf/client/menu_items/gearboxes_menu.lua +++ b/lua/acf/client/menu_items/gearboxes_menu.lua @@ -82,148 +82,375 @@ ACF.AddOptionItem("Entities", "Gearboxes", "cog", CreateMenu) do -- Default Menus local Values = {} - local CVTData = { - { - Name = "Gear 2", - Variable = "Gear2", - Min = -1, - Max = 1, - Decimals = 2, - Default = -0.1, - }, - { - Name = "Min Target RPM", - Variable = "MinRPM", - Min = 1, - Max = 10000, - Decimals = 0, - Default = 3000, - }, - { - Name = "Max Target RPM", - Variable = "MaxRPM", - Min = 1, - Max = 10000, - Decimals = 0, - Default = 5000, - }, - { - Name = "Final Drive", - Variable = "FinalDrive", - Min = -1, - Max = 1, - Decimals = 2, - Default = 1, - }, - } - - function ACF.ManualGearboxMenu(Class, Data, Menu) - local Text = "Mass : %s\nDefault Gear : Gear %s\nTorque Rating : %s n/m - %s fl-lb" - local Mass = ACF.GetProperMass(Data.Mass) - local Gears = Class.Gears - local Torque = math.floor(Data.MaxTorque * 0.73) - - Menu:AddLabel(Text:format(Mass, Gears.Default or Gears.Min, Data.MaxTorque, Torque)) - - if Data.DualClutch then - Menu:AddLabel("The dual clutch allows you to apply power and brake each side independently.") - end - Menu:AddTitle("Gear Settings") + do -- Manual Gearbox Menu + function ACF.ManualGearboxMenu(Class, Data, Menu) + local Text = "Mass : %s\nTorque Rating : %s n/m - %s fl-lb" + local Mass = ACF.GetProperMass(Data.Mass) + local Gears = Class.Gears + local Torque = math.floor(Data.MaxTorque * 0.73) + + Menu:AddLabel(Text:format(Mass, Data.MaxTorque, Torque)) + + if Data.DualClutch then + Menu:AddLabel("The dual clutch allows you to apply power and brake each side independently.") + end + + ----------------------------------- + + Menu:AddTitle("Gear Settings") + + Values[Class.ID] = Values[Class.ID] or {} + + local ValuesData = Values[Class.ID] + + for I = math.max(1, Gears.Min), Gears.Max do + local Variable = "Gear" .. I + local Default = ValuesData[Variable] + + if not Default then + Default = math.Clamp(I * 0.1, -1, 1) - Values[Class.ID] = Values[Class.ID] or {} + ValuesData[Variable] = Default + end - local ValuesData = Values[Class.ID] + ACF.WriteValue(Variable, Default) - for I = math.max(1, Gears.Min), Gears.Max do - local Variable = "Gear" .. I - local Default = ValuesData[Variable] + local Control = Menu:AddSlider("Gear " .. I, -1, 1, 2) + Control:SetDataVar(Variable, "OnValueChanged") + Control:SetValueFunction(function(Panel) + local Value = math.Round(ACF.ReadNumber(Variable), 2) - if not Default then - Default = math.Clamp(I * 0.1, -1, 1) + ValuesData[Variable] = Value - ValuesData[Variable] = Default + Panel:SetValue(Value) + + return Value + end) + end + + if not ValuesData.FinalDrive then + ValuesData.FinalDrive = 1 end - ACF.WriteValue(Variable, Default) + ACF.WriteValue("FinalDrive", ValuesData.FinalDrive) - local Control = Menu:AddSlider("Gear " .. I, -1, 1, 2) - Control:SetDataVar(Variable, "OnValueChanged") - Control:SetValueFunction(function(Panel) - local Value = math.Round(ACF.ReadNumber(Variable), 2) + local FinalDrive = Menu:AddSlider("Final Drive", -1, 1, 2) + FinalDrive:SetDataVar("FinalDrive", "OnValueChanged") + FinalDrive:SetValueFunction(function(Panel) + local Value = math.Round(ACF.ReadNumber("FinalDrive"), 2) - ValuesData[Variable] = Value + ValuesData.FinalDrive = Value Panel:SetValue(Value) return Value end) end + end - if not ValuesData.FinalDrive then - ValuesData.FinalDrive = 1 - end + do -- CVT Gearbox Menu + local CVTData = { + { + Name = "Gear 2", + Variable = "Gear2", + Min = -1, + Max = 1, + Decimals = 2, + Default = -0.1, + }, + { + Name = "Min Target RPM", + Variable = "MinRPM", + Min = 1, + Max = 9900, + Decimals = 0, + Default = 3000, + }, + { + Name = "Max Target RPM", + Variable = "MaxRPM", + Min = 101, + Max = 10000, + Decimals = 0, + Default = 5000, + }, + { + Name = "Final Drive", + Variable = "FinalDrive", + Min = -1, + Max = 1, + Decimals = 2, + Default = 1, + }, + } + + function ACF.CVTGearboxMenu(Class, Data, Menu) + local Text = "Mass : %s\nTorque Rating : %s n/m - %s fl-lb" + local Mass = ACF.GetProperMass(Data.Mass) + local Torque = math.floor(Data.MaxTorque * 0.73) + + Menu:AddLabel(Text:format(Mass, Data.MaxTorque, Torque)) + + if Data.DualClutch then + Menu:AddLabel("The dual clutch allows you to apply power and brake each side independently.") + end - ACF.WriteValue("FinalDrive", ValuesData.FinalDrive) + ----------------------------------- - local FinalDrive = Menu:AddSlider("Final Drive", -1, 1, 2) - FinalDrive:SetDataVar("FinalDrive", "OnValueChanged") - FinalDrive:SetValueFunction(function(Panel) - local Value = math.Round(ACF.ReadNumber("FinalDrive"), 2) + Menu:AddTitle("Gear Settings") - ValuesData.FinalDrive = Value + Values[Class.ID] = Values[Class.ID] or {} - Panel:SetValue(Value) + local ValuesData = Values[Class.ID] - return Value - end) - end + ACF.WriteValue("Gear1", 0.01) + + for _, GearData in ipairs(CVTData) do + local Variable = GearData.Variable + local Default = ValuesData[Variable] + + if not Default then + Default = GearData.Default - function ACF.CVTGearboxMenu(Class, Data, Menu) - local Text = "Mass : %s\nDefault Gear : Gear %s\nTorque Rating : %s n/m - %s fl-lb" - local Mass = ACF.GetProperMass(Data.Mass) - local Gears = Class.Gears - local Torque = math.floor(Data.MaxTorque * 0.73) + ValuesData[Variable] = Default + end - Menu:AddLabel(Text:format(Mass, Gears.Default or Gears.Min, Data.MaxTorque, Torque)) + ACF.WriteValue(Variable, Default) - if Data.DualClutch then - Menu:AddLabel("The dual clutch allows you to apply power and brake each side independently.") + local Control = Menu:AddSlider(GearData.Name, GearData.Min, GearData.Max, GearData.Decimals) + Control:SetDataVar(Variable, "OnValueChanged") + Control:SetValueFunction(function(Panel) + local Value = math.Round(ACF.ReadNumber(Variable), GearData.Decimals) + + ValuesData[Variable] = Value + + Panel:SetValue(Value) + + return Value + end) + end end + end + + do -- Automatic Gearbox Menu + local UnitMult = 10.936 -- km/h is set by default + local AutoData = { + { + Name = "Reverse Gear", + Variable = "Reverse", + Min = -1, + Max = 1, + Decimals = 2, + Default = -0.1, + }, + { + Name = "Final Drive", + Variable = "FinalDrive", + Min = -1, + Max = 1, + Decimals = 2, + Default = 1, + }, + } + + local GenData = { + { + Name = "Upshift RPM", + Variable = "UpshiftRPM", + Tooltip = "Target engine RPM to upshift at.", + Min = 0, + Max = 10000, + Decimals = 0, + Default = 5000, + }, + { + Name = "Total Ratio", + Variable = "TotalRatio", + Tooltip = "Total ratio is the ratio of all gearboxes (exluding this one) multiplied together.\nFor example, if you use engine to automatic to diffs to wheels, your total ratio would be (diff gear ratio * diff final ratio).", + Min = 0, + Max = 1, + Decimals = 2, + Default = 0.1, + }, + { + Name = "Wheel Diameter", + Variable = "WheelDiameter", + Tooltip = "If you use default spherical settings, add 0.5 to your wheel diameter.\nFor treaded vehicles, use the diameter of road wheels, not drive wheels.", + Min = 0, + Max = 1000, + Decimals = 2, + Default = 30, + }, + } + + function ACF.AutomaticGearboxMenu(Class, Data, Menu) + local Text = "Mass : %s\nTorque Rating : %s n/m - %s fl-lb" + local Mass = ACF.GetProperMass(Data.Mass) + local Gears = Class.Gears + local Torque = math.floor(Data.MaxTorque * 0.73) + + Menu:AddLabel(Text:format(Mass, Data.MaxTorque, Torque)) + + if Data.DualClutch then + Menu:AddLabel("The dual clutch allows you to apply power and brake each side independently.") + end + + ----------------------------------- + + Menu:AddTitle("Gear Settings") + + Values[Class.ID] = Values[Class.ID] or {} - Values[Class.ID] = Values[Class.ID] or {} + local ValuesData = Values[Class.ID] - local ValuesData = Values[Class.ID] + Menu:AddLabel("Upshift Speed Unit :") - ACF.WriteValue("Gear1", 0.01) + local Unit = Menu:AddComboBox() + Unit:AddChoice("KPH", 10.936) + Unit:AddChoice("MPH", 17.6) + Unit:AddChoice("GMU", 1) - for _, GearData in ipairs(CVTData) do - local Variable = GearData.Variable - local Default = ValuesData[Variable] + function Unit:OnSelect(_, _, Mult) + if UnitMult == Mult then return end - if not Default then - Default = GearData.Default + local Delta = UnitMult / Mult - ValuesData[Variable] = Default + for I = math.max(1, Gears.Min), Gears.Max do + local Var = "Shift" .. I + local Old = ACF.ReadNumber(Var) + + ACF.WriteValue(Var, Old * Delta) + end + + UnitMult = Mult end - ACF.WriteValue(Variable, Default) + for I = math.max(1, Gears.Min), Gears.Max do + local GearVar = "Gear" .. I + local DefGear = ValuesData[GearVar] - local Control = Menu:AddSlider(GearData.Name, GearData.Min, GearData.Max, GearData.Decimals) - Control:SetDataVar(Variable, "OnValueChanged") - Control:SetValueFunction(function(Panel) - local Value = math.Round(ACF.ReadNumber(Variable), GearData.Decimals) + if not DefGear then + DefGear = math.Clamp(I * 0.1, -1, 1) - ValuesData[Variable] = Value + ValuesData[GearVar] = DefGear + end - Panel:SetValue(Value) + ACF.WriteValue(GearVar, DefGear) - return Value - end) - end - end + local Gear = Menu:AddSlider("Gear " .. I, -1, 1, 2) + Gear:SetDataVar(GearVar, "OnValueChanged") + Gear:SetValueFunction(function(Panel) + local Value = math.Round(ACF.ReadNumber(GearVar), 2) + + ValuesData[GearVar] = Value + + Panel:SetValue(Value) - --function ACF.AutomaticGearboxMenu(Class, Data, Menu) + return Value + end) - --end + local ShiftVar = "Shift" .. I + local DefShift = ValuesData[ShiftVar] + + if not DefShift then + DefShift = I * 10 + + ValuesData[ShiftVar] = DefShift + end + + ACF.WriteValue(ShiftVar, DefShift) + + local Shift = Menu:AddNumberWang("Gear " .. I .. " Upshift Speed", 0, 9999, 2) + Shift:HideWang() + Shift:SetDataVar(ShiftVar, "OnValueChanged") + Shift:SetValueFunction(function(Panel) + local Value = math.Round(ACF.ReadNumber(ShiftVar), 2) + + ValuesData[ShiftVar] = Value + + Panel:SetValue(Value) + + return Value + end) + end + + for _, GearData in ipairs(AutoData) do + local Variable = GearData.Variable + local Default = ValuesData[Variable] + + if not Default then + Default = GearData.Default + + ValuesData[Variable] = Default + end + + ACF.WriteValue(Variable, Default) + + local Control = Menu:AddSlider(GearData.Name, GearData.Min, GearData.Max, GearData.Decimals) + Control:SetDataVar(Variable, "OnValueChanged") + Control:SetValueFunction(function(Panel) + local Value = math.Round(ACF.ReadNumber(Variable), GearData.Decimals) + + ValuesData[Variable] = Value + + Panel:SetValue(Value) + + return Value + end) + end + + Unit:ChooseOptionID(1) + + ----------------------------------- + + Menu:AddTitle("Shift Point Generator") + + for _, PanelData in ipairs(GenData) do + local Variable = PanelData.Variable + local Default = ValuesData[Variable] + + if not Default then + Default = PanelData.Default + + ValuesData[Variable] = Default + end + + ACF.WriteValue(Variable, Default) + + local Panel = Menu:AddNumberWang(PanelData.Name, PanelData.Min, PanelData.Max, PanelData.Decimals) + Panel:HideWang() + Panel:SetDataVar(Variable, "OnValueChanged") + Panel:SetValueFunction(function() + local Value = math.Round(ACF.ReadNumber(Variable), PanelData.Decimals) + + ValuesData[Variable] = Value + + Panel:SetValue(Value) + + return Value + end) + + if PanelData.Tooltip then + Panel:SetTooltip(PanelData.Tooltip) + end + end + + local Button = Menu:AddButton("Calculate") + + function Button:DoClickInternal() + local UpshiftRPM = ValuesData.UpshiftRPM + local TotalRatio = ValuesData.TotalRatio + local FinalDrive = ValuesData.FinalDrive + local WheelDiameter = ValuesData.WheelDiameter + local Multiplier = math.pi * UpshiftRPM * TotalRatio * FinalDrive * WheelDiameter / (60 * UnitMult) + + for I = math.max(1, Gears.Min), Gears.Max do + local Gear = ValuesData["Gear" .. I] + + ACF.WriteValue("Shift" .. I, Gear * Multiplier) + end + end + end + end end diff --git a/lua/acf/shared/gearboxes/cvt.lua b/lua/acf/shared/gearboxes/cvt.lua index 2fb195cc7..4051cf546 100644 --- a/lua/acf/shared/gearboxes/cvt.lua +++ b/lua/acf/shared/gearboxes/cvt.lua @@ -329,7 +329,6 @@ ACF.RegisterGearboxClass("CVT", { Gears = { Min = 0, Max = 2, - Default = 1, } }) From 877c073ff636bb0db7384f6fb9bed007241e5a57 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Fri, 17 Apr 2020 02:58:33 -0400 Subject: [PATCH 053/279] Added entity class registration function - Added ACF.RegisterEntityClass function to reduce the amount of code done by duplicator.RegisterEntityClass. - Added ACF.GetEntityClass to retrieve the data table of a certain registered entity class. --- lua/acf/base/sh_classes.lua | 34 +++++++++++++++++++++++++++++ lua/acf/base/sh_round_functions.lua | 1 + 2 files changed, 35 insertions(+) diff --git a/lua/acf/base/sh_classes.lua b/lua/acf/base/sh_classes.lua index f8ae2d679..d9bea3ae5 100644 --- a/lua/acf/base/sh_classes.lua +++ b/lua/acf/base/sh_classes.lua @@ -329,3 +329,37 @@ do -- Sensor registration functions return AddGroupedClass(ID, ClassID, Sensors, Data) end end + +-- Serverside-only stuff +if CLIENT then return end + +do -- Entity class registration function + ACF.Classes.Entities = ACF.Classes.Entities or {} + + local Entities = ACF.Classes.Entities + + function ACF.RegisterEntityClass(Class, Function, Data) + if not isstring(Class) then return end + if not isfunction(Function) then return end + + local Entity = { + Spawn = Function, + } + + if istable(Data) then + for K, V in pairs(Data) do + Entity[K] = V + end + end + + Entities[Class] = Entity + + duplicator.RegisterEntityClass(Class, Function, "Pos", "Angle", "Data") + end + + function ACF.GetEntityClass(Class) + if not Class then return end + + return Entities[Class] + end +end diff --git a/lua/acf/base/sh_round_functions.lua b/lua/acf/base/sh_round_functions.lua index 22032d487..764bdb621 100644 --- a/lua/acf/base/sh_round_functions.lua +++ b/lua/acf/base/sh_round_functions.lua @@ -62,6 +62,7 @@ local Ignore = { FuelTypes = true, Gearboxes = true, Guidances = true, + Entities = true, Engines = true, Sensors = true, Crates = true, From 3f2517b845d899e4464e1045d5a39c8f144efbda Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Fri, 17 Apr 2020 03:30:13 -0400 Subject: [PATCH 054/279] Added tool functions - Added ACF.RegisterOperation to register custom tool stage and operations. - Added ACF.RegisterToolInfo to register tool information to be later displayed on the player's screen. - Added ACF.LoadToolFunctions to easily embbed ACF tool functions into the TOOL structure. - Added ACF.SetToolMode function to be able to manage tool stage/operations from the clientside. --- lua/acf/base/sh_tool_functions.lua | 344 +++++++++++++++++++++++++++++ 1 file changed, 344 insertions(+) create mode 100644 lua/acf/base/sh_tool_functions.lua diff --git a/lua/acf/base/sh_tool_functions.lua b/lua/acf/base/sh_tool_functions.lua new file mode 100644 index 000000000..8ac5b1791 --- /dev/null +++ b/lua/acf/base/sh_tool_functions.lua @@ -0,0 +1,344 @@ +ACF.Tools = ACF.Tools or {} + +local Tools = ACF.Tools + +local function GetToolData(Tool) + if not Tools[Tool] then + Tools[Tool] = { + Indexed = {}, + Stages = {}, + Count = 0, + } + + ACF.RegisterOperation(Tool, "Main", "Idle", {}) + ACF.RegisterToolInfo(Tool, "Main", "Idle", { + name = "info", + text = "Select an option on the menu." + }) + end + + return Tools[Tool] +end + +do -- Tool Stage/Operation Registration function + local function RegisterStage(Data, Name) + local Stage = Data.Stages[Name] + + if not Stage then + local Count = Data.Count + + Stage = { + Ops = {}, + Count = 0, + Name = Name, + Indexed = {}, + Index = Count, + } + + Data.Stages[Name] = Stage + Data.Indexed[Count] = Stage + + Data.Count = Count + 1 + end + + return Stage + end + + function ACF.RegisterOperation(Tool, StageName, OpName, ToolFuncs) + if not Tool then return end + if not OpName then return end + if not StageName then return end + if not istable(ToolFuncs) then return end + + local Data = GetToolData(Tool) + local Stage = RegisterStage(Data, StageName) + local Operation = Stage.Ops[OpName] + local Count = Stage.Count + + if not Operation then + Operation = {} + + Stage.Ops[OpName] = Operation + Stage.Indexed[Count] = Operation + Stage.Count = Count + 1 + end + + for K, V in pairs(ToolFuncs) do + Operation[K] = V + end + + Operation.Name = OpName + Operation.Index = Count + + return Operation + end +end + +do -- Tool Information Registration function + local function GetInformation(Tool) + local Data = Tools[Tool] + + if not Data.Information then + Data.Information = {} + Data.InfoLookup = {} + Data.InfoCount = 0 + end + + return Data.Information + end + + -- This function will add entries to the tool's Information table + -- For more reference about the values you can give it see: + -- https://wiki.facepunch.com/gmod/Tool_Information_Display + -- Note: name, stage and op will be assigned automatically + function ACF.RegisterToolInfo(Tool, Stage, Op, Info) + if SERVER then return end + if not Tool then return end + if not Stage then return end + if not Op then return end + if not istable(Info) then return end + if not Info.name then return end + if not Info.text then return end + + local Data = GetToolData(Tool) + local Stages = Data.Stages[Stage] + + if not Stages then return end + + local Ops = Stages.Ops[Op] + + if not Ops then return end + + local StageIdx, OpIdx = Stages.Index, Ops.Index + local Name = Info.name .. "_" .. StageIdx .. "_" .. OpIdx + local ToolInfo = GetInformation(Tool) + local New = Data.InfoLookup[Name] + + if not New then + local Count = Data.InfoCount + 1 + + New = {} + + Data.InfoLookup[Name] = New + Data.InfoCount = Count + + ToolInfo[Count] = New + end + + for K, V in pairs(Info) do + New[K] = K == "name" and Name or V + end + + New.stage = StageIdx + New.op = OpIdx + + return New + end +end + +do -- Tool Functions Loader + if SERVER then + util.AddNetworkString("ACF_ToolNetVars") + else + net.Receive("ACF_ToolNetVars", function() + local ToolName = net.ReadString() + local Name = net.ReadString() + local Value = net.ReadInt(8) + + local Data = Tools[ToolName] + local Tool = LocalPlayer():GetTool(ToolName) + + if not Data then return end + if not Tool then return end + + if Name == "Stage" then + Tool.Stage = Value + Tool.StageData = Data.Indexed[Value] + elseif Name == "Operation" then + Tool.Operation = Value + Tool.OpData = Tool.StageData.Indexed[Value] + Tool.DrawToolScreen = Tool.OpData.DrawToolScreen + end + end) + end + + local function UpdateNetvar(Tool, Name, Value) + net.Start("ACF_ToolNetVars") + net.WriteString(Tool.Mode) + net.WriteString(Name) + net.WriteInt(Value, 8) + net.Send(Tool:GetOwner()) + end + + function ACF.LoadToolFunctions(Tool) + if not Tool then return end + if not Tools[Tool.Mode] then return end + + local Mode = Tool.Mode + local Data = Tools[Mode] + Data.Tool = Tool + + function Tool:SetStage(Stage) + if CLIENT then return end + if not Stage then return end + if not Data.Indexed[Stage] then return end + + self.Stage = Stage + self.StageData = Data.Indexed[Stage] + + UpdateNetvar(self, "Stage", Stage) + + self:SetOperation(0) + end + + function Tool:GetStage() + return self.Stage + end + + function Tool:SetOperation(Op) + if CLIENT then return end + if not Op then return end + if not self.StageData.Indexed[Op] then return end + + self.Operation = Op + self.OpData = self.StageData.Indexed[Op] + + UpdateNetvar(self, "Operation", Op) + end + + function Tool:GetOperation() + return self.Operation + end + + if CLIENT then + if Data.Information then + Tool.Information = {} + + for K, V in ipairs(Data.Information) do + Tool.Information[K] = V + + language.Add("Tool." .. Mode .. "." .. V.name, V.text) + end + end + + function Tool:LeftClick(Trace) + return not Trace.HitSky + end + + function Tool:RightClick(Trace) + return not Trace.HitSky + end + + function Tool:Reload(Trace) + return not Trace.HitSky + end + else + function Tool:SetMode(StageName, OpName) + if not StageName then return end + if not OpName then return end + + local Stage = Data.Stages[StageName] + + if not Stage then return end + + local Op = Stage.Ops[OpName] + + if not Op then return end + + self:SetStage(Stage.Index) + self:SetOperation(Op.Index) + end + + function Tool:LeftClick(Trace) + local OnLeftClick = self.OpData.OnLeftClick + + if OnLeftClick then + return OnLeftClick(self, Trace) + end + + return false + end + + function Tool:RightClick(Trace) + local OnRightClick = self.OpData.OnRightClick + + if OnRightClick then + return OnRightClick(self, Trace) + end + + return false + end + + function Tool:Reload(Trace) + local OnReload = self.OpData.OnReload + + if OnReload then + return OnReload(self, Trace) + end + + return false + end + + function Tool:Deploy() + local OnDeploy = self.OpData.OnDeploy + + self:SetStage(self.LastStage) + self:SetOperation(self.LastOp) + + if OnDeploy then + OnDeploy(self) + end + end + + function Tool:Holster() + local OnHolster = self.OpData.OnHolster + + if OnHolster then + OnHolster(self) + end + + self.LastStage = self.Stage + self.LastOp = self.Operation + end + + function Tool:Think() + local OnThink = self.OpData.OnThink + + if OnThink then + OnThink(self) + end + end + end + end +end + +do -- Clientside Tool interaction + if SERVER then + util.AddNetworkString("ACF_ToolMode") + + net.Receive("ACF_ToolMode", function(_, Player) + local ToolName = net.ReadString() + local StageName = net.ReadString() + local OpName = net.ReadString() + local Tool = Player:GetTool(ToolName) + + if not Tool then return end + if not Tool.SetMode then return end + if Player:GetTool() ~= Tool then return end + + Tool:SetMode(StageName, OpName) + end) + else + function ACF.SetToolMode(Tool, Stage, Op) + if not isstring(Tool) then return end + if not isstring(Stage) then return end + if not isstring(Op) then return end + + net.Start("ACF_ToolMode") + net.WriteString(Tool) + net.WriteString(Stage) + net.WriteString(Op) + net.SendToServer() + end + end +end From edb03c952bea87d32110abc1063c1bc78fa539c4 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Fri, 17 Apr 2020 03:32:55 -0400 Subject: [PATCH 055/279] Updated new ACF Menu to use ACF tool functions - Loaded ACF tool functions into the new menu's TOOL structure. - Removed the methods that would override the ACF tool methods. --- lua/weapons/gmod_tool/stools/acf_menu2.lua | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/lua/weapons/gmod_tool/stools/acf_menu2.lua b/lua/weapons/gmod_tool/stools/acf_menu2.lua index a56876d18..104a068c9 100644 --- a/lua/weapons/gmod_tool/stools/acf_menu2.lua +++ b/lua/weapons/gmod_tool/stools/acf_menu2.lua @@ -1,6 +1,8 @@ TOOL.Name = "ACF Menu Test" TOOL.Category = "Construction" +ACF.LoadToolFunctions(TOOL) + cleanup.Register("acfmenu") if CLIENT then @@ -29,14 +31,6 @@ if CLIENT then cam.End3D() end - function TOOL:LeftClick(Trace) - return not Trace.HitSky - end - - function TOOL:RightClick(Trace) - return not Trace.HitSky - end - TOOL.BuildCPanel = ACF.BuildContextPanel concommand.Add("acf_reload_menu", function() @@ -44,12 +38,4 @@ if CLIENT then ACF.BuildContextPanel(ACF.Menu.Panel) end) -else - function TOOL:LeftClick(Trace) - return not Trace.HitSky - end - - function TOOL:RightClick(Trace) - return not Trace.HitSky - end end From 7356ae9073ef164b9672676d4359599e64e78959 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Fri, 17 Apr 2020 03:40:23 -0400 Subject: [PATCH 056/279] Added Spawner and Linker tool operations - Added Spawner operation, used on all entity related menus - Added Linker operation, used by the Spawner operation when an entity is marker for linking. - ACF Menu will try to default the operation to Idle. --- lua/acf/client/cl_menu.lua | 2 + lua/acf/client/menu_items/components_menu.lua | 2 + lua/acf/client/menu_items/engines_menu.lua | 2 + lua/acf/client/menu_items/gearboxes_menu.lua | 2 + lua/acf/client/menu_items/online_wiki.lua | 6 +- lua/acf/client/menu_items/sensors_menu.lua | 2 + lua/acf/client/menu_items/weapons_menu.lua | 2 + lua/acf/shared/tool_operations/acf_menu.lua | 243 ++++++++++++++++++ 8 files changed, 258 insertions(+), 3 deletions(-) create mode 100644 lua/acf/shared/tool_operations/acf_menu.lua diff --git a/lua/acf/client/cl_menu.lua b/lua/acf/client/cl_menu.lua index c9fff9e9e..71b77af92 100644 --- a/lua/acf/client/cl_menu.lua +++ b/lua/acf/client/cl_menu.lua @@ -172,6 +172,8 @@ do -- ACF Menu context panel Node.Parent.Selected = Node self.Selected = Node + ACF.SetToolMode("acf_menu2", "Main", "Idle") + Menu:ClearTemporal() Menu:StartTemporal() diff --git a/lua/acf/client/menu_items/components_menu.lua b/lua/acf/client/menu_items/components_menu.lua index 72a374724..f4f026475 100644 --- a/lua/acf/client/menu_items/components_menu.lua +++ b/lua/acf/client/menu_items/components_menu.lua @@ -33,6 +33,8 @@ local function CreateMenu(Menu) ACF.WriteValue("PrimaryClass", "N/A") ACF.WriteValue("SecondaryClass", "N/A") + ACF.SetToolMode("acf_menu2", "Main", "Spawner") + if not next(Components) then Menu:AddTitle("No Components Registered") Menu:AddLabel("No components have been registered. If this is incorrect, check your console for errors and contact the server owner.") diff --git a/lua/acf/client/menu_items/engines_menu.lua b/lua/acf/client/menu_items/engines_menu.lua index 66f6a14a9..f0dd55734 100644 --- a/lua/acf/client/menu_items/engines_menu.lua +++ b/lua/acf/client/menu_items/engines_menu.lua @@ -110,6 +110,8 @@ local function CreateMenu(Menu) ACF.WriteValue("PrimaryClass", "acf_engine") ACF.WriteValue("SecondaryClass", "acf_fueltank") + ACF.SetToolMode("acf_menu2", "Main", "Spawner") + function EngineClass:OnSelect(Index, _, Data) if self.Selected == Data then return end diff --git a/lua/acf/client/menu_items/gearboxes_menu.lua b/lua/acf/client/menu_items/gearboxes_menu.lua index 4f1ad50e1..ee7306a6f 100644 --- a/lua/acf/client/menu_items/gearboxes_menu.lua +++ b/lua/acf/client/menu_items/gearboxes_menu.lua @@ -38,6 +38,8 @@ local function CreateMenu(Menu) ACF.WriteValue("PrimaryClass", "acf_gearbox") ACF.WriteValue("SecondaryClass", "N/A") + ACF.SetToolMode("acf_menu2", "Main", "Spawner") + function GearboxClass:OnSelect(Index, _, Data) if self.Selected == Data then return end diff --git a/lua/acf/client/menu_items/online_wiki.lua b/lua/acf/client/menu_items/online_wiki.lua index b49749a12..b686c6935 100644 --- a/lua/acf/client/menu_items/online_wiki.lua +++ b/lua/acf/client/menu_items/online_wiki.lua @@ -1,7 +1,7 @@ local function CreateMenu(Menu) Menu:AddTitle("A Reference Guide") - Menu:AddLabel("From now on, the ACF wiki will have a greater focus on references about the addon's multiple mechanics.") - Menu:AddLabel("We'll also leave some content aimed for developers so they can take advatange of everything we leave at their disposal.") + Menu:AddLabel("The new ACF wiki will have a greater focus on references about the addon's multiple mechanics.") + Menu:AddLabel("There's also gonna be more content aimed towards extension developers, allowing them to take advantage of all the features ACF has to offer.") local Wiki = Menu:AddButton("Open the Wiki") @@ -9,7 +9,7 @@ local function CreateMenu(Menu) gui.OpenURL("https://github.com/Stooberton/ACF-3/wiki") end - Menu:AddLabel("Note: The wiki is still a work in progress, it'll get poblated as time passes.") + Menu:AddLabel("Note: The wiki is still a work in progress, it'll get populated as time passes.") end ACF.AddOptionItem("About the Addon", "Online Wiki", "book_open", CreateMenu) diff --git a/lua/acf/client/menu_items/sensors_menu.lua b/lua/acf/client/menu_items/sensors_menu.lua index a3647529a..779815793 100644 --- a/lua/acf/client/menu_items/sensors_menu.lua +++ b/lua/acf/client/menu_items/sensors_menu.lua @@ -33,6 +33,8 @@ local function CreateMenu(Menu) ACF.WriteValue("PrimaryClass", "N/A") ACF.WriteValue("SecondaryClass", "N/A") + ACF.SetToolMode("acf_menu2", "Main", "Spawner") + if not next(Sensors) then Menu:AddTitle("No Sensors Registered") Menu:AddLabel("No sensors have been registered. If this is incorrect, check your console for errors and contact the server owner.") diff --git a/lua/acf/client/menu_items/weapons_menu.lua b/lua/acf/client/menu_items/weapons_menu.lua index 8d0c05797..3307ff961 100644 --- a/lua/acf/client/menu_items/weapons_menu.lua +++ b/lua/acf/client/menu_items/weapons_menu.lua @@ -68,6 +68,8 @@ local function CreateMenu(Menu) ACF.WriteValue("PrimaryClass", "acf_gun") ACF.WriteValue("SecondaryClass", "acf_ammo") + ACF.SetToolMode("acf_menu2", "Main", "Spawner") + function ClassList:OnSelect(Index, _, Data) if self.Selected == Data then return end diff --git a/lua/acf/shared/tool_operations/acf_menu.lua b/lua/acf/shared/tool_operations/acf_menu.lua new file mode 100644 index 000000000..6e69b77d4 --- /dev/null +++ b/lua/acf/shared/tool_operations/acf_menu.lua @@ -0,0 +1,243 @@ +local GetToolData = ACF.GetToolData +local GetEntityClass = ACF.GetEntityClass +local SendMessage = ACF.SendMessage +local Entities = {} + +local function GetPlayerEnts(Player) + local Ents = Entities[Player] + + if not Ents then + Ents = {} + Entities[Player] = Ents + end + + return Ents +end + +local function UnselectEntity(Tool, Player, Entity) + local Ents = GetPlayerEnts(Player) + + Entity:RemoveCallOnRemove("ACF_ToolLinking") + Entity:SetColor(Ents[Entity]) + + Ents[Entity] = nil + + if not next(Ents) then + Tool:SetMode("Main", "Spawner") + end +end + +local function SelectEntity(Tool, Player, Entity) + local Ents = GetPlayerEnts(Player) + + if not next(Ents) then + Tool:SetMode("Main", "Linker") + end + + Ents[Entity] = Entity:GetColor() + Entity:SetColor(Color(0, 255, 0)) + Entity:CallOnRemove("ACF_ToolLinking", function() + UnselectEntity(Tool, Player, Entity) + end) +end + +local function CanTool(Player, Entity) + if not IsValid(Entity) then return false end + if not CPPI then return true end + + return Entity:CPPICanTool(Player, "#Tool.acf_menu2.name") +end + +do -- Spawner operation + local function CanUpdate(Player, Entity, ClassName) + if not CanTool(Player, Entity) then return false end + if Entity:GetClass() ~= ClassName then return false end + if not isfunction(Entity.Update) then return false end + + return true + end + + local function SpawnEntity(Player, ClassName, Trace, Data) + if not ClassName or ClassName == "N/A" then return false end + + local Entity = Trace.Entity + + if CanUpdate(Player, Entity, ClassName) then + Entity:Update(Data) + return true + end + + local Class = GetEntityClass(ClassName) + + if not Class then + SendMessage(Player, "Error", ClassName, " is not a registered ACF entity class.") + return false + end + + local Position = Trace.HitPos + Trace.HitNormal * 128 + local Angles = Trace.HitNormal:Angle():Up():Angle() + + Entity = Class.Spawn(Player, Position, Angles, Data) + + if not IsValid(Entity) then + SendMessage(Player, "Error", ClassName, " entity couldn't be created.") + return false + end + + Entity:Activate() + Entity:DropToFloor() + + if CPPI then + Entity:CPPISetOwner(Player) + end + + undo.Create(ClassName) + undo.AddEntity(Entity) + undo.SetPlayer(Player) + undo.Finish() + + local PhysObj = Entity:GetPhysicsObject() + + if IsValid(PhysObj) then + PhysObj:EnableMotion(false) + PhysObj:Sleep() + end + + return true + end + + ACF.RegisterOperation("acf_menu2", "Main", "Spawner", { + OnLeftClick = function(Tool, Trace) + if Trace.HitSky then return false end + + local Player = Tool:GetOwner() + local Data = GetToolData(Player) + local ClassName = Data.PrimaryClass + + return SpawnEntity(Player, ClassName, Trace, Data) + end, + OnRightClick = function(Tool, Trace) + local Player = Tool:GetOwner() + local Data = GetToolData(Player) + local ClassName = Data.SecondaryClass + + if SpawnEntity(Player, ClassName, Trace, Data) then + return true + end + + if not Player:KeyDown(IN_SPEED) then return false end + if not CanTool(Player, Trace.Entity) then return false end + + SelectEntity(Tool, Player, Trace.Entity) + + return true + end, + }) + + ACF.RegisterToolInfo("acf_menu2", "Main", "Spawner", { + name = "left", + text = "Spawn or update the selected primary entity.", + }) + + ACF.RegisterToolInfo("acf_menu2", "Main", "Spawner", { + name = "right", + text = "If valid, spawn or update the selected secondary entity.", + }) + + ACF.RegisterToolInfo("acf_menu2", "Main", "Spawner", { + name = "right_shift", + text = "(Hold Shift) Select the entity you want to link or unlink.", + icon2 = "gui/info", + }) +end + +do -- Linker operation + local function LinkEntities(Tool, Player, Entity, Ents) + local Total, Done = 0, 0 + local Unlink = Player:KeyDown(IN_RELOAD) + local Action = Unlink and Entity.Unlink or Entity.Link + + for K in pairs(Ents) do + local EntAction = Unlink and K.Unlink or K.Link + local Success = false + + if EntAction then + Success = EntAction(K, Entity) + elseif Action then + Success = Action(Entity, K) + end + + Total = Total + 1 + + if Success then + Done = Done + 1 + end + + UnselectEntity(Tool, Player, K) + end + + if Done > 0 then + SendMessage(Player, "Info", "Successfully linked ", Done, " out of ", Total, " entities to ", tostring(Entity), ".") + else + SendMessage(Player, "Error", "None of the ", Total, " entities could be linked to ", tostring(Entity), ".") + end + end + + ACF.RegisterOperation("acf_menu2", "Main", "Linker", { + OnRightClick = function(Tool, Trace) + local Player = Tool:GetOwner() + local Entity = Trace.Entity + + if Trace.HitWorld then Tool:Holster() return true end + if not CanTool(Player, Entity) then return false end + + local Ents = GetPlayerEnts(Player) + + if not Player:KeyDown(IN_SPEED) then + LinkEntities(Tool, Player, Entity, Ents) + return true + end + + if not Ents[Entity] then + SelectEntity(Tool, Player, Entity) + else + UnselectEntity(Tool, Player, Entity) + end + + return true + end, + OnHolster = function(Tool) + local Player = Tool:GetOwner() + local Ents = GetPlayerEnts(Player) + + if not next(Ents) then return end + + for Entity in pairs(Ents) do + UnselectEntity(Tool, Player, Entity) + end + end, + }) + + ACF.RegisterToolInfo("acf_menu2", "Main", "Linker", { + name = "right", + text = "Link all the selected entities to an entity.", + }) + + ACF.RegisterToolInfo("acf_menu2", "Main", "Linker", { + name = "right_r", + text = "Unlink all the selected entities from an entity.", + icon2 = "gui/r.png", + }) + + ACF.RegisterToolInfo("acf_menu2", "Main", "Linker", { + name = "right_shift", + text = "Select another entity to link.", + icon2 = "gui/info", + }) + + ACF.RegisterToolInfo("acf_menu2", "Main", "Linker", { + name = "right_world", + text = "(Hit the World) Unselected all selected entities.", + icon2 = "gui/info", + }) +end From 4a8bcdaa7bdaaac868b4f1ab0d2d64a343459828 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Fri, 17 Apr 2020 05:57:00 -0400 Subject: [PATCH 057/279] Replaced uses of ACF.FuelDensity, ACF.TorqueScale and ACF.Efficiency - Most cases where ACF.FuelDensity, ACF.TorqueScale or ACF.Efficiency were used got replaced with their respective fuel type or engine type classes. --- lua/acf/server/damage.lua | 4 ++-- lua/entities/acf_engine/init.lua | 13 +++++++++---- lua/entities/acf_fueltank/init.lua | 5 +++-- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/lua/acf/server/damage.lua b/lua/acf/server/damage.lua index 9be912b0e..fb8863800 100644 --- a/lua/acf/server/damage.lua +++ b/lua/acf/server/damage.lua @@ -220,7 +220,7 @@ do local HEWeight if ent:GetClass() == "acf_fueltank" then - HEWeight = (math.max(ent.Fuel, ent.Capacity * 0.0025) / ACF.FuelDensity[ent.FuelType]) * 0.1 + HEWeight = (math.max(ent.Fuel, ent.Capacity * 0.0025) / ent.FuelDensity) * 0.1 else local HE, Propel @@ -270,7 +270,7 @@ do if Occ.Hit and Occ.Entity:EntIndex() == Found.Entity:EntIndex() then local FoundHEWeight if Found:GetClass() == "acf_fueltank" then - FoundHEWeight = (math.max(Found.Fuel, Found.Capacity * 0.0025) / ACF.FuelDensity[Found.FuelType]) * 0.1 + FoundHEWeight = (math.max(Found.Fuel, Found.Capacity * 0.0025) / Found.FuelDensity) * 0.1 else local HE, Propel diff --git a/lua/entities/acf_engine/init.lua b/lua/entities/acf_engine/init.lua index 3cf2793e1..d246e2a04 100644 --- a/lua/entities/acf_engine/init.lua +++ b/lua/entities/acf_engine/init.lua @@ -100,6 +100,7 @@ end local CheckLegal = ACF_CheckLegal local ClassLink = ACF.GetClassLink local ClassUnlink = ACF.GetClassUnlink +local EngineTypes = ACF.Classes.EngineTypes local UnlinkSound = "physics/metal/metal_box_impact_bullet%s.wav" local Round = math.Round local max = math.max @@ -109,6 +110,9 @@ local TimerSimple = timer.Simple local TimerRemove = timer.Remove local function UpdateEngineData(Entity, Id, EngineData) + local Type = EngineData.enginetype or "GenericPetrol" + local EngineType = EngineTypes[Type] + Entity.Id = Id Entity.Name = EngineData.name Entity.ShortName = Id @@ -127,9 +131,10 @@ local function UpdateEngineData(Entity, Id, EngineData) Entity.FlywheelOverride = EngineData.flywheeloverride Entity.IsTrans = EngineData.istrans -- driveshaft outputs to the side Entity.FuelType = EngineData.fuel or "Petrol" - Entity.EngineType = EngineData.enginetype or "GenericPetrol" + Entity.EngineType = EngineType.Name + Entity.Efficiency = EngineType.Efficiency + Entity.TorqueScale = EngineType.TorqueScale Entity.RequiresFuel = EngineData.requiresfuel - Entity.TorqueScale = ACF.TorqueScale[Entity.EngineType] --calculate boosted peak kw if Entity.EngineType == "Turbine" or Entity.EngineType == "Electric" then @@ -142,9 +147,9 @@ local function UpdateEngineData(Entity, Id, EngineData) --calculate base fuel usage if Entity.EngineType == "Electric" then - Entity.FuelUse = ACF.ElecRate / (ACF.Efficiency[Entity.EngineType] * 60 * 60) --elecs use current power output, not max + Entity.FuelUse = ACF.ElecRate / (Entity.Efficiency * 60 * 60) --elecs use current power output, not max else - Entity.FuelUse = ACF.TorqueBoost * ACF.FuelRate * ACF.Efficiency[Entity.EngineType] * Entity.peakkw / (60 * 60) + Entity.FuelUse = ACF.TorqueBoost * ACF.FuelRate * Entity.Efficiency * Entity.peakkw / (60 * 60) end local PhysObj = Entity:GetPhysicsObject() diff --git a/lua/entities/acf_fueltank/init.lua b/lua/entities/acf_fueltank/init.lua index 477fddbcf..594ab9119 100644 --- a/lua/entities/acf_fueltank/init.lua +++ b/lua/entities/acf_fueltank/init.lua @@ -12,6 +12,7 @@ local ClassLink = ACF.GetClassLink local ClassUnlink = ACF.GetClassUnlink local TimerCreate = timer.Create local TimerExists = timer.Exists +local FuelTypes = ACF.Classes.FuelTypes local function UpdateFuelData(Entity, Id, Data1, Data2, FuelData) local Percentage = 1 --how full is the tank? @@ -32,7 +33,7 @@ local function UpdateFuelData(Entity, Id, Data1, Data2, FuelData) Entity.ShortName = Entity.Name Entity.EntType = Data2 Entity.Model = FuelData.model - Entity.FuelDensity = ACF.FuelDensity[Data2] + Entity.FuelDensity = FuelTypes[Data2].Density Entity.Volume = PhysObj:GetVolume() - (Area * Wall) -- total volume of tank (cu in), reduced by wall thickness Entity.Capacity = Entity.Volume * ACF.CuIToLiter * ACF.TankVolumeMul * 0.4774 --internal volume available for fuel in liters, with magic realism number Entity.EmptyMass = (Area * Wall) * 16.387 * (7.9 / 1000) -- total wall volume * cu in to cc * density of steel (kg/cc) @@ -216,7 +217,7 @@ function ENT:Detonate() self.Damaged = nil -- Prevent multiple explosions local Pos = self:LocalToWorld(self:OBBCenter() + VectorRand() * (self:OBBMaxs() - self:OBBMins()) / 2) - local ExplosiveMass = (math.max(ent.Fuel, ent.Capacity * 0.0025) / ACF.FuelDensity[ent.FuelType]) * 0.1 + local ExplosiveMass = (math.max(self.Fuel, self.Capacity * 0.0025) / self.FuelDensity) * 0.1 ACF_KillChildProps(self, Pos, ExplosiveMass) ACF_HE(Pos, ExplosiveMass, ExplosiveMass * 0.5, self.Inflictor, {self}, self) From e614b2b805df08b1a2fce4e4f6a4edae2160bcc7 Mon Sep 17 00:00:00 2001 From: Stoob Date: Fri, 17 Apr 2020 09:58:17 -0500 Subject: [PATCH 058/279] Fixed EngineType being set to EngineName --- lua/entities/acf_engine/init.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/entities/acf_engine/init.lua b/lua/entities/acf_engine/init.lua index d246e2a04..e423a012c 100644 --- a/lua/entities/acf_engine/init.lua +++ b/lua/entities/acf_engine/init.lua @@ -131,7 +131,7 @@ local function UpdateEngineData(Entity, Id, EngineData) Entity.FlywheelOverride = EngineData.flywheeloverride Entity.IsTrans = EngineData.istrans -- driveshaft outputs to the side Entity.FuelType = EngineData.fuel or "Petrol" - Entity.EngineType = EngineType.Name + Entity.EngineType = Type Entity.Efficiency = EngineType.Efficiency Entity.TorqueScale = EngineType.TorqueScale Entity.RequiresFuel = EngineData.requiresfuel From aae7a534abea82cfe625b7035f1822ef794221eb Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sat, 18 Apr 2020 22:37:48 -0400 Subject: [PATCH 059/279] Fixed temporal panels inside ACF_Panel - Fixed panels not being correctly assigned to temporal sections if these were created after said sections were closed. - Added a pseudo CallOnRemove for panels created by an ACF_Panel. --- lua/vgui/acf_panel.lua | 71 ++++++++++++++++++++++++++++++++---------- 1 file changed, 55 insertions(+), 16 deletions(-) diff --git a/lua/vgui/acf_panel.lua b/lua/vgui/acf_panel.lua index 8b8b33b9d..4ee5c1a7c 100644 --- a/lua/vgui/acf_panel.lua +++ b/lua/vgui/acf_panel.lua @@ -2,18 +2,45 @@ local PANEL = {} DEFINE_BASECLASS("Panel") +-- Panels don't have a CallOnRemove function +-- This roughly replicates the same behavior +local function AddOnRemove(Panel, Parent) + local OldRemove = Panel.Remove + + function Panel:Remove() + Parent:EndTemporal(self) + Parent:ClearTemporal(self) + + Parent.Items[self] = nil + + for TempParent in pairs(self.TempParents) do + TempParent.TempItems[self] = nil + end + + if self == Parent.LastItem then + Parent.LastItem = self.PrevItem + end + + if IsValid(self.PrevItem) then + self.PrevItem.NextItem = self.NextItem + end + + if IsValid(self.NextItem) then + self.NextItem.PrevItem = self.PrevItem + end + + OldRemove(self) + end +end + function PANEL:Init() self.Items = {} self.TempItems = {} end function PANEL:ClearAll() - for K in pairs(self.Items) do - if IsValid(K) then - K:Remove() - end - - self.Items[K] = nil + for Item in pairs(self.Items) do + Item:Remove() end self:Clear() @@ -25,11 +52,7 @@ function PANEL:ClearTemporal(Panel) if not Target.TempItems then return end for K in pairs(Target.TempItems) do - if IsValid(K) then - K:Remove() - end - - Target.TempItems[K] = nil + K:Remove() end end @@ -53,8 +76,6 @@ end function PANEL:ClearAllTemporal() for Panel in pairs(TemporalPanels) do - if not IsValid(Panel) then continue end - self:EndTemporal(Panel) self:ClearTemporal(Panel) end @@ -69,17 +90,35 @@ function PANEL:AddPanel(Name) Panel:Dock(TOP) Panel:DockMargin(0, 0, 0, 10) + Panel:InvalidateParent() Panel:InvalidateLayout() + Panel.TempParents = {} self:InvalidateLayout() self.Items[Panel] = true - if next(TemporalPanels) then - for K in pairs(TemporalPanels) do - K.TempItems[Panel] = true + local LastItem = self.LastItem + + if IsValid(LastItem) then + LastItem.NextItem = Panel + + Panel.PrevItem = LastItem + + for Temp in pairs(LastItem.TempParents) do + Panel.TempParents[Temp] = true + Temp.TempItems[Panel] = true end end + self.LastItem = Panel + + for Temp in pairs(TemporalPanels) do + Panel.TempParents[Temp] = true + Temp.TempItems[Panel] = true + end + + AddOnRemove(Panel, self) + return Panel end From 8f0629690c0889480422c84a78c54b7a840867d7 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sun, 19 Apr 2020 00:30:16 -0400 Subject: [PATCH 060/279] Fixed linking - Fixed linking being ignored if the entity had the same class as the selected secondary class. - Fixed link result messages missing numbers. --- lua/acf/shared/tool_operations/acf_menu.lua | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/lua/acf/shared/tool_operations/acf_menu.lua b/lua/acf/shared/tool_operations/acf_menu.lua index 6e69b77d4..0be2a2f3c 100644 --- a/lua/acf/shared/tool_operations/acf_menu.lua +++ b/lua/acf/shared/tool_operations/acf_menu.lua @@ -67,6 +67,9 @@ do -- Spawner operation return true end + -- Couldn't update the entity, aborting spawn + if IsValid(Entity) then return false end + local Class = GetEntityClass(ClassName) if not Class then @@ -121,11 +124,10 @@ do -- Spawner operation local Data = GetToolData(Player) local ClassName = Data.SecondaryClass - if SpawnEntity(Player, ClassName, Trace, Data) then + if not Player:KeyDown(IN_SPEED) and SpawnEntity(Player, ClassName, Trace, Data) then return true end - if not Player:KeyDown(IN_SPEED) then return false end if not CanTool(Player, Trace.Entity) then return false end SelectEntity(Tool, Player, Trace.Entity) @@ -177,9 +179,13 @@ do -- Linker operation end if Done > 0 then - SendMessage(Player, "Info", "Successfully linked ", Done, " out of ", Total, " entities to ", tostring(Entity), ".") + local Status = (Unlink and "unlinked " or "linked ") .. Done .. " out of " .. Total + + SendMessage(Player, "Info", "Successfully ", Status, " entities to ", tostring(Entity), ".") else - SendMessage(Player, "Error", "None of the ", Total, " entities could be linked to ", tostring(Entity), ".") + local Status = Total .. " entities could be " .. (Unlink and "unlinked" or "linked") + + SendMessage(Player, "Error", "None of the ", Status, " to ", tostring(Entity), ".") end end From fad01e76469a74e889f83a434a66cf24361e828f Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Mon, 20 Apr 2020 03:13:54 -0400 Subject: [PATCH 061/279] Added limit convar creation to weapon registration - Extension creators will be able to define their custom limit convars directly from the weapon's class defintion function. - Added some missing language strings. --- lua/acf/base/acf_globals.lua | 2 -- lua/acf/base/sh_classes.lua | 13 +++++++++++++ lua/acf/shared/guns/smokelauncher.lua | 4 ++++ lua/entities/acf_gun/cl_init.lua | 4 ++++ lua/weapons/gmod_tool/stools/acfmenu.lua | 2 -- 5 files changed, 21 insertions(+), 4 deletions(-) diff --git a/lua/acf/base/acf_globals.lua b/lua/acf/base/acf_globals.lua index c5ee87f7d..0b33c6f59 100644 --- a/lua/acf/base/acf_globals.lua +++ b/lua/acf/base/acf_globals.lua @@ -95,8 +95,6 @@ do -- ACF global vars end do -- ACF Convars/Callbacks ------------------------ - CreateConVar("sbox_max_acf_gun", 16) - CreateConVar("sbox_max_acf_smokelauncher", 10) CreateConVar("sbox_max_acf_ammo", 32) CreateConVar("sbox_max_acf_misc", 32) CreateConVar("acf_meshvalue", 1) diff --git a/lua/acf/base/sh_classes.lua b/lua/acf/base/sh_classes.lua index d9bea3ae5..54d28e02e 100644 --- a/lua/acf/base/sh_classes.lua +++ b/lua/acf/base/sh_classes.lua @@ -165,6 +165,19 @@ do -- Weapon registration functions function ACF.RegisterWeaponClass(ID, Data) local Group = AddClassGroup(ID, Weapons, Data) + if not Group.LimitConVar then + Group.LimitConVar = { + Name = "_acf_gun", + Amount = 16, + } + end + + local Limit = Group.LimitConVar + + if not ConVarExists("sbox_max" .. Limit.Name) then + CreateConVar("sbox_max" .. Limit.Name, Limit.Amount, FCVAR_ARCHIVE) + end + if Group.MuzzleFlash then PrecacheParticleSystem(Group.MuzzleFlash) end diff --git a/lua/acf/shared/guns/smokelauncher.lua b/lua/acf/shared/guns/smokelauncher.lua index fc52f8df3..5e5173a2e 100644 --- a/lua/acf/shared/guns/smokelauncher.lua +++ b/lua/acf/shared/guns/smokelauncher.lua @@ -58,6 +58,10 @@ ACF.RegisterWeaponClass("SL", { ROFMod = 45, Spread = 0.32, Sound = "weapons/acf_gun/smoke_launch.mp3", + LimitConVar = { + Name = "_acf_smokelauncher", + Amount = 10, + }, Caliber = { Min = 40, Max = 81, diff --git a/lua/entities/acf_gun/cl_init.lua b/lua/entities/acf_gun/cl_init.lua index c37a93f43..f458ba407 100644 --- a/lua/entities/acf_gun/cl_init.lua +++ b/lua/entities/acf_gun/cl_init.lua @@ -2,6 +2,10 @@ include("shared.lua") local ACF_GunInfoWhileSeated = CreateClientConVar("ACF_GunInfoWhileSeated", 0, true, false) +language.Add("Undone_acf_gun", "Undone ACF Weapon") +language.Add("SBoxLimit__acf_gun", "You've reached the ACF Weapons limit!") +language.Add("SBoxLimit__acf_smokelauncher", "You've reached the ACF Smoke Launcher limit!") + function ENT:Initialize() self.LastFire = 0 self.Reload = 0 diff --git a/lua/weapons/gmod_tool/stools/acfmenu.lua b/lua/weapons/gmod_tool/stools/acfmenu.lua index 5e4fc8062..078bc904a 100644 --- a/lua/weapons/gmod_tool/stools/acfmenu.lua +++ b/lua/weapons/gmod_tool/stools/acfmenu.lua @@ -33,8 +33,6 @@ if CLIENT then language.Add( "Undone_acf_engine", "Undone ACF Engine" ) language.Add( "Undone_acf_gearbox", "Undone ACF Gearbox" ) language.Add( "Undone_acf_ammo", "Undone ACF Ammo" ) - language.Add( "Undone_acf_gun", "Undone ACF Gun" ) - language.Add( "SBoxLimit_acf_gun", "You've reached the ACF Guns limit!" ) language.Add( "SBoxLimit_acf_rack", "You've reached the ACF Launchers limit!" ) language.Add( "SBoxLimit_acf_ammo", "You've reached the ACF Explosives limit!" ) language.Add( "SBoxLimit_acf_sensor", "You've reached the ACF Sensors limit!" ) From 2acab5a4bbd76adc9355ed2ef605ad5b22ec1050 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Mon, 20 Apr 2020 03:15:37 -0400 Subject: [PATCH 062/279] Added ACF.GetClassGroup - Added ACF.GetClassGroup helper function to easily retrieve the class group data using a class name. --- lua/acf/base/sh_classes.lua | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/lua/acf/base/sh_classes.lua b/lua/acf/base/sh_classes.lua index 54d28e02e..cacb82f02 100644 --- a/lua/acf/base/sh_classes.lua +++ b/lua/acf/base/sh_classes.lua @@ -46,6 +46,20 @@ do -- Basic class registration functions return Group end + local Groups = {} + + local function GetDestinyData(Destiny) + local Data = Groups[Destiny] + + if not Data then + Data = {} + + Groups[Destiny] = Data + end + + return Data + end + function ACF.AddGroupedClass(ID, GroupID, Destiny, Data) if not ID then return end if not Data then return end @@ -66,6 +80,9 @@ do -- Basic class registration functions Group.Count = Group.Count + 1 Group.Lookup[ID] = Class Group.Items[Group.Count] = Class + + local DestinyData = GetDestinyData(Destiny) + DestinyData[ID] = Group end for K, V in pairs(Data) do @@ -74,6 +91,15 @@ do -- Basic class registration functions return Class end + + function ACF.GetClassGroup(Destiny, Class) + if not Destiny then return end + if not Class then return end + + local Data = Groups[Destiny] + + return Data and Data[Class] + end end local AddSimpleClass = ACF.AddSimpleClass From e1eca4bbaf2a40f3683feb33064971a0e2e08482 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Mon, 20 Apr 2020 03:17:42 -0400 Subject: [PATCH 063/279] Improved Entity Class registration functions - ACF.RegisterEntityClass will now use varargs to allow extension creators to define which variables from the entity will be used on spawn. - Added ACF.AddEntClassVars function to simplify the process of adding more variables to an already registered class without rewriting the whole thing. --- lua/acf/base/sh_classes.lua | 45 ++++++++++++++++++++++++++++++------- 1 file changed, 37 insertions(+), 8 deletions(-) diff --git a/lua/acf/base/sh_classes.lua b/lua/acf/base/sh_classes.lua index cacb82f02..ea8df8cc9 100644 --- a/lua/acf/base/sh_classes.lua +++ b/lua/acf/base/sh_classes.lua @@ -376,24 +376,53 @@ do -- Entity class registration function ACF.Classes.Entities = ACF.Classes.Entities or {} local Entities = ACF.Classes.Entities + local VarLookup = {} + local VarList = {} - function ACF.RegisterEntityClass(Class, Function, Data) + function ACF.RegisterEntityClass(Class, Function, ...) if not isstring(Class) then return end if not isfunction(Function) then return end - local Entity = { + Entities[Class] = { Spawn = Function, } - if istable(Data) then - for K, V in pairs(Data) do - Entity[K] = V - end + local Vars = istable(...) and ... or { ... } + local Lookup, List = {}, {} + local Count = 0 + + for _, V in pairs(Vars) do + Count = Count + 1 + + Lookup[V] = true + List[Count] = V end - Entities[Class] = Entity + VarLookup[Class] = Lookup + VarList[Class] = List + + duplicator.RegisterEntityClass(Class, Function, "Pos", "Angle", "Data", unpack(List)) + end + + function ACF.AddEntClassVars(Class, ...) + if not isstring(Class) then return end + if not Entities[Class] then return end + + local Vars = istable(...) and ... or { ... } + local Lookup = VarLookup[Class] + local List = VarList[Class] + local Count = #List + + for _, V in pairs(Vars) do + if not Lookup[V] then + Count = Count + 1 + + Lookup[V] = true + List[Count] = V + end + end - duplicator.RegisterEntityClass(Class, Function, "Pos", "Angle", "Data") + duplicator.RegisterEntityClass(Class, Function, "Pos", "Angle", "Data", unpack(List)) end function ACF.GetEntityClass(Class) From a806f96dc5c7e129a095e2b2c37314cf4b9cb539 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Mon, 20 Apr 2020 03:20:46 -0400 Subject: [PATCH 064/279] Adapted acf_gun to work with the new menu tool - The new menu tool will now be capable of spawning ACF weapons. The old menu will throw errors whenever this is attempted. - ACF Weapons can now be fully updated. - Input Fuze won't be created anymore if the caliber is lower than the minimum defined by ACF.MinFuzeCaliber --- lua/effects/acf_muzzle_flash.lua | 14 +- lua/entities/acf_gun/cl_init.lua | 20 ++- lua/entities/acf_gun/init.lua | 252 ++++++++++++++++++++----------- 3 files changed, 191 insertions(+), 95 deletions(-) diff --git a/lua/effects/acf_muzzle_flash.lua b/lua/effects/acf_muzzle_flash.lua index a2608283d..67057f19d 100644 --- a/lua/effects/acf_muzzle_flash.lua +++ b/lua/effects/acf_muzzle_flash.lua @@ -1,3 +1,5 @@ +local Weapons = ACF.Classes.Weapons + function EFFECT:Init(Data) local Gun = Data:GetEntity() @@ -7,16 +9,16 @@ function EFFECT:Init(Data) local ReloadTime = Data:GetMagnitude() local Sound = Gun:GetNWString("Sound") local Class = Gun:GetNWString("Class") - local ClassData = ACF.Classes.GunClass[Class] + local ClassData = Weapons[Class] local Attachment = "muzzle" - local LongBarrel = ClassData.longbarrel + local LongBarrel = ClassData.LongBarrel - if LongBarrel and Gun:GetBodygroup(LongBarrel.index) == LongBarrel.submodel then - Attachment = LongBarrel.newpos + if LongBarrel and Gun:GetBodygroup(LongBarrel.Index) == LongBarrel.Submodel then + Attachment = LongBarrel.NewPos end if not IsValidSound(Sound) then - Sound = ClassData.sound + Sound = ClassData.Sound end if Propellant > 0 then @@ -36,7 +38,7 @@ function EFFECT:Init(Data) end end - local Effect = ClassData.muzzleflash + local Effect = ClassData.MuzzleFlash local AttachID = Gun:LookupAttachment(Attachment) if AttachID > 0 then diff --git a/lua/entities/acf_gun/cl_init.lua b/lua/entities/acf_gun/cl_init.lua index f458ba407..7599f69eb 100644 --- a/lua/entities/acf_gun/cl_init.lua +++ b/lua/entities/acf_gun/cl_init.lua @@ -14,11 +14,16 @@ function ENT:Initialize() self.RateScale = 0 self.FireAnim = self:LookupSequence("shoot") self.CloseAnim = self:LookupSequence("load") - self.HitBoxes = ACF.HitBoxes[self:GetModel()] + + self:UpdateHitboxes() self.BaseClass.Initialize(self) end +function ENT:UpdateHitboxes() + self.HitBoxes = ACF.HitBoxes[self:GetModel()] +end + -- copied from base_wire_entity: DoNormalDraw's notip arg isn't accessible from ENT:Draw defined there. function ENT:Draw() local Player = LocalPlayer() @@ -100,4 +105,15 @@ function ACFGunGUICreate(Table) end acfmenupanel.CustomDisplay:PerformLayout() -end \ No newline at end of file +end + +net.Receive("ACF_UpdateHitboxes", function() + local Entity = net.ReadEntity() + + timer.Simple(0.1, function() + if not IsValid(Entity) then return end + if not Entity.UpdateHitboxes then return end + + Entity:UpdateHitboxes() + end) +end) diff --git a/lua/entities/acf_gun/init.lua b/lua/entities/acf_gun/init.lua index ac5f49d80..654137110 100644 --- a/lua/entities/acf_gun/init.lua +++ b/lua/entities/acf_gun/init.lua @@ -11,131 +11,210 @@ local CheckLegal = ACF_CheckLegal local ClassLink = ACF.GetClassLink local ClassUnlink = ACF.GetClassUnlink local Shove = ACF.KEShove +local Weapons = ACF.Classes.Weapons local TraceRes = {} -- Output for traces local TraceData = {start = true, endpos = true, filter = true, mask = MASK_SOLID, output = TraceRes} local Trace = util.TraceLine local TimerExists = timer.Exists local TimerCreate = timer.Create local HookRun = hook.Run -local EMPTY = { Type = "Empty", PropMass = 0, ProjMass = 0, Tracer = 0 } +local EMPTY = { Type = "Empty", PropMass = 0, ProjMass = 0, Tracer = 0 } +do -- Spawn and Update functions -------------------------------- + local function VerifyData(Data) + -- Entity was created via menu tool + if Data.Weapon then + Data.Id = Data.Weapon + end + + local Class = ACF.GetClassGroup(Weapons, Data.Id) + + if not Class then + Data.Id = "50mmC" + end + end -do -- Spawn Func -------------------------------- - function MakeACF_Gun(Player, Pos, Angle, Id) - local List = ACF.Weapons - local EID = List.Guns[Id] and Id or "50mmC" - local Lookup = List.Guns[EID] - local Ext = Lookup.gunclass == "SL" and "_acf_smokelauncher" or "_acf_gun" - local ClassData = ACF.Classes.GunClass[Lookup.gunclass] - local Caliber = Lookup.caliber + local function UpdateWeapon(Entity, Class, Weapon) + local Caliber = Weapon.Caliber * 0.1 - if not Player:CheckLimit(Ext) then return false end -- Check gun spawn limits + Entity:SetModel(Weapon.Model) + + Entity:PhysicsInit(SOLID_VPHYSICS) + Entity:SetMoveType(MOVETYPE_VPHYSICS) + + if Caliber > ACF.MinFuzeCaliber then + Entity.Inputs = WireLib.CreateInputs(Entity, { "Fire", "Unload", "Reload", "Fuze" }) + else + Entity.Inputs = WireLib.CreateInputs(Entity, { "Fire", "Unload", "Reload" }) + end + + Entity.Id = Weapon.ID -- MUST be stored on ent to be duped + Entity.Name = Weapon.Name + Entity.ShortName = Entity.Id + Entity.EntType = Class.Name + Entity.Caliber = Caliber + Entity.Class = Weapon.ClassID + Entity.MagReload = Weapon.MagReload + Entity.MagSize = Weapon.MagSize or 1 + Entity.Cyclic = Weapon.Cyclic and 60 / Weapon.Cyclic + Entity.ReloadTime = Entity.Cyclic or 1 + Entity.Spread = Class.Spread + Entity.MinLengthBonus = 0.75 * 3.1416 * (Caliber * 0.5) ^ 2 * Weapon.Round.MaxLength + Entity.PGRoFmod = math.max(0.01, Weapon.ROFMod or 1) + Entity.RoFmod = Class.ROFMod + Entity.HitBoxes = ACF.HitBoxes[Weapon.Model] + Entity.Long = Class.LongBarrel + Entity.NormalMuzzle = Entity:WorldToLocal(Entity:GetAttachment(Entity:LookupAttachment("muzzle")).Pos) + Entity.Muzzle = Entity.NormalMuzzle + + -- Set NWvars + Entity:SetNWString("WireName", Weapon.Name) + Entity:SetNWString("Class", Entity.Class) + Entity:SetNWString("ID", Entity.Id) + + -- Adjustable barrel length + if Entity.Long then + local Attachment = Entity:GetAttachment(Entity:LookupAttachment(Entity.Long.NewPos)) + + Entity.LongMuzzle = Attachment and Entity:WorldToLocal(Attachment.Pos) + end + + if Entity.Cyclic then -- Automatics don't change their rate of fire + WireLib.TriggerOutput(Entity, "Reload Time", Entity.Cyclic) + WireLib.TriggerOutput(Entity, "Rate of Fire", 60 / Entity.Cyclic) + end + + ACF_Activate(Entity, true) + + Entity.ACF.LegalMass = Weapon.Mass + Entity.ACF.Model = Weapon.Model + + local Phys = Entity:GetPhysicsObject() + if IsValid(Phys) then Phys:SetMass(Weapon.Mass) end + + Entity:UpdateOverlay(true) + + CheckLegal(Entity) + end + + function MakeACF_Weapon(Player, Pos, Angle, Data) + VerifyData(Data) + + local Class = ACF.GetClassGroup(Weapons, Data.Id) + local Weapon = Class.Lookup[Data.Id] + local Limit = Class.LimitConVar.Name + + if not Player:CheckLimit(Limit) then return false end -- Check gun spawn limits local Gun = ents.Create("acf_gun") if not IsValid(Gun) then return end Player:AddCleanup("acfmenu", Gun) - Player:AddCount(Ext, Gun) + Player:AddCount(Limit, Gun) - Gun:SetModel(Lookup.model) Gun:SetPlayer(Player) Gun:SetAngles(Angle) Gun:SetPos(Pos) Gun:Spawn() - Gun:PhysicsInit(SOLID_VPHYSICS) - Gun:SetMoveType(MOVETYPE_VPHYSICS) - - Gun.Id = Id -- MUST be stored on ent to be duped - Gun.Owner = Player -- MUST be stored on ent for PP - Gun.Outputs = WireLib.CreateOutputs(Gun, { "Status [STRING]", "Entity [ENTITY]", "Shots Left", "Rate of Fire", "Reload Time", "Projectile Mass", "Muzzle Velocity" }) - - if Caliber > ACF.MinFuzeCaliber then - Gun.Inputs = WireLib.CreateInputs(Gun, { "Fire", "Unload", "Reload", "Fuze" } ) - else - Gun.Inputs = WireLib.CreateInputs(Gun, {"Fire", "Unload", "Reload", "Fuze"}) - end - - -- ACF Specific vars - Gun.BarrelFilter = { Gun } - Gun.State = "Empty" - Gun.Crates = {} - Gun.Name = Lookup.name - Gun.ShortName = Id - Gun.EntType = ClassData.name - Gun.Caliber = Caliber - Gun.Class = Lookup.gunclass - Gun.MagReload = Lookup.magreload - Gun.MagSize = Lookup.magsize or 1 - Gun.Cyclic = Lookup.Cyclic and 60 / Lookup.Cyclic or nil - Gun.ReloadTime = Gun.Cyclic or 1 + Gun.Owner = Player -- MUST be stored on ent for PP + Gun.Outputs = WireLib.CreateOutputs(Gun, { "Status [STRING]", "Entity [ENTITY]", "Shots Left", "Rate of Fire", "Reload Time", "Projectile Mass", "Muzzle Velocity" }) + Gun.Sound = Class.Sound + Gun.BarrelFilter = { Gun } + Gun.State = "Empty" + Gun.Crates = {} Gun.CurrentShot = 0 - Gun.Spread = ClassData.spread - Gun.MinLengthBonus = 0.75 * 3.1416 * (Caliber / 2) ^ 2 * Lookup.round.maxlength - Gun.Muzzleflash = ClassData.muzzleflash - Gun.PGRoFmod = math.max(0.01, Lookup.rofmod or 1) - Gun.RoFmod = ClassData.rofmod - Gun.Sound = ClassData.sound Gun.BulletData = { Type = "Empty", PropMass = 0, ProjMass = 0, Tracer = 0 } - Gun.HitBoxes = ACF.HitBoxes[Lookup.model] - Gun.Long = ClassData.longbarrel - Gun.NormalMuzzle = Gun:WorldToLocal(Gun:GetAttachment(Gun:LookupAttachment("muzzle")).Pos) - Gun.Muzzle = Gun.NormalMuzzle - -- Set NWvars Gun:SetNWString("Sound", Gun.Sound) - Gun:SetNWString("WireName", Lookup.name) - Gun:SetNWString("ID", Id) - Gun:SetNWString("Class", Gun.Class) - -- Adjustable barrel length - if Gun.Long then - local Attachment = Gun:GetAttachment(Gun:LookupAttachment(Gun.Long.newpos)) + WireLib.TriggerOutput(Gun, "Status", "Empty") + WireLib.TriggerOutput(Gun, "Entity", Gun) + WireLib.TriggerOutput(Gun, "Projectile Mass", 1000) + WireLib.TriggerOutput(Gun, "Muzzle Velocity", 1000) - Gun.LongMuzzle = Attachment and Gun:WorldToLocal(Attachment.Pos) + UpdateWeapon(Gun, Class, Weapon, true) - timer.Simple(0, function() - if not IsValid(Gun) then return end - if not Attachment then return end + if Class.OnSpawn then + Class.OnSpawn(Gun, Class, Weapon) + end - local Long = Gun.Long + return Gun + end - if Gun:GetBodygroup(Long.index) == Long.submodel then - Gun.Muzzle = Gun.LongMuzzle - end - end) + ACF.RegisterEntityClass("acf_gun", MakeACF_Weapon, "Id") + ACF.RegisterLinkSource("acf_gun", "Crates") + + ------------------- Updating --------------------- + + util.AddNetworkString("ACF_UpdateHitboxes") + + local function SavePhysObj(Entity) + local PhysObj = Entity:GetPhysicsObject() + + return { + Gravity = PhysObj:IsGravityEnabled(), + Motion = PhysObj:IsMotionEnabled(), + } + end + + local function RestorePhysObj(Entity, PhysData) + local PhysObj = Entity:GetPhysicsObject() + + PhysObj:EnableGravity(PhysData.Gravity) + PhysObj:EnableMotion(PhysData.Motion) + end + + local function RestoreConstraints(List) + local Constraints = duplicator.ConstraintType + + for _, Data in ipairs(List) do + local Constraint = Constraints[Data.Type] + local Args = {} + + for Index, Name in ipairs(Constraint.Args) do + Args[Index] = Data[Name] + end + + Constraint.Func(unpack(Args)) end + end - WireLib.TriggerOutput(Gun, "Status", "Empty") - WireLib.TriggerOutput(Gun, "Entity", Gun) - WireLib.TriggerOutput(Gun, "Projectile Mass", 1000) - WireLib.TriggerOutput(Gun, "Muzzle Velocity", 1000) + function ENT:Update(Data) + VerifyData(Data) + + if self.Id == Data.Id then return end + + local Class = ACF.GetClassGroup(Weapons, Data.Id) + local Weapon = Class.Lookup[Data.Id] - if Gun.Cyclic then -- Automatics don't change their rate of fire - WireLib.TriggerOutput(Gun, "Reload Time", Gun.Cyclic) - WireLib.TriggerOutput(Gun, "Rate of Fire", 60 / Gun.Cyclic) + if self.State ~= "Empty" then + self:Unload() end - local Mass = Lookup.weight - local Phys = Gun:GetPhysicsObject() - if IsValid(Phys) then Phys:SetMass(Mass) end + local Constraints = constraint.GetTable(self) + local PhysData = SavePhysObj(self) - ACF_Activate(Gun) + UpdateWeapon(self, Class, Weapon) - Gun.ACF.LegalMass = Mass - Gun.ACF.Model = Lookup.model + if Class.OnUpdate then + Class.OnUpdate(self, Class, Weapon) + end - Gun:UpdateOverlay(true) + RestorePhysObj(self, PhysData) + RestoreConstraints(Constraints) - CheckLegal(Gun) + if next(self.Crates) then + for Crate in pairs(self.Crates) do + self:Unlink(Crate) + end + end - return Gun + net.Start("ACF_UpdateHitboxes") + net.WriteEntity(self) + net.Send(self.Owner) end - - list.Set("ACFCvars", "acf_gun", {"id"} ) - duplicator.RegisterEntityClass("acf_gun", MakeACF_Gun, "Pos", "Angle", "Id") - ACF.RegisterLinkSource("acf_gun", "Crates") end --------------------------------------------- do -- Metamethods -------------------------------- @@ -165,8 +244,7 @@ do -- Metamethods -------------------------------- return true, "Weapon unlinked successfully." end - - if not Weapon.Crates[Target] then return false, "This weapon is not linked to this crate." end + return false, "This weapon is not linked to this crate." end) local WireTable = { @@ -636,7 +714,7 @@ do -- Metamethods -------------------------------- if not IsValid(self) then return end local Long = self.Long - local IsLong = self:GetBodygroup(Long.index) == Long.submodel + local IsLong = self:GetBodygroup(Long.Index) == Long.Submodel self.Muzzle = IsLong and self.LongMuzzle or self.NormalMuzzle end) From 3faded546dca3a3d5f5831c81851095324136dee Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Wed, 22 Apr 2020 05:19:14 -0400 Subject: [PATCH 065/279] Improved dupe data storage method - Added serverside ACF.GetEntClassVars function to retrieve the argument list of a certain entity class. - ACF Entities will now store their class' argument list, required every time they're either spawned or updated. --- lua/acf/base/sh_classes.lua | 13 +++++++++++++ lua/entities/acf_gun/init.lua | 13 +++++++++---- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/lua/acf/base/sh_classes.lua b/lua/acf/base/sh_classes.lua index ea8df8cc9..1a412127d 100644 --- a/lua/acf/base/sh_classes.lua +++ b/lua/acf/base/sh_classes.lua @@ -430,4 +430,17 @@ do -- Entity class registration function return Entities[Class] end + + function ACF.GetEntClassVars(Class) + if not Class then return end + if not VarList[Class] then return end + + local List = {} + + for K, V in ipairs(VarList[Class]) do + List[K] = V + end + + return List + end end diff --git a/lua/entities/acf_gun/init.lua b/lua/entities/acf_gun/init.lua index 654137110..08c06906f 100644 --- a/lua/entities/acf_gun/init.lua +++ b/lua/entities/acf_gun/init.lua @@ -34,7 +34,7 @@ do -- Spawn and Update functions -------------------------------- end end - local function UpdateWeapon(Entity, Class, Weapon) + local function UpdateWeapon(Entity, Data, Class, Weapon) local Caliber = Weapon.Caliber * 0.1 Entity:SetModel(Weapon.Model) @@ -48,7 +48,11 @@ do -- Spawn and Update functions -------------------------------- Entity.Inputs = WireLib.CreateInputs(Entity, { "Fire", "Unload", "Reload" }) end - Entity.Id = Weapon.ID -- MUST be stored on ent to be duped + -- Storing all the relevant information on the entity for duping + for _, V in ipairs(Entity.DataStore) do + Entity[V] = Data[V] + end + Entity.Name = Weapon.Name Entity.ShortName = Entity.Id Entity.EntType = Class.Name @@ -126,6 +130,7 @@ do -- Spawn and Update functions -------------------------------- Gun.Crates = {} Gun.CurrentShot = 0 Gun.BulletData = { Type = "Empty", PropMass = 0, ProjMass = 0, Tracer = 0 } + Gun.DataStore = ACF.GetEntClassVars("acf_gun") Gun:SetNWString("Sound", Gun.Sound) @@ -134,7 +139,7 @@ do -- Spawn and Update functions -------------------------------- WireLib.TriggerOutput(Gun, "Projectile Mass", 1000) WireLib.TriggerOutput(Gun, "Muzzle Velocity", 1000) - UpdateWeapon(Gun, Class, Weapon, true) + UpdateWeapon(Gun, Data, Class, Weapon) if Class.OnSpawn then Class.OnSpawn(Gun, Class, Weapon) @@ -196,7 +201,7 @@ do -- Spawn and Update functions -------------------------------- local Constraints = constraint.GetTable(self) local PhysData = SavePhysObj(self) - UpdateWeapon(self, Class, Weapon) + UpdateWeapon(self, Data, Class, Weapon) if Class.OnUpdate then Class.OnUpdate(self, Class, Weapon) From 4ba2b1071be5a4510ee2833254398c3ec23d9993 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Wed, 22 Apr 2020 18:09:22 -0400 Subject: [PATCH 066/279] Fixed typos on engine definitions - Fixed a typo on the Small Electric Standalone Motor definition (iselec instead of IsElectric). - Fixed a typo on the 250cc Single Cylinder definition (model instead of Model). --- lua/acf/shared/engines/electric.lua | 2 +- lua/acf/shared/engines/single.lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lua/acf/shared/engines/electric.lua b/lua/acf/shared/engines/electric.lua index 63cafe4e6..91df876ab 100644 --- a/lua/acf/shared/engines/electric.lua +++ b/lua/acf/shared/engines/electric.lua @@ -221,7 +221,7 @@ do -- Electric Standalone Motors Mass = 125, Torque = 384, FlywheelMass = 0.3, - iselec = true, + IsElectric = true, RequiresFuel = true, RPM = { Idle = 10, diff --git a/lua/acf/shared/engines/single.lua b/lua/acf/shared/engines/single.lua index a171a0bc4..4634d1ff6 100644 --- a/lua/acf/shared/engines/single.lua +++ b/lua/acf/shared/engines/single.lua @@ -60,7 +60,7 @@ do ACF.RegisterEngine("0.25-I1", "I1", { Name = "250cc Single Cylinder", Description = "Tiny bike engine.", - model = "models/engines/1cylsml.mdl", + Model = "models/engines/1cylsml.mdl", Sound = "acf_engines/i1_small.wav", Fuel = { Petrol = true }, Type = "GenericPetrol", From bbf4489c6d79fadbcd4f3cec9f940f99e79c18f7 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Wed, 22 Apr 2020 18:10:44 -0400 Subject: [PATCH 067/279] Added chat feedback to entity updating - Updating an entity with the new menu tool will now provide chat feedback. --- lua/acf/shared/tool_operations/acf_menu.lua | 4 +++- lua/entities/acf_ammo/init.lua | 1 - lua/entities/acf_gun/init.lua | 15 +++++++++------ 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/lua/acf/shared/tool_operations/acf_menu.lua b/lua/acf/shared/tool_operations/acf_menu.lua index 0be2a2f3c..a44c1bb62 100644 --- a/lua/acf/shared/tool_operations/acf_menu.lua +++ b/lua/acf/shared/tool_operations/acf_menu.lua @@ -63,7 +63,9 @@ do -- Spawner operation local Entity = Trace.Entity if CanUpdate(Player, Entity, ClassName) then - Entity:Update(Data) + local Result, Message = Entity:Update(Data) + + SendMessage(Player, Result and "Info" or "Error", Message) return true end diff --git a/lua/entities/acf_ammo/init.lua b/lua/entities/acf_ammo/init.lua index 92a32938d..f43c72b31 100644 --- a/lua/entities/acf_ammo/init.lua +++ b/lua/entities/acf_ammo/init.lua @@ -535,7 +535,6 @@ do -- Metamethods ------------------------------- end function ENT:Detonate() - debug.Trace() timer.Remove("ACF Crate Cookoff " .. self:EntIndex()) -- Prevent multiple explosions self.Damaged = nil -- Prevent multiple explosions diff --git a/lua/entities/acf_gun/init.lua b/lua/entities/acf_gun/init.lua index 08c06906f..b92e453fa 100644 --- a/lua/entities/acf_gun/init.lua +++ b/lua/entities/acf_gun/init.lua @@ -142,7 +142,7 @@ do -- Spawn and Update functions -------------------------------- UpdateWeapon(Gun, Data, Class, Weapon) if Class.OnSpawn then - Class.OnSpawn(Gun, Class, Weapon) + Class.OnSpawn(Gun, Data, Class, Weapon) end return Gun @@ -187,24 +187,25 @@ do -- Spawn and Update functions -------------------------------- end function ENT:Update(Data) + if self.Firing then return false, "Stop firing before updating the weapon!" end + VerifyData(Data) - if self.Id == Data.Id then return end + if self.Id == Data.Id then return false, "This weapon is already the one you want it to update to!" end local Class = ACF.GetClassGroup(Weapons, Data.Id) local Weapon = Class.Lookup[Data.Id] + local Constraints = constraint.GetTable(self) + local PhysData = SavePhysObj(self) if self.State ~= "Empty" then self:Unload() end - local Constraints = constraint.GetTable(self) - local PhysData = SavePhysObj(self) - UpdateWeapon(self, Data, Class, Weapon) if Class.OnUpdate then - Class.OnUpdate(self, Class, Weapon) + Class.OnUpdate(self, Data, Class, Weapon) end RestorePhysObj(self, PhysData) @@ -219,6 +220,8 @@ do -- Spawn and Update functions -------------------------------- net.Start("ACF_UpdateHitboxes") net.WriteEntity(self) net.Send(self.Owner) + + return true, "Weapon updated successfully!" end end --------------------------------------------- From 4ce9228d17c7d8bd5c90e17a17af2ce65de7519e Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Wed, 22 Apr 2020 18:17:14 -0400 Subject: [PATCH 068/279] Adapted acf_engine to work with the new menu tool - The new menu tool will now be capable of spawning ACF Engines. Attempting to do this with the old menu tool with throw errors. - Engines can now be fully updated with the new menu tool. - Engines will now have their own limit convar, `sbox_max_acf_engine`, instead of using the `_acf_misc` convar. Extension developers can also define custom convars inside each engine class definition if they desire. - Engine type definitions can now have CalculatePeakEnergy and CalculateFuelUsage functions to be used with engines --- lua/acf/base/sh_classes.lua | 17 +- lua/acf/shared/engine_types/electric.lua | 11 + lua/acf/shared/engine_types/turbine.lua | 7 + lua/entities/acf_engine/cl_init.lua | 10 +- lua/entities/acf_engine/init.lua | 350 +++++++++++++++-------- lua/weapons/gmod_tool/stools/acfmenu.lua | 1 - 6 files changed, 264 insertions(+), 132 deletions(-) diff --git a/lua/acf/base/sh_classes.lua b/lua/acf/base/sh_classes.lua index 1a412127d..021774f56 100644 --- a/lua/acf/base/sh_classes.lua +++ b/lua/acf/base/sh_classes.lua @@ -259,7 +259,22 @@ do -- Engine registration functions local Engines = ACF.Classes.Engines function ACF.RegisterEngineClass(ID, Data) - return AddClassGroup(ID, Engines, Data) + local Group = AddClassGroup(ID, Engines, Data) + + if not Group.LimitConVar then + Group.LimitConVar = { + Name = "_acf_engine", + Amount = 16, + } + end + + local Limit = Group.LimitConVar + + if not ConVarExists("sbox_max" .. Limit.Name) then + CreateConVar("sbox_max" .. Limit.Name, Limit.Amount, FCVAR_ARCHIVE) + end + + return Group end function ACF.RegisterEngine(ID, ClassID, Data) diff --git a/lua/acf/shared/engine_types/electric.lua b/lua/acf/shared/engine_types/electric.lua index 312c78833..13bc17cdd 100644 --- a/lua/acf/shared/engine_types/electric.lua +++ b/lua/acf/shared/engine_types/electric.lua @@ -3,4 +3,15 @@ ACF.RegisterEngineType("Electric", { Efficiency = 0.85, --percent efficiency converting chemical kw into mechanical kw TorqueScale = 0.5, HealthMult = 0.75, + CalculatePeakEnergy = function(Entity) + -- Adjust torque to 1 rpm maximum, assuming a linear decrease from a max @ 1 rpm to min @ limiter + local peakkw = (Entity.PeakTorque * (1 + Entity.PeakMaxRPM / Entity.LimitRPM)) * Entity.LimitRPM / (4 * 9548.8) + local PeakKwRPM = math.floor(Entity.LimitRPM * 0.5) + + return peakkw, PeakKwRPM + end, + CalculateFuelUsage = function(Entity) + -- Electric engines use current power output, not max + return ACF.ElecRate / Entity.Efficiency * 3600 + end }) diff --git a/lua/acf/shared/engine_types/turbine.lua b/lua/acf/shared/engine_types/turbine.lua index 6abb95a71..66cf8ea02 100644 --- a/lua/acf/shared/engine_types/turbine.lua +++ b/lua/acf/shared/engine_types/turbine.lua @@ -3,4 +3,11 @@ ACF.RegisterEngineType("Turbine", { Efficiency = 0.375, -- previously 0.231 TorqueScale = 0.2, HealthMult = 0.125, + CalculatePeakEnergy = function(Entity) + -- Adjust torque to 1 rpm maximum, assuming a linear decrease from a max @ 1 rpm to min @ limiter + local peakkw = (Entity.PeakTorque * (1 + Entity.PeakMaxRPM / Entity.LimitRPM)) * Entity.LimitRPM / (4 * 9548.8) + local PeakKwRPM = math.floor(Entity.LimitRPM * 0.5) + + return peakkw, PeakKwRPM + end, }) diff --git a/lua/entities/acf_engine/cl_init.lua b/lua/entities/acf_engine/cl_init.lua index 25122c636..ff42b1f68 100644 --- a/lua/entities/acf_engine/cl_init.lua +++ b/lua/entities/acf_engine/cl_init.lua @@ -2,11 +2,15 @@ include("shared.lua") local SeatedInfo = CreateClientConVar("ACF_EngineInfoWhileSeated", 0, true, false) +language.Add("Undone_acf_engine", "Undone ACF Engine") +language.Add("SBoxLimit__acf_engine", "You've reached the ACF Engines limit!") + -- copied from base_wire_entity: DoNormalDraw's notip arg isn't accessible from ENT:Draw defined there. function ENT:Draw() - local lply = LocalPlayer() - local hideBubble = not SeatedInfo:GetBool() and IsValid(lply) and lply:InVehicle() - self.BaseClass.DoNormalDraw(self, false, hideBubble) + local Player = LocalPlayer() + local HideBubble = IsValid(Player) and Player:InVehicle() and not SeatedInfo:GetBool() + + self.BaseClass.DoNormalDraw(self, false, HideBubble) Wire_Render(self) if self.GetBeamLength and (not self.GetShowBeam or self:GetShowBeam()) then diff --git a/lua/entities/acf_engine/init.lua b/lua/entities/acf_engine/init.lua index e423a012c..42568d704 100644 --- a/lua/entities/acf_engine/init.lua +++ b/lua/entities/acf_engine/init.lua @@ -10,7 +10,7 @@ do ACF.RegisterClassLink("acf_engine", "acf_fueltank", function(Engine, Target) if Engine.FuelTanks[Target] then return false, "This engine is already linked to this fuel tank!" end if Target.Engines[Engine] then return false, "This engine is already linked to this fuel tank!" end - if Engine.FuelType ~= "Multifuel" and Engine.FuelType ~= Target.FuelType then return false, "Cannot link because fuel type is incompatible." end + if not Engine.FuelTypes[Target.FuelType] then return false, "Cannot link because fuel type is incompatible." end if Target.NoLinks then return false, "This fuel tank doesn't allow linking." end Engine.FuelTanks[Target] = true @@ -100,6 +100,7 @@ end local CheckLegal = ACF_CheckLegal local ClassLink = ACF.GetClassLink local ClassUnlink = ACF.GetClassUnlink +local Engines = ACF.Classes.Engines local EngineTypes = ACF.Classes.EngineTypes local UnlinkSound = "physics/metal/metal_box_impact_bullet%s.wav" local Round = math.Round @@ -109,60 +110,6 @@ local TimerExists = timer.Exists local TimerSimple = timer.Simple local TimerRemove = timer.Remove -local function UpdateEngineData(Entity, Id, EngineData) - local Type = EngineData.enginetype or "GenericPetrol" - local EngineType = EngineTypes[Type] - - Entity.Id = Id - Entity.Name = EngineData.name - Entity.ShortName = Id - Entity.EntType = EngineData.category - Entity.SoundPath = EngineData.sound - Entity.SoundPitch = EngineData.pitch or 1 - Entity.Mass = EngineData.weight - Entity.PeakTorque = EngineData.torque - Entity.PeakTorqueHeld = EngineData.torque - Entity.IdleRPM = EngineData.idlerpm - Entity.PeakMinRPM = EngineData.peakminrpm - Entity.PeakMaxRPM = EngineData.peakmaxrpm - Entity.LimitRPM = EngineData.limitrpm - Entity.Inertia = EngineData.flywheelmass * 3.1416 ^ 2 - Entity.IsElectric = EngineData.iselec - Entity.FlywheelOverride = EngineData.flywheeloverride - Entity.IsTrans = EngineData.istrans -- driveshaft outputs to the side - Entity.FuelType = EngineData.fuel or "Petrol" - Entity.EngineType = Type - Entity.Efficiency = EngineType.Efficiency - Entity.TorqueScale = EngineType.TorqueScale - Entity.RequiresFuel = EngineData.requiresfuel - - --calculate boosted peak kw - if Entity.EngineType == "Turbine" or Entity.EngineType == "Electric" then - Entity.peakkw = (Entity.PeakTorque * (1 + Entity.PeakMaxRPM / Entity.LimitRPM)) * Entity.LimitRPM / (4 * 9548.8) --adjust torque to 1 rpm maximum, assuming a linear decrease from a max @ 1 rpm to min @ limiter - Entity.PeakKwRPM = math.floor(Entity.LimitRPM / 2) - else - Entity.peakkw = Entity.PeakTorque * Entity.PeakMaxRPM / 9548.8 - Entity.PeakKwRPM = Entity.PeakMaxRPM - end - - --calculate base fuel usage - if Entity.EngineType == "Electric" then - Entity.FuelUse = ACF.ElecRate / (Entity.Efficiency * 60 * 60) --elecs use current power output, not max - else - Entity.FuelUse = ACF.TorqueBoost * ACF.FuelRate * Entity.Efficiency * Entity.peakkw / (60 * 60) - end - - local PhysObj = Entity:GetPhysicsObject() - - if IsValid(PhysObj) then - PhysObj:SetMass(Entity.Mass) - end - - Entity:SetNWString("WireName", Entity.Name) - - Entity:UpdateOverlay(true) -end - local function GetPitchVolume(Engine) local RPM = Engine.FlyRPM local Pitch = math.Clamp(20 + (RPM * Engine.SoundPitch) * 0.02, 1, 255) @@ -305,63 +252,240 @@ local Inputs = { --===============================================================================================-- -function MakeACF_Engine(Owner, Pos, Angle, Id) - if not Owner:CheckLimit("_acf_misc") then return end +do -- Spawn and Update functions + local function VerifyData(Data) + -- Entity was created via menu tool + if Data.Engine then + Data.Id = Data.Engine + end + + local Class = ACF.GetClassGroup(Engines, Data.Id) + + if not Class then + Data.Id = "5.7-V8" + end + end - local EngineData = ACF.Weapons.Mobility[Id] + local function UpdateEngine(Entity, Data, Class, EngineData) + local Type = EngineData.Type or "GenericPetrol" + local EngineType = EngineTypes[Type] or EngineTypes.GenericPetrol - if not EngineData then return end + Entity:SetModel(EngineData.Model) - local Engine = ents.Create("acf_engine") + Entity:PhysicsInit(SOLID_VPHYSICS) + Entity:SetMoveType(MOVETYPE_VPHYSICS) - if not IsValid(Engine) then return end + -- Storing all the relevant information on the entity for duping + for _, V in ipairs(Entity.DataStore) do + Entity[V] = Data[V] + end - Engine:SetModel(EngineData.model) - Engine:SetPlayer(Owner) - Engine:SetAngles(Angle) - Engine:SetPos(Pos) - Engine:Spawn() + Entity.Name = EngineData.Name + Entity.ShortName = EngineData.ID + Entity.EntType = Class.ID + Entity.SoundPitch = EngineData.Pitch or 1 + Entity.PeakTorque = EngineData.Torque + Entity.PeakTorqueHeld = EngineData.Torque + Entity.IdleRPM = EngineData.RPM.Idle + Entity.PeakMinRPM = EngineData.RPM.PeakMin + Entity.PeakMaxRPM = EngineData.RPM.PeakMax + Entity.LimitRPM = EngineData.RPM.Limit + Entity.FlywheelOverride = EngineData.RPM.Override + Entity.Inertia = EngineData.FlywheelMass * 3.1416 ^ 2 + Entity.IsElectric = EngineData.IsElectric + Entity.IsTrans = EngineData.IsTrans -- driveshaft outputs to the side + Entity.FuelTypes = EngineData.Fuel or { Petrol = true } + Entity.FuelType = next(EngineData.Fuel) + Entity.RequiresFuel = EngineData.RequiresFuel + Entity.EngineType = EngineType.ID + Entity.Efficiency = EngineType.Efficiency + Entity.TorqueScale = EngineType.TorqueScale + Entity.HealthMult = EngineType.HealthMult + Entity.Out = Entity:WorldToLocal(Entity:GetAttachment(Entity:LookupAttachment("driveshaft")).Pos) + + Entity:SetNWString("WireName", Entity.Name) + + --calculate boosted peak kw + if EngineType.CalculatePeakEnergy then + local peakkw, PeakKwRPM = EngineType.CalculatePeakEnergy(Entity) + + Entity.peakkw = peakkw + Entity.PeakKwRPM = PeakKwRPM + else + Entity.peakkw = Entity.PeakTorque * Entity.PeakMaxRPM / 9548.8 + Entity.PeakKwRPM = Entity.PeakMaxRPM + end - Engine:PhysicsInit(SOLID_VPHYSICS) - Engine:SetMoveType(MOVETYPE_VPHYSICS) + --calculate base fuel usage + if EngineType.CalculateFuelUsage then + Entity.FuelUse = EngineType.CalculateFuelUsage(Entity) + else + Entity.FuelUse = ACF.TorqueBoost * ACF.FuelRate * Entity.Efficiency * Entity.peakkw / 3600 + end - Owner:AddCount("_acf_misc", Engine) - Owner:AddCleanup("acfmenu", Engine) + ACF_Activate(Entity, true) - UpdateEngineData(Engine, Id, EngineData) + Entity.ACF.LegalMass = EngineData.Mass + Entity.ACF.Model = EngineData.Model - Engine.Owner = Owner - Engine.Model = EngineData.model - Engine.CanUpdate = true - Engine.Active = false - Engine.Gearboxes = {} - Engine.FuelTanks = {} - Engine.LastThink = 0 - Engine.MassRatio = 1 - Engine.FuelUsage = 0 - Engine.Throttle = 0 - Engine.FlyRPM = 0 - Engine.Out = Engine:WorldToLocal(Engine:GetAttachment(Engine:LookupAttachment("driveshaft")).Pos) + local Phys = Entity:GetPhysicsObject() + if IsValid(Phys) then Phys:SetMass(EngineData.Mass) end - Engine.Inputs = WireLib.CreateInputs(Engine, { "Active", "Throttle" }) - Engine.Outputs = WireLib.CreateOutputs(Engine, { "RPM", "Torque", "Power", "Fuel Use", "Entity [ENTITY]", "Mass", "Physical Mass" }) + Entity:UpdateOverlay(true) - WireLib.TriggerOutput(Engine, "Entity", Engine) + CheckLegal(Entity) + end - ACF_Activate(Engine) + function MakeACF_Engine(Player, Pos, Angle, Data) + VerifyData(Data) - Engine.ACF.LegalMass = Engine.Mass - Engine.ACF.Model = Engine.Model + local Class = ACF.GetClassGroup(Engines, Data.Id) + local EngineData = Class.Lookup[Data.Id] + local Limit = Class.LimitConVar.Name - CheckLegal(Engine) + if not Player:CheckLimit(Limit) then return false end - return Engine -end + local Engine = ents.Create("acf_engine") -list.Set("ACFCvars", "acf_engine", { "id" }) -duplicator.RegisterEntityClass("acf_engine", MakeACF_Engine, "Pos", "Angle", "Id") -ACF.RegisterLinkSource("acf_engine", "FuelTanks") -ACF.RegisterLinkSource("acf_engine", "Gearboxes") + if not IsValid(Engine) then return end + + Engine:SetPlayer(Player) + Engine:SetAngles(Angle) + Engine:SetPos(Pos) + Engine:Spawn() + + Player:AddCleanup("acfmenu", Engine) + Player:AddCount(Limit, Engine) + + Engine.Owner = Player -- MUST be stored on ent for PP + Engine.Active = false + Engine.Gearboxes = {} + Engine.FuelTanks = {} + Engine.LastThink = 0 + Engine.MassRatio = 1 + Engine.FuelUsage = 0 + Engine.Throttle = 0 + Engine.FlyRPM = 0 + Engine.SoundPath = EngineData.Sound + Engine.Inputs = WireLib.CreateInputs(Engine, { "Active", "Throttle" }) + Engine.Outputs = WireLib.CreateOutputs(Engine, { "RPM", "Torque", "Power", "Fuel Use", "Entity [ENTITY]", "Mass", "Physical Mass" }) + Engine.DataStore = ACF.GetEntClassVars("acf_engine") + + WireLib.TriggerOutput(Engine, "Entity", Engine) + + UpdateEngine(Engine, Data, Class, EngineData) + + if Class.OnSpawn then + Class.OnSpawn(Engine, Data, Class, EngineData) + end + + return Engine + end + + ACF.RegisterEntityClass("acf_engine", MakeACF_Engine, "Id") + ACF.RegisterLinkSource("acf_engine", "FuelTanks") + ACF.RegisterLinkSource("acf_engine", "Gearboxes") + + local function SavePhysObj(Entity) + local PhysObj = Entity:GetPhysicsObject() + + return { + Gravity = PhysObj:IsGravityEnabled(), + Motion = PhysObj:IsMotionEnabled(), + } + end + + local function RestorePhysObj(Entity, PhysData) + local PhysObj = Entity:GetPhysicsObject() + + PhysObj:EnableGravity(PhysData.Gravity) + PhysObj:EnableMotion(PhysData.Motion) + end + + local function RestoreConstraints(List) + local Constraints = duplicator.ConstraintType + + for _, Data in ipairs(List) do + local Constraint = Constraints[Data.Type] + local Args = {} + + for Index, Name in ipairs(Constraint.Args) do + Args[Index] = Data[Name] + end + + Constraint.Func(unpack(Args)) + end + end + + function ENT:Update(Data) + if self.Active then return false, "Turn off the engine before updating it!" end + + VerifyData(Data) + + if self.Id == Data.Id then return false, "This engine is already the one you want it to update to!" end + + local Class = ACF.GetClassGroup(Engines, Data.Id) + local EngineData = Class.Lookup[Data.Id] + local Constraints = constraint.GetTable(self) + local PhysData = SavePhysObj(self) + local Feedback = "" + + UpdateEngine(self, Data, Class, EngineData) + + if Class.OnUpdate then + Class.OnUpdate(self, Data, Class, EngineData) + end + + RestorePhysObj(self, PhysData) + RestoreConstraints(Constraints) + + if next(self.Gearboxes) then + local Count, Total = 0, 0 + + for Gearbox in pairs(self.Gearboxes) do + self:Unlink(Gearbox) + + local Result = self:Link(Gearbox) + + if not Result then Count = Count + 1 end + + Total = Total + 1 + end + + if Count == Total then + Feedback = Feedback .. " Unlinked all gearboxes due to excessive driveshaft angle." + elseif Count > 0 then + local Text = Feedback .. " Unlinked %s out of %s gearboxes due to excessive driveshaft angle." + + Feedback = Text:format(Count, Total) + end + end + + if next(self.FuelTanks) then + local Count, Total = 0, 0 + + for Tank in pairs(self.FuelTanks) do + if not self.FuelTypes[Tank.FuelType] then + self:Unlink(Tank) + + Count = Count + 1 + end + + Total = Total + 1 + end + + if Count == Total then + Feedback = Feedback .. " Unlinked all fuel tanks due to fuel type change." + elseif Count > 0 then + local Text = Feedback .. " Unlinked %s out of %s fuel tanks due to fuel type change." + + Feedback = Text:format(Count, Total) + end + end + + return true, "Engine updated successfully!" .. Feedback + end +end --===============================================================================================-- -- Meta Funcs @@ -387,35 +511,6 @@ function ENT:Disable() self:UpdateOverlay() end -function ENT:Update(ArgsTable) - if self.Active then return false, "Turn off the engine before updating it!" end - if ArgsTable[1] ~= self.Owner then return false, "You don't own that engine!" end - - local Id = ArgsTable[4] -- Argtable[4] is the engine ID - local EngineData = ACF.Weapons.Mobility[Id] - - if not EngineData then return false, "Invalid engine type!" end - if EngineData.model ~= self.Model then return false, "The new engine must have the same model!" end - - local Feedback = "" - - if EngineData.fuel ~= self.FuelType then - Feedback = " Fuel type changed, fuel tanks unlinked." - - for Tank in pairs(self.FuelTanks) do - self:Unlink(Tank) - end - end - - UpdateEngineData(self, Id, EngineData) - - ACF_Activate(self, true) - - self.ACF.LegalMass = self.Mass - - return true, "Engine updated successfully!" .. Feedback -end - function ENT:UpdateOutputs() if TimerExists("ACF Output Buffer" .. self:EntIndex()) then return end @@ -513,8 +608,8 @@ function ENT:ACF_Activate() Percent = self.ACF.Health / self.ACF.MaxHealth end - self.ACF.Health = Health * Percent * ACF.EngineHPMult[self.EngineType] - self.ACF.MaxHealth = Health * ACF.EngineHPMult[self.EngineType] + self.ACF.Health = Health * Percent * self.HealthMult + self.ACF.MaxHealth = Health * self.HealthMult self.ACF.Armour = Armour * (0.5 + Percent / 2) self.ACF.MaxArmour = Armour * ACF.ArmorMod self.ACF.Type = nil @@ -593,6 +688,7 @@ function ENT:CalcRPM() --calculate fuel usage if IsValid(FuelTank) then self.FuelTank = FuelTank + self.FuelType = FuelTank.FuelType local Consumption = self:GetConsumption(self.Throttle, self.FlyRPM) * DeltaTime diff --git a/lua/weapons/gmod_tool/stools/acfmenu.lua b/lua/weapons/gmod_tool/stools/acfmenu.lua index 078bc904a..066ea96ef 100644 --- a/lua/weapons/gmod_tool/stools/acfmenu.lua +++ b/lua/weapons/gmod_tool/stools/acfmenu.lua @@ -30,7 +30,6 @@ if CLIENT then language.Add( "Tool.acfmenu.1", "Right click to link the selected sensor to a pod" ) language.Add( "Undone_ACF Entity", "Undone ACF Entity" ) - language.Add( "Undone_acf_engine", "Undone ACF Engine" ) language.Add( "Undone_acf_gearbox", "Undone ACF Gearbox" ) language.Add( "Undone_acf_ammo", "Undone ACF Ammo" ) language.Add( "SBoxLimit_acf_rack", "You've reached the ACF Launchers limit!" ) From 5d01844987f059be5b5b52e5a1b602b5beaa9e6b Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Wed, 22 Apr 2020 19:03:29 -0400 Subject: [PATCH 069/279] Added backwards compatibility with removed HRACs - Due to the removal of HRACs, all weapons with this ID will be turned into RACs. --- lua/entities/acf_gun/init.lua | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lua/entities/acf_gun/init.lua b/lua/entities/acf_gun/init.lua index b92e453fa..ff4bc10e3 100644 --- a/lua/entities/acf_gun/init.lua +++ b/lua/entities/acf_gun/init.lua @@ -21,6 +21,11 @@ local HookRun = hook.Run local EMPTY = { Type = "Empty", PropMass = 0, ProjMass = 0, Tracer = 0 } do -- Spawn and Update functions -------------------------------- + local Updated = { + ["20mmHRAC"] = "20mmRAC", + ["30mmHRAC"] = "30mmRAC", + } + local function VerifyData(Data) -- Entity was created via menu tool if Data.Weapon then @@ -30,7 +35,7 @@ do -- Spawn and Update functions -------------------------------- local Class = ACF.GetClassGroup(Weapons, Data.Id) if not Class then - Data.Id = "50mmC" + Data.Id = Data.Id and Updated[Data.Id] or "50mmC" end end From bcf98860e1644a4a88770ef546d410a9592255ed Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Thu, 23 Apr 2020 15:49:05 -0400 Subject: [PATCH 070/279] Moved ACF_UpdateHitboxes netmessage to ACF Globals file - Moved the ACF_UpdateHitboxes network message from the acf_gun files to the acf globals file due to more entities requiring it. --- lua/acf/base/acf_globals.lua | 14 ++++++++++++++ lua/entities/acf_gun/cl_init.lua | 11 ----------- lua/entities/acf_gun/init.lua | 2 -- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/lua/acf/base/acf_globals.lua b/lua/acf/base/acf_globals.lua index 0b33c6f59..cf2de4726 100644 --- a/lua/acf/base/acf_globals.lua +++ b/lua/acf/base/acf_globals.lua @@ -123,6 +123,7 @@ do -- ACF Convars/Callbacks ------------------------ end if SERVER then + util.AddNetworkString("ACF_UpdateHitboxes") util.AddNetworkString("ACF_KilledByACF") util.AddNetworkString("ACF_RenderDamage") util.AddNetworkString("ACF_Notify") @@ -154,6 +155,19 @@ elseif CLIENT then end) end --------------------------------------------- + + -- Hitbox Updating -------------------------- + net.Receive("ACF_UpdateHitboxes", function() + local Entity = net.ReadEntity() + + timer.Simple(0.1, function() + if not IsValid(Entity) then return end + if not Entity.UpdateHitboxes then return end + + Entity:UpdateHitboxes() + end) + end) + --------------------------------------------- end timer.Simple(0, function() diff --git a/lua/entities/acf_gun/cl_init.lua b/lua/entities/acf_gun/cl_init.lua index 7599f69eb..642336f31 100644 --- a/lua/entities/acf_gun/cl_init.lua +++ b/lua/entities/acf_gun/cl_init.lua @@ -106,14 +106,3 @@ function ACFGunGUICreate(Table) acfmenupanel.CustomDisplay:PerformLayout() end - -net.Receive("ACF_UpdateHitboxes", function() - local Entity = net.ReadEntity() - - timer.Simple(0.1, function() - if not IsValid(Entity) then return end - if not Entity.UpdateHitboxes then return end - - Entity:UpdateHitboxes() - end) -end) diff --git a/lua/entities/acf_gun/init.lua b/lua/entities/acf_gun/init.lua index ff4bc10e3..900b7a247 100644 --- a/lua/entities/acf_gun/init.lua +++ b/lua/entities/acf_gun/init.lua @@ -158,8 +158,6 @@ do -- Spawn and Update functions -------------------------------- ------------------- Updating --------------------- - util.AddNetworkString("ACF_UpdateHitboxes") - local function SavePhysObj(Entity) local PhysObj = Entity:GetPhysicsObject() From 63589e336486d498a1dbfbe1bfb8fecf05c19690 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Thu, 23 Apr 2020 15:54:42 -0400 Subject: [PATCH 071/279] Increased fuel capacity and reduced consumption - Fuel tanks will now spawn with greater, more realistic amount of fuel inside of them. - Engines will now have lower, more realistic fuel consumption rates. --- lua/acf/base/acf_globals.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lua/acf/base/acf_globals.lua b/lua/acf/base/acf_globals.lua index cf2de4726..c0e239f95 100644 --- a/lua/acf/base/acf_globals.lua +++ b/lua/acf/base/acf_globals.lua @@ -41,9 +41,9 @@ do -- ACF global vars ACF.MVScale = 0.5 --Propellant to MV convertion expotential ACF.PDensity = 1.6 --Gun propellant density (Real powders go from 0.7 to 1.6, i"m using higher densities to simulate case bottlenecking) ACF.TorqueBoost = 1.25 --torque multiplier from using fuel - ACF.FuelRate = 5 --multiplier for fuel usage, 1.0 is approx real world + ACF.FuelRate = 1 --multiplier for fuel usage, 1.0 is approx real world ACF.ElecRate = 1.5 --multiplier for electrics - ACF.TankVolumeMul = 0.5 -- multiplier for fuel tank capacity, 1.0 is approx real world + ACF.TankVolumeMul = 1 -- multiplier for fuel tank capacity, 1.0 is approx real world ACF.LiIonED = 0.458 -- li-ion energy density: kw hours / liter ACF.CuIToLiter = 0.0163871 -- cubic inches to liters ACF.RefillDistance = 300 --Distance in which ammo crate starts refilling. From c21aad3793eaedb10a5c81acabb46eb0cfa68fe7 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Thu, 23 Apr 2020 18:05:57 -0400 Subject: [PATCH 072/279] Improved SBox limit convar creation - SBox limit convars created inside class definition functions will now only exist serverside. They have also received the FCVAR_NOTIFY flag, along with optional help text. --- lua/acf/base/sh_classes.lua | 24 ++++++++++++++---------- lua/acf/shared/guns/smokelauncher.lua | 1 + lua/entities/acf_gun/cl_init.lua | 4 ++-- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/lua/acf/base/sh_classes.lua b/lua/acf/base/sh_classes.lua index 021774f56..1bd230b33 100644 --- a/lua/acf/base/sh_classes.lua +++ b/lua/acf/base/sh_classes.lua @@ -106,6 +106,16 @@ local AddSimpleClass = ACF.AddSimpleClass local AddClassGroup = ACF.AddClassGroup local AddGroupedClass = ACF.AddGroupedClass +local function AddSboxLimit(Data) + if CLIENT then return end + if ConVarExists("sbox_max" .. Data.Name) then return end + + CreateConVar("sbox_max" .. Data.Name, + Data.Amount, + FCVAR_ARCHIVE + FCVAR_NOTIFY, + Data.Text or "") +end + do -- Class registration function local Classes = {} local Queued = {} @@ -195,14 +205,11 @@ do -- Weapon registration functions Group.LimitConVar = { Name = "_acf_gun", Amount = 16, + Text = "Maximum amount of weapons a player can create." } end - local Limit = Group.LimitConVar - - if not ConVarExists("sbox_max" .. Limit.Name) then - CreateConVar("sbox_max" .. Limit.Name, Limit.Amount, FCVAR_ARCHIVE) - end + AddSboxLimit(Group.LimitConVar) if Group.MuzzleFlash then PrecacheParticleSystem(Group.MuzzleFlash) @@ -265,14 +272,11 @@ do -- Engine registration functions Group.LimitConVar = { Name = "_acf_engine", Amount = 16, + Text = "Maximum amount of engines a player can create." } end - local Limit = Group.LimitConVar - - if not ConVarExists("sbox_max" .. Limit.Name) then - CreateConVar("sbox_max" .. Limit.Name, Limit.Amount, FCVAR_ARCHIVE) - end + AddSboxLimit(Group.LimitConVar) return Group end diff --git a/lua/acf/shared/guns/smokelauncher.lua b/lua/acf/shared/guns/smokelauncher.lua index 5e5173a2e..bd7e6293b 100644 --- a/lua/acf/shared/guns/smokelauncher.lua +++ b/lua/acf/shared/guns/smokelauncher.lua @@ -61,6 +61,7 @@ ACF.RegisterWeaponClass("SL", { LimitConVar = { Name = "_acf_smokelauncher", Amount = 10, + Text = "Maximum amount of smoke launchers a player can create." }, Caliber = { Min = 40, diff --git a/lua/entities/acf_gun/cl_init.lua b/lua/entities/acf_gun/cl_init.lua index 642336f31..33792961d 100644 --- a/lua/entities/acf_gun/cl_init.lua +++ b/lua/entities/acf_gun/cl_init.lua @@ -1,6 +1,6 @@ include("shared.lua") -local ACF_GunInfoWhileSeated = CreateClientConVar("ACF_GunInfoWhileSeated", 0, true, false) +local SeatedInfo = CreateClientConVar("ACF_GunInfoWhileSeated", 0, true, false) language.Add("Undone_acf_gun", "Undone ACF Weapon") language.Add("SBoxLimit__acf_gun", "You've reached the ACF Weapons limit!") @@ -27,7 +27,7 @@ end -- copied from base_wire_entity: DoNormalDraw's notip arg isn't accessible from ENT:Draw defined there. function ENT:Draw() local Player = LocalPlayer() - local HideBubble = IsValid(Player) and Player:InVehicle() and not ACF_GunInfoWhileSeated:GetBool() + local HideBubble = IsValid(Player) and Player:InVehicle() and not SeatedInfo:GetBool() self.BaseClass.DoNormalDraw(self, false, HideBubble) Wire_Render(self) From bfaa9a57cf2c79a1ed1e2f48f5540d131dde580c Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Thu, 23 Apr 2020 18:08:57 -0400 Subject: [PATCH 073/279] Added backwards compatibility with 14.5mm RACs - 14.5mm RACs from ACF-2 will be turned into 20mm RACs. --- lua/entities/acf_gun/init.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/lua/entities/acf_gun/init.lua b/lua/entities/acf_gun/init.lua index 900b7a247..dc8131b24 100644 --- a/lua/entities/acf_gun/init.lua +++ b/lua/entities/acf_gun/init.lua @@ -24,6 +24,7 @@ do -- Spawn and Update functions -------------------------------- local Updated = { ["20mmHRAC"] = "20mmRAC", ["30mmHRAC"] = "30mmRAC", + ["14.5mmRAC"] = "20mmRAC", } local function VerifyData(Data) From 427d9d6e9cf5b1ab0952d19cda584950f02220a7 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Thu, 23 Apr 2020 18:52:44 -0400 Subject: [PATCH 074/279] Adapted acf_fueltank to work with the new menu tool - The new menu tool will now be capable of spawning ACF Fuel Tanks. Attempting to do this with the old menu tool with throw errors. - Fuel tanks can now be fully updated with the new menu tool. - Fuel tanks will now have their own limit convar, `sbox_max_acf_fueltank`, instead of using the `_acf_misc` convar. Extension developers can also define custom convars inside each engine class definition if they desire. --- lua/acf/base/sh_classes.lua | 14 +- lua/entities/acf_fueltank/cl_init.lua | 14 +- lua/entities/acf_fueltank/init.lua | 416 +++++++++++++++----------- 3 files changed, 273 insertions(+), 171 deletions(-) diff --git a/lua/acf/base/sh_classes.lua b/lua/acf/base/sh_classes.lua index 1bd230b33..b8fd166cb 100644 --- a/lua/acf/base/sh_classes.lua +++ b/lua/acf/base/sh_classes.lua @@ -308,7 +308,19 @@ do -- Fuel tank registration functions local FuelTanks = ACF.Classes.FuelTanks function ACF.RegisterFuelTankClass(ID, Data) - return AddClassGroup(ID, FuelTanks, Data) + local Group = AddClassGroup(ID, FuelTanks, Data) + + if not Group.LimitConVar then + Group.LimitConVar = { + Name = "_acf_fueltank", + Amount = 24, + Text = "Maximum amount of fuel tanks a player can create." + } + end + + AddSboxLimit(Group.LimitConVar) + + return Group end function ACF.RegisterFuelTank(ID, ClassID, Data) diff --git a/lua/entities/acf_fueltank/cl_init.lua b/lua/entities/acf_fueltank/cl_init.lua index 68a40e40b..383502ad5 100644 --- a/lua/entities/acf_fueltank/cl_init.lua +++ b/lua/entities/acf_fueltank/cl_init.lua @@ -2,7 +2,14 @@ include("shared.lua") local SeatedInfo = CreateClientConVar("ACF_FuelInfoWhileSeated", 0, true, false) +language.Add("Undone_acf_fueltank", "Undone ACF Fuel Tank") +language.Add("SBoxLimit__acf_fueltank", "You've reached the ACF Fuel Tanks limit!") + function ENT:Initialize() + self:UpdateHitboxes() +end + +function ENT:UpdateHitboxes() self.HitBoxes = { Main = { Pos = self:OBBCenter(), @@ -15,9 +22,10 @@ end -- copied from base_wire_entity: DoNormalDraw's notip arg isn't accessible from ENT:Draw defined there. function ENT:Draw() - local lply = LocalPlayer() - local hideBubble = not SeatedInfo:GetBool() and IsValid(lply) and lply:InVehicle() - self.BaseClass.DoNormalDraw(self, false, hideBubble) + local Player = LocalPlayer() + local HideBubble = IsValid(Player) and Player:InVehicle() and not SeatedInfo:GetBool() + + self.BaseClass.DoNormalDraw(self, false, HideBubble) Wire_Render(self) if self.GetBeamLength and (not self.GetShowBeam or self:GetShowBeam()) then diff --git a/lua/entities/acf_fueltank/init.lua b/lua/entities/acf_fueltank/init.lua index 594ab9119..00179b5a5 100644 --- a/lua/entities/acf_fueltank/init.lua +++ b/lua/entities/acf_fueltank/init.lua @@ -10,47 +10,12 @@ include("shared.lua") local CheckLegal = ACF_CheckLegal local ClassLink = ACF.GetClassLink local ClassUnlink = ACF.GetClassUnlink +local FuelTanks = ACF.Classes.FuelTanks +local FuelTypes = ACF.Classes.FuelTypes +local ActiveTanks = ACF.FuelTanks local TimerCreate = timer.Create local TimerExists = timer.Exists -local FuelTypes = ACF.Classes.FuelTypes - -local function UpdateFuelData(Entity, Id, Data1, Data2, FuelData) - local Percentage = 1 --how full is the tank? - - --if updating existing tank, keep fuel level - if Entity.Capacity and Entity.Capacity ~= 0 then - Percentage = Entity.Fuel / Entity.Capacity - end - - local PhysObj = Entity:GetPhysicsObject() - local Area = PhysObj:GetSurfaceArea() - local Wall = 0.03937 --wall thickness in inches (1mm) - - Entity.Id = Id - Entity.SizeId = Data1 - Entity.FuelType = Data2 - Entity.Name = Data2 .. " " .. Data1 - Entity.ShortName = Entity.Name - Entity.EntType = Data2 - Entity.Model = FuelData.model - Entity.FuelDensity = FuelTypes[Data2].Density - Entity.Volume = PhysObj:GetVolume() - (Area * Wall) -- total volume of tank (cu in), reduced by wall thickness - Entity.Capacity = Entity.Volume * ACF.CuIToLiter * ACF.TankVolumeMul * 0.4774 --internal volume available for fuel in liters, with magic realism number - Entity.EmptyMass = (Area * Wall) * 16.387 * (7.9 / 1000) -- total wall volume * cu in to cc * density of steel (kg/cc) - Entity.IsExplosive = Entity.FuelType ~= "Electric" and FuelData.explosive - Entity.NoLinks = FuelData.nolinks - - if Entity.FuelType == "Electric" then - Entity.Liters = Entity.Capacity --batteries capacity is different from internal volume - Entity.Capacity = Entity.Capacity * ACF.LiIonED - end - - Entity.Fuel = Percentage * Entity.Capacity - - Entity:UpdateMass() - Entity:UpdateOverlay() - Entity:UpdateOutputs() -end +local Wall = 0.03937 --wall thickness in inches (1mm) local Inputs = { Active = function(Entity, Value) @@ -71,74 +36,214 @@ local Inputs = { --===============================================================================================-- -function MakeACF_FuelTank(Owner, Pos, Angle, Id, Data1, Data2) - if not Owner:CheckLimit("_acf_misc") then return end +do -- Spawn and Update functions + local function VerifyData(Data) + if Data.FuelTank then -- Entity was created via menu tool + Data.Id = Data.FuelTank + elseif Data.SizeId then -- Backwards compatibility with ACF-2 dupes + Data.Id = Data.SizeId + Data.SizeId = nil + end + + local Class = ACF.GetClassGroup(FuelTanks, Data.Id) - local FuelData = ACF.Weapons.FuelTanks[Data1] + if not Class then + Data.Id = "Jerry_Can" + end - if not FuelData then return end + -- Making sure to provide a valid fuel type + if not (Data.FuelType and FuelTypes[Data.FuelType]) then + Data.FuelType = "Petrol" + end + end - local Tank = ents.Create("acf_fueltank") + local function UpdateFuelTank(Entity, Data, Class, FuelTank) + local FuelData = FuelTypes[Data.FuelType] + local Percentage = 1 - if not IsValid(Tank) then return end + Entity:SetModel(FuelTank.Model) - Tank:SetModel(FuelData.model) - Tank:SetPlayer(Owner) - Tank:SetAngles(Angle) - Tank:SetPos(Pos) - Tank:Spawn() + Entity:PhysicsInit(SOLID_VPHYSICS) + Entity:SetMoveType(MOVETYPE_VPHYSICS) - Tank:PhysicsInit(SOLID_VPHYSICS) - Tank:SetMoveType(MOVETYPE_VPHYSICS) + local PhysObj = Entity:GetPhysicsObject() + local Area = PhysObj:GetSurfaceArea() - Owner:AddCount("_acf_misc", Tank) - Owner:AddCleanup("acfmenu", Tank) + -- Storing all the relevant information on the entity for duping + for _, V in ipairs(Entity.DataStore) do + Entity[V] = Data[V] + end - UpdateFuelData(Tank, Id, Data1, Data2, FuelData) + -- If updating, keep the same fuel level + if Entity.Capacity then + Percentage = Entity.Fuel / Entity.Capacity + end - Tank.Owner = Owner - Tank.Engines = {} - Tank.Active = true - Tank.Leaking = 0 - Tank.CanUpdate = true - Tank.LastThink = 0 - Tank.HitBoxes = { + Entity.Name = FuelTank.Name + Entity.ShortName = Entity.Id + Entity.EntType = Class.Name + Entity.FuelDensity = FuelData.Density + Entity.Volume = PhysObj:GetVolume() - (Area * Wall) -- total volume of tank (cu in), reduced by wall thickness + Entity.Capacity = Entity.Volume * ACF.CuIToLiter * ACF.TankVolumeMul * 0.4774 --internal volume available for fuel in liters, with magic realism number + Entity.EmptyMass = (Area * Wall) * 16.387 * (7.9 / 1000) -- total wall volume * cu in to cc * density of steel (kg/cc) + Entity.IsExplosive = Entity.FuelType ~= "Electric" and FuelTank.IsExplosive + Entity.NoLinks = FuelTank.Unlinkable + Entity.HitBoxes = { Main = { - Pos = Tank:OBBCenter(), - Scale = (Tank:OBBMaxs() - Tank:OBBMins()) - Vector(0.5, 0.5, 0.5), + Pos = Entity:OBBCenter(), + Scale = (Entity:OBBMaxs() - Entity:OBBMins()) - Vector(0.5, 0.5, 0.5), } } - Tank.Inputs = WireLib.CreateInputs(Tank, { "Active", "Refuel Duty" }) - Tank.Outputs = WireLib.CreateOutputs(Tank, { "Fuel", "Capacity", "Leaking", "Entity [ENTITY]" }) + Entity:SetNWString("WireName", Entity.Name) - WireLib.TriggerOutput(Tank, "Entity", Tank) + if Entity.FuelType == "Electric" then + Entity.Liters = Entity.Capacity --batteries capacity is different from internal volume + Entity.Capacity = Entity.Capacity * ACF.LiIonED + end + + Entity.Fuel = Percentage * Entity.Capacity - ACF.FuelTanks[Tank] = true + ACF_Activate(Entity, true) - local PhysObj = Tank:GetPhysicsObject() - local Fuel = Tank.FuelType == "Electric" and Tank.Liters or Tank.Fuel - local Mass = math.floor(Tank.EmptyMass + Fuel * Tank.FuelDensity) + Entity.ACF.Model = FuelTank.Model - if IsValid(PhysObj) then - PhysObj:SetMass(Mass) + Entity:UpdateMass(true) + Entity:UpdateOverlay(true) - Tank.Mass = Mass + CheckLegal(Entity) end - ACF_Activate(Tank) + function MakeACF_FuelTank(Player, Pos, Angle, Data) + VerifyData(Data) - Tank.ACF.LegalMass = Tank.Mass - Tank.ACF.Model = Tank.Model + local Class = ACF.GetClassGroup(FuelTanks, Data.Id) + local FuelTank = Class.Lookup[Data.Id] + local Limit = Class.LimitConVar.Name - CheckLegal(Tank) + if not Player:CheckLimit(Limit) then return end - return Tank -end + local Tank = ents.Create("acf_fueltank") + + if not IsValid(Tank) then return end + + Tank:SetPlayer(Player) + Tank:SetAngles(Angle) + Tank:SetPos(Pos) + Tank:Spawn() + + Player:AddCleanup("acfmenu", Tank) + Player:AddCount(Limit, Tank) + + Tank.Owner = Player -- MUST be stored on ent for PP + Tank.Engines = {} + Tank.Active = true + Tank.Leaking = 0 + Tank.CanUpdate = true + Tank.LastThink = 0 + Tank.Inputs = WireLib.CreateInputs(Tank, { "Active", "Refuel Duty" }) + Tank.Outputs = WireLib.CreateOutputs(Tank, { "Fuel", "Capacity", "Leaking", "Entity [ENTITY]" }) + Tank.DataStore = ACF.GetEntClassVars("acf_fueltank") + + WireLib.TriggerOutput(Tank, "Entity", Tank) + + ActiveTanks[Tank] = true -list.Set("ACFCvars", "acf_fueltank", {"id", "data1", "data2"}) -duplicator.RegisterEntityClass("acf_fueltank", MakeACF_FuelTank, "Pos", "Angle", "Id", "SizeId", "FuelType") -ACF.RegisterLinkSource("acf_fueltank", "Engines") + UpdateFuelTank(Tank, Data, Class, FuelTank) + + if Class.OnSpawn then + Class.OnSpawn(Tank, Data, Class, FuelTank) + end + + return Tank + end + + ACF.RegisterEntityClass("acf_fueltank", MakeACF_FuelTank, "Id", "FuelType", "SizeId") + ACF.RegisterLinkSource("acf_fueltank", "Engines") + + ------------------- Updating --------------------- + + local function SavePhysObj(Entity) + local PhysObj = Entity:GetPhysicsObject() + + return { + Gravity = PhysObj:IsGravityEnabled(), + Motion = PhysObj:IsMotionEnabled(), + } + end + + local function RestorePhysObj(Entity, PhysData) + local PhysObj = Entity:GetPhysicsObject() + + PhysObj:EnableGravity(PhysData.Gravity) + PhysObj:EnableMotion(PhysData.Motion) + end + + local function RestoreConstraints(List) + local Constraints = duplicator.ConstraintType + + for _, Data in ipairs(List) do + local Constraint = Constraints[Data.Type] + local Args = {} + + for Index, Name in ipairs(Constraint.Args) do + Args[Index] = Data[Name] + end + + Constraint.Func(unpack(Args)) + end + end + + function ENT:Update(Data) + VerifyData(Data) + + if self.Id == Data.Id then return false, "This fuel tank is already the one you want it to update to!" end + + local Class = ACF.GetClassGroup(FuelTanks, Data.Id) + local FuelTank = Class.Lookup[Data.Id] + local Constraints = constraint.GetTable(self) + local PhysData = SavePhysObj(self) + local Feedback = "" + + UpdateFuelTank(self, Data, Class, FuelTank) + + if Class.OnUpdate then + Class.OnUpdate(self, Data, Class, FuelTank) + end + + RestorePhysObj(self, PhysData) + RestoreConstraints(Constraints) + + if next(self.Engines) then + local FuelType = self.FuelType + local Count, Total = 0, 0 + + for Engine in pairs(self.Engines) do + if not Engine.FuelTypes[FuelType] then + self:Unlink(Engine) + + Count = Count + 1 + end + + Total = Total + 1 + end + + if Count == Total then + Feedback = " Unlinked from all engines due to fuel type change." + elseif Count > 0 then + local Text = " Unlinked from %s out of %s engines due to fuel type change." + + Feedback = Text:format(Count, Total) + end + end + + net.Start("ACF_UpdateHitboxes") + net.WriteEntity(self) + net.Send(self.Owner) + + return true, "Fuel tank updated successfully!" .. Feedback + end +end --===============================================================================================-- -- Meta Funcs @@ -167,8 +272,6 @@ function ENT:ACF_Activate(Recalc) self.ACF.MaxHealth = Health self.ACF.Armour = Armour * (0.5 + Percent / 2) self.ACF.MaxArmour = Armour - self.ACF.Mass = self.Mass - self.ACF.Density = (PhysObj:GetMass() * 1000) / self.ACF.Volume self.ACF.Type = "Prop" end @@ -234,29 +337,6 @@ function ENT:Detonate() self:Remove() end -function ENT:Update(ArgsTable) - if ArgsTable[1] ~= self.Owner then return false, "You don't own that fuel tank!" end - - local FuelData = ACF.Weapons.FuelTanks[ArgsTable[5]] - - if not FuelData then return false, "Invalid fuel tank type!" end - if FuelData.model ~= self.Model then return false, "The new fuel tank must have the same model!" end - - local Feedback = "" - - if self.FuelType ~= ArgsTable[6] then - for Engine in pairs(self.Engines) do - self:Unlink(Engine) - end - - Feedback = " New fuel type loaded, fuel tank unlinked." - end - - UpdateFuelData(self, ArgsTable[4], ArgsTable[5], ArgsTable[6], FuelData) - - return true, "Fuel tank successfully updated." .. Feedback -end - function ENT:Enable() if self.Inputs.Active.Path then self.Active = tobool(self.Inputs.Active.Value) @@ -299,77 +379,82 @@ function ENT:Unlink(Target) return false, "Fuel tanks can't be unlinked from '" .. Target:GetClass() .. "'." end -function ENT:UpdateMass() - if TimerExists("ACF Mass Buffer" .. self:EntIndex()) then return end +do -- Mass Update + local function UpdateMass(Entity) + local Fuel = Entity.FuelType == "Electric" and Entity.Liters or Entity.Fuel + local Mass = math.floor(Entity.EmptyMass + Fuel * Entity.FuelDensity) + local PhysObj = Entity.ACF.PhysObj - TimerCreate("ACF Mass Buffer" .. self:EntIndex(), 5, 1, function() - if not IsValid(self) then return end - - local Fuel = self.FuelType == "Electric" and self.Liters or self.Fuel - local PhysObj = self.ACF.PhysObj - - self.Mass = math.floor(self.EmptyMass + Fuel * self.FuelDensity) - self.ACF.LegalMass = self.Mass + Entity.ACF.LegalMass = Mass + Entity.ACF.Density = Mass * 1000 / Entity.ACF.Volume if IsValid(PhysObj) then - PhysObj:SetMass(self.Mass) + PhysObj:SetMass(Mass) end - end) -end + end -local function Overlay(Ent) - local Text + function ENT:UpdateMass(Instant) + if Instant then + return UpdateMass(self) + end - if Ent.DisableReason then - Text = "Disabled: " .. Ent.DisableReason - elseif Ent.Leaking > 0 then - Text = "Leaking" - else - Text = Ent.Active and "Providing Fuel" or "Idle" + if TimerExists("ACF Mass Buffer" .. self:EntIndex()) then return end + + TimerCreate("ACF Mass Buffer" .. self:EntIndex(), 1, 1, function() + if not IsValid(self) then + UpdateMass(self) + end + end) end +end - Text = Text .. "\n\nFuel Type: " .. Ent.FuelType +do -- Overlay Update + local function Overlay(Ent) + local Text - if Ent.FuelType == "Electric" then - local KiloWatt = math.Round(Ent.Fuel, 1) - local Joules = math.Round(Ent.Fuel * 3.6, 1) + if Ent.DisableReason then + Text = "Disabled: " .. Ent.DisableReason + elseif Ent.Leaking > 0 then + Text = "Leaking" + else + Text = Ent.Active and "Providing Fuel" or "Idle" + end - Text = Text .. "\nCharge Level: " .. KiloWatt .. " kWh / " .. Joules .. " MJ" - else - local Liters = math.Round(Ent.Fuel, 1) - local Gallons = math.Round(Ent.Fuel * 0.264172, 1) + Text = Text .. "\n\nFuel Type: " .. Ent.FuelType - Text = Text .. "\nFuel Remaining: " .. Liters .. " liters / " .. Gallons .. " gallons" - end + if Ent.FuelType == "Electric" then + local KiloWatt = math.Round(Ent.Fuel, 1) + local Joules = math.Round(Ent.Fuel * 3.6, 1) - Ent:SetOverlayText(Text) -end + Text = Text .. "\nCharge Level: " .. KiloWatt .. " kWh / " .. Joules .. " MJ" + else + local Liters = math.Round(Ent.Fuel, 1) + local Gallons = math.Round(Ent.Fuel * 0.264172, 1) -function ENT:UpdateOverlay(Instant) - if Instant then - Overlay(self) - return - end + Text = Text .. "\nFuel Remaining: " .. Liters .. " liters / " .. Gallons .. " gallons" + end - if not TimerExists("ACF Overlay Buffer" .. self:EntIndex()) then - TimerCreate("ACF Overlay Buffer" .. self:EntIndex(), 1, 1, function() - if IsValid(self) then - Overlay(self) - end - end) - end -end + WireLib.TriggerOutput(Ent, "Fuel", math.Round(Ent.Fuel, 2)) + WireLib.TriggerOutput(Ent, "Capacity", math.Round(Ent.Capacity, 2)) + WireLib.TriggerOutput(Ent, "Leaking", Ent.Leaking > 0 and 1 or 0) -function ENT:UpdateOutputs() - if TimerExists("ACF Outputs Buffer" .. self:EntIndex()) then return end + Ent:SetOverlayText(Text) + end - TimerCreate("ACF Outputs Buffer" .. self:EntIndex(), 0.1, 1, function() - if not IsValid(self) then return end + function ENT:UpdateOverlay(Instant) + if Instant then + Overlay(self) + return + end - WireLib.TriggerOutput(self, "Fuel", math.Round(self.Fuel, 2)) - WireLib.TriggerOutput(self, "Capacity", math.Round(self.Capacity, 2)) - WireLib.TriggerOutput(self, "Leaking", self.Leaking > 0 and 1 or 0) - end) + if not TimerExists("ACF Overlay Buffer" .. self:EntIndex()) then + TimerCreate("ACF Overlay Buffer" .. self:EntIndex(), 1, 1, function() + if IsValid(self) then + Overlay(self) + end + end) + end + end end function ENT:TriggerInput(Input, Value) @@ -391,7 +476,6 @@ function ENT:Think() self:UpdateMass() self:UpdateOverlay() - self:UpdateOutputs() end --refuelling @@ -399,7 +483,7 @@ function ENT:Think() local MaxDist = ACF.RefillDistance * ACF.RefillDistance local SelfPos = self:GetPos() - for Tank in pairs(ACF.FuelTanks) do + for Tank in pairs(ActiveTanks) do if self.FuelType == Tank.FuelType and not Tank.SupplyFuel then local Distance = SelfPos:DistToSqr(Tank:GetPos()) @@ -418,7 +502,6 @@ function ENT:Think() Tank:UpdateMass() Tank:UpdateOverlay() - Tank:UpdateOutputs() if Tank.FuelType == "Electric" then Tank:EmitSound("ambient/energy/newspark04.wav", 75, 100, 0.5) @@ -431,7 +514,6 @@ function ENT:Think() self:UpdateMass() self:UpdateOverlay() - self:UpdateOutputs() end self.LastThink = CurTime() @@ -444,7 +526,7 @@ function ENT:OnRemove() self:Unlink(Engine) end - ACF.FuelTanks[self] = nil + ActiveTanks[self] = nil WireLib.Remove(self) end From b152dd56476329d0da118d02d7dd65c3da1c44f4 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Fri, 24 Apr 2020 13:48:09 -0400 Subject: [PATCH 075/279] Fixed unlinkable fuel tank updating - If a fuel tank is updated to an unlinkable model, all engines will be forced to unlink, no matter if the fuel type is still compatible. --- lua/entities/acf_fueltank/init.lua | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lua/entities/acf_fueltank/init.lua b/lua/entities/acf_fueltank/init.lua index 00179b5a5..101774077 100644 --- a/lua/entities/acf_fueltank/init.lua +++ b/lua/entities/acf_fueltank/init.lua @@ -216,10 +216,11 @@ do -- Spawn and Update functions if next(self.Engines) then local FuelType = self.FuelType + local NoLinks = self.NoLinks local Count, Total = 0, 0 for Engine in pairs(self.Engines) do - if not Engine.FuelTypes[FuelType] then + if NoLinks or not Engine.FuelTypes[FuelType] then self:Unlink(Engine) Count = Count + 1 @@ -229,9 +230,9 @@ do -- Spawn and Update functions end if Count == Total then - Feedback = " Unlinked from all engines due to fuel type change." + Feedback = " Unlinked from all engines due to fuel type or model change." elseif Count > 0 then - local Text = " Unlinked from %s out of %s engines due to fuel type change." + local Text = " Unlinked from %s out of %s engines due to fuel type or model change." Feedback = Text:format(Count, Total) end From bebdb555b5bc68ffdf64c86e86923d51619d0a1c Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Tue, 28 Apr 2020 00:41:09 -0400 Subject: [PATCH 076/279] Update weapon menu's rate of fire display - The weapon menu now uses the correct formula to display a weapon's rate of fire. - The rate of fire will be updated on the menu according to ammo type changes for non cyclic weapons. --- lua/acf/client/menu_items/weapons_menu.lua | 56 ++++++++++++++-------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/lua/acf/client/menu_items/weapons_menu.lua b/lua/acf/client/menu_items/weapons_menu.lua index 3307ff961..04094c73e 100644 --- a/lua/acf/client/menu_items/weapons_menu.lua +++ b/lua/acf/client/menu_items/weapons_menu.lua @@ -53,6 +53,7 @@ end local function CreateMenu(Menu) local EntText = "Mass : %s kg\nFirerate : %s rpm\nSpread : %s degrees%s" local MagText = "\nRounds : %s rounds\nReload : %s seconds" + local AmmoData local ClassList = Menu:AddComboBox() local EntList = Menu:AddComboBox() @@ -92,21 +93,33 @@ local function CreateMenu(Menu) self.Selected = Data local ClassData = ClassList.Selected - local RoundVolume = 3.1416 * (Data.Caliber * 0.05) ^ 2 * Data.Round.MaxLength - local Firerate = Data.Cyclic or 60 / (((RoundVolume * 0.002) ^ 0.6) * ClassData.ROFMod * (Data.ROFMod or 1)) - local Magazine = Data.MagSize and MagText:format(Data.MagSize, Data.MagReload) or "" - local Choices = Sorted[ClassData.Items] Selected[Choices] = Index ACF.WriteValue("Weapon", Data.ID) EntName:SetText(Data.Name) - EntData:SetText(EntText:format(Data.Mass, math.Round(Firerate, 2), ClassData.Spread * 100, Magazine)) AmmoList:UpdateMenu() end + EntData:TrackDataVar("Projectile", "SetText") + EntData:TrackDataVar("Propellant") + EntData:TrackDataVar("Tracer") + EntData:SetValueFunction(function() + local Class = ClassList.Selected + local Data = EntList.Selected + + if not Class then return "" end + if not Data then return "" end + + local ReloadTime = AmmoData and (ACF.BaseReload + (AmmoData.ProjMass + AmmoData.PropMass) * ACF.MassToTime) or 60 + local Firerate = Data.Cyclic or 60 / ReloadTime + local Magazine = Data.MagSize and MagText:format(Data.MagSize, Data.MagReload) or "" + + return EntText:format(Data.Mass, math.Round(Firerate, 2), Class.Spread * 100, Magazine) + end) + function CrateList:OnSelect(Index, _, Data) if self.Selected == Data then return end @@ -136,7 +149,8 @@ local function CreateMenu(Menu) local Ammo = self.Selected local ToolData = Ammo:GetToolData() - local Data = Ammo:ClientConvert(Menu, ToolData) + + AmmoData = Ammo:ClientConvert(Menu, ToolData) Menu:ClearTemporal(self) Menu:StartTemporal(self) @@ -150,51 +164,51 @@ local function CreateMenu(Menu) RoundLength:TrackDataVar("Tracer") RoundLength:SetValueFunction(function() local Text = "Round Length: %s / %s cm" - local CurLength = Data.ProjLength + Data.PropLength + Data.Tracer - local MaxLength = Data.MaxRoundLength + local CurLength = AmmoData.ProjLength + AmmoData.PropLength + AmmoData.Tracer + local MaxLength = AmmoData.MaxRoundLength return Text:format(CurLength, MaxLength) end) - local Projectile = Menu:AddSlider("Projectile Length", 0, Data.MaxRoundLength, 2) + local Projectile = Menu:AddSlider("Projectile Length", 0, AmmoData.MaxRoundLength, 2) Projectile:SetDataVar("Projectile", "OnValueChanged") Projectile:SetValueFunction(function(Panel, IsTracked) ToolData.Projectile = ACF.ReadNumber("Projectile") if not IsTracked then - Data.Priority = "Projectile" + AmmoData.Priority = "Projectile" end - Ammo:UpdateRoundData(ToolData, Data) + Ammo:UpdateRoundData(ToolData, AmmoData) - ACF.WriteValue("Propellant", Data.PropLength) + ACF.WriteValue("Propellant", AmmoData.PropLength) - Panel:SetValue(Data.ProjLength) + Panel:SetValue(AmmoData.ProjLength) - return Data.ProjLength + return AmmoData.ProjLength end) - local Propellant = Menu:AddSlider("Propellant Length", 0, Data.MaxRoundLength, 2) + local Propellant = Menu:AddSlider("Propellant Length", 0, AmmoData.MaxRoundLength, 2) Propellant:SetDataVar("Propellant", "OnValueChanged") Propellant:SetValueFunction(function(Panel, IsTracked) ToolData.Propellant = ACF.ReadNumber("Propellant") if not IsTracked then - Data.Priority = "Propellant" + AmmoData.Priority = "Propellant" end - Ammo:UpdateRoundData(ToolData, Data) + Ammo:UpdateRoundData(ToolData, AmmoData) - ACF.WriteValue("Projectile", Data.ProjLength) + ACF.WriteValue("Projectile", AmmoData.ProjLength) - Panel:SetValue(Data.PropLength) + Panel:SetValue(AmmoData.PropLength) - return Data.PropLength + return AmmoData.PropLength end) end if Ammo.MenuAction then - Ammo:MenuAction(Menu, ToolData, Data) + Ammo:MenuAction(Menu, ToolData, AmmoData) end Menu:EndTemporal(self) From 5694fb1e530b9dab336e36abf83db07135c3dc19 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Tue, 28 Apr 2020 00:43:05 -0400 Subject: [PATCH 077/279] Removed unused rate of fire multipliers - Removed unused rate of fire multipliers from weapon and weapon class definitions. - Removed unused rate of fire multipliers from ACF guns. --- lua/acf/shared/guns/autocannon.lua | 5 ----- lua/acf/shared/guns/autoloader.lua | 5 ----- lua/acf/shared/guns/cannon.lua | 2 -- lua/acf/shared/guns/grenadelauncher.lua | 1 - lua/acf/shared/guns/heavymachinegun.lua | 5 ----- lua/acf/shared/guns/howitzer.lua | 1 - lua/acf/shared/guns/machinegun.lua | 4 ---- lua/acf/shared/guns/mortar.lua | 2 -- lua/acf/shared/guns/rotaryautocannon.lua | 4 ---- lua/acf/shared/guns/semiauto.lua | 6 ------ lua/acf/shared/guns/shortcannon.lua | 3 --- lua/acf/shared/guns/smokelauncher.lua | 2 -- lua/entities/acf_gun/init.lua | 2 -- 13 files changed, 42 deletions(-) diff --git a/lua/acf/shared/guns/autocannon.lua b/lua/acf/shared/guns/autocannon.lua index e1b689454..1e7dfb56b 100644 --- a/lua/acf/shared/guns/autocannon.lua +++ b/lua/acf/shared/guns/autocannon.lua @@ -88,7 +88,6 @@ ACF.RegisterWeaponClass("AC", { Name = "Autocannon", Description = "Autocannons have a rather high weight and bulk for the ammo they fire, but they can fire it extremely fast.", MuzzleFlash = "auto_muzzleflash_noscale", - ROFMod = 0.85, Spread = 0.25, Sound = "weapons/ACF_Gun/ac_fire4.mp3", Caliber = { @@ -104,7 +103,6 @@ ACF.RegisterWeapon("20mmAC", "AC", { Caliber = 20, Mass = 500, Year = 1930, - ROFMod = 0.7, MagSize = 100, MagReload = 15, Cyclic = 250, @@ -121,7 +119,6 @@ ACF.RegisterWeapon("30mmAC", "AC", { Caliber = 30, Mass = 1000, Year = 1935, - ROFMod = 0.5, MagSize = 75, MagReload = 20, Cyclic = 225, @@ -138,7 +135,6 @@ ACF.RegisterWeapon("40mmAC", "AC", { Caliber = 40, Mass = 1500, Year = 1940, - ROFMod = 0.48, MagSize = 30, MagReload = 25, Cyclic = 200, @@ -155,7 +151,6 @@ ACF.RegisterWeapon("50mmAC", "AC", { Caliber = 50, Mass = 2000, Year = 1965, - ROFMod = 0.4, MagSize = 25, MagReload = 30, Cyclic = 175, diff --git a/lua/acf/shared/guns/autoloader.lua b/lua/acf/shared/guns/autoloader.lua index d6f874d1c..9bc54370d 100644 --- a/lua/acf/shared/guns/autoloader.lua +++ b/lua/acf/shared/guns/autoloader.lua @@ -107,7 +107,6 @@ ACF.RegisterWeaponClass("AL", { Name = "Autoloader", Description = "A cannon with attached autoloading mechanism. While it allows for several quick shots, the mechanism adds considerable bulk, weight, and magazine reload time.", MuzzleFlash = "cannon_muzzleflash_noscale", - ROFMod = 0.64, Spread = 0.08, Sound = "weapons/ACF_Gun/autoloader.mp3", Caliber = { @@ -123,7 +122,6 @@ ACF.RegisterWeapon("75mmAL", "AL", { Caliber = 75, Mass = 1892, Year = 1946, - ROFMod = 1, MagSize = 8, MagReload = 15, Cyclic = 30, @@ -140,7 +138,6 @@ ACF.RegisterWeapon("100mmAL", "AL", { Caliber = 100, Mass = 3325, Year = 1956, - ROFMod = 0.85, MagSize = 6, MagReload = 21, Cyclic = 18, @@ -157,7 +154,6 @@ ACF.RegisterWeapon("120mmAL", "AL", { Caliber = 120, Mass = 6050, Year = 1956, - ROFMod = 0.757, MagSize = 5, MagReload = 27, Cyclic = 11, @@ -174,7 +170,6 @@ ACF.RegisterWeapon("140mmAL", "AL", { Caliber = 140, Mass = 8830, Year = 1970, - ROFMod = 0.743, MagSize = 5, MagReload = 35, Cyclic = 8, diff --git a/lua/acf/shared/guns/cannon.lua b/lua/acf/shared/guns/cannon.lua index 599ea92cb..40bc2a92d 100644 --- a/lua/acf/shared/guns/cannon.lua +++ b/lua/acf/shared/guns/cannon.lua @@ -119,7 +119,6 @@ ACF.RegisterWeaponClass("C", { Name = "Cannon", Description = "High velocity guns that can fire very powerful ammunition, but are rather slow to reload.", MuzzleFlash = "cannon_muzzleflash_noscale", - ROFMod = 2, Spread = 0.08, Sound = "weapons/ACF_Gun/cannon_new.mp3", Caliber = { @@ -135,7 +134,6 @@ ACF.RegisterWeapon("37mmC", "C", { Caliber = 37, Mass = 350, Year = 1919, - ROFMod = 1.4, Sound = "weapons/ACF_Gun/ac_fire4.mp3", Round = { MaxLength = 48, diff --git a/lua/acf/shared/guns/grenadelauncher.lua b/lua/acf/shared/guns/grenadelauncher.lua index 04a2c1381..38371e0a5 100644 --- a/lua/acf/shared/guns/grenadelauncher.lua +++ b/lua/acf/shared/guns/grenadelauncher.lua @@ -32,7 +32,6 @@ ACF.RegisterWeaponClass("GL", { Name = "Grenade Launcher", Description = "Grenade Launchers can fire shells with relatively large payloads at a fast rate, but with very limited velocities and poor accuracy.", MuzzleFlash = "gl_muzzleflash_noscale", - ROFMod = 1, Spread = 0.32, Sound = "weapons/acf_gun/grenadelauncher.mp3", Caliber = { diff --git a/lua/acf/shared/guns/heavymachinegun.lua b/lua/acf/shared/guns/heavymachinegun.lua index de78b0f0c..5c3c6f259 100644 --- a/lua/acf/shared/guns/heavymachinegun.lua +++ b/lua/acf/shared/guns/heavymachinegun.lua @@ -92,7 +92,6 @@ ACF.RegisterWeaponClass("HMG", { Name = "Heavy Machinegun", Description = "Designed as autocannons for aircraft, HMGs are rapid firing, lightweight, and compact but sacrifice accuracy, magazine size, and reload times.", MuzzleFlash = "mg_muzzleflash_noscale", - ROFMod = 0.14, Spread = 1.3, Sound = "weapons/ACF_Gun/mg_fire3.mp3", Caliber = { @@ -113,7 +112,6 @@ ACF.RegisterWeapon("13mmHMG", "HMG", { Caliber = 13, Mass = 90, Year = 1935, - ROFMod = 3.3, MagSize = 35, MagReload = 6, Cyclic = 550, @@ -130,7 +128,6 @@ ACF.RegisterWeapon("20mmHMG", "HMG", { Caliber = 20, Mass = 160, Year = 1935, - ROFMod = 1.9, MagSize = 30, MagReload = 6, Cyclic = 525, @@ -147,7 +144,6 @@ ACF.RegisterWeapon("30mmHMG", "HMG", { Caliber = 30, Mass = 480, Year = 1941, - ROFMod = 1.1, MagSize = 25, MagReload = 6, Cyclic = 500, @@ -164,7 +160,6 @@ ACF.RegisterWeapon("40mmHMG", "HMG", { Caliber = 40, Mass = 780, Year = 1955, - ROFMod = 0.95, MagSize = 20, MagReload = 8, Cyclic = 475, diff --git a/lua/acf/shared/guns/howitzer.lua b/lua/acf/shared/guns/howitzer.lua index c1a2cac20..eca3dcf4b 100644 --- a/lua/acf/shared/guns/howitzer.lua +++ b/lua/acf/shared/guns/howitzer.lua @@ -116,7 +116,6 @@ ACF.RegisterWeaponClass("HW", { Name = "Howitzer", Description = "Howitzers are limited to rather mediocre muzzle velocities, but can fire extremely heavy projectiles with large useful payload capacities.", MuzzleFlash = "howie_muzzleflash_noscale", - ROFMod = 1.8, Spread = 0.12, Sound = "weapons/ACF_Gun/howitzer_new2.mp3", Caliber = { diff --git a/lua/acf/shared/guns/machinegun.lua b/lua/acf/shared/guns/machinegun.lua index 689311ab4..954247c21 100644 --- a/lua/acf/shared/guns/machinegun.lua +++ b/lua/acf/shared/guns/machinegun.lua @@ -70,7 +70,6 @@ ACF.RegisterWeaponClass("MG", { Name = "Machinegun", Description = "Machineguns are light guns that fire equally light bullets at a fast rate.", MuzzleFlash = "mg_muzzleflash_noscale", - ROFMod = 0.9, Spread = 0.24, Sound = "weapons/ACF_Gun/mg_fire4.mp3", Caliber = { @@ -86,7 +85,6 @@ ACF.RegisterWeapon("7.62mmMG", "MG", { Caliber = 7.62, Mass = 15, Year = 1930, - ROFMod = 1.59, MagSize = 250, MagReload = 6, Cyclic = 700, -- Rounds per minute @@ -103,7 +101,6 @@ ACF.RegisterWeapon("12.7mmMG", "MG", { Caliber = 12.7, Mass = 30, Year = 1910, - ROFMod = 1, MagSize = 150, MagReload = 6, Cyclic = 600, @@ -120,7 +117,6 @@ ACF.RegisterWeapon("14.5mmMG", "MG", { Caliber = 14.5, Mass = 45, Year = 1932, - ROFMod = 1, MagSize = 90, MagReload = 5, Cyclic = 500, diff --git a/lua/acf/shared/guns/mortar.lua b/lua/acf/shared/guns/mortar.lua index eec670ddc..5b6d0e683 100644 --- a/lua/acf/shared/guns/mortar.lua +++ b/lua/acf/shared/guns/mortar.lua @@ -103,7 +103,6 @@ ACF.RegisterWeaponClass("MO", { Name = "Mortar", Description = "Mortars are able to fire shells with usefull payloads from a light weight gun, at the price of limited velocities.", MuzzleFlash = "mortar_muzzleflash_noscale", - ROFMod = 2.5, Spread = 0.64, Sound = "weapons/ACF_Gun/mortar_new.mp3", Caliber = { @@ -119,7 +118,6 @@ ACF.RegisterWeapon("60mmM", "MO", { Caliber = 60, Mass = 60, Year = 1930, - ROFMod = 1.25, Round = { MaxLength = 20, PropMass = 0.037, diff --git a/lua/acf/shared/guns/rotaryautocannon.lua b/lua/acf/shared/guns/rotaryautocannon.lua index 0b121985f..6df1ef3fa 100644 --- a/lua/acf/shared/guns/rotaryautocannon.lua +++ b/lua/acf/shared/guns/rotaryautocannon.lua @@ -70,8 +70,6 @@ ACF.RegisterWeaponClass("RAC", { Name = "Rotary Autocannon", Description = "Rotary Autocannons sacrifice weight, bulk and accuracy over classic autocannons to get the highest rate of fire possible.", MuzzleFlash = "mg_muzzleflash_noscale", - ROFMod = 0.07, - Spread = 0.4, Sound = "weapons/acf_gun/mg_fire3.mp3", Caliber = { @@ -87,7 +85,6 @@ ACF.RegisterWeapon("20mmRAC", "RAC", { Caliber = 20, Mass = 760, Year = 1965, - ROFMod = 2.1, MagSize = 200, MagReload = 25, Cyclic = 4000, @@ -104,7 +101,6 @@ ACF.RegisterWeapon("30mmRAC", "RAC", { Caliber = 30, Mass = 1500, Year = 1975, - ROFMod = 1, MagSize = 100, MagReload = 35, Cyclic = 3000, diff --git a/lua/acf/shared/guns/semiauto.lua b/lua/acf/shared/guns/semiauto.lua index 1d13abd9c..3318a44d6 100644 --- a/lua/acf/shared/guns/semiauto.lua +++ b/lua/acf/shared/guns/semiauto.lua @@ -106,7 +106,6 @@ ACF.RegisterWeaponClass("SA", { Name = "Semiautomatic Cannon", Description = "Semiautomatic cannons offer light weight, small size, and high rates of fire at the cost of often reloading and low accuracy.", MuzzleFlash = "semi_muzzleflash_noscale", - ROFMod = 0.36, Spread = 1.1, Sound = "weapons/acf_gun/sa_fire1.mp3", Caliber = { @@ -122,7 +121,6 @@ ACF.RegisterWeapon("25mmSA", "SA", { Caliber = 25, Mass = 250, Year = 1935, - ROFMod = 0.7, MagSize = 5, MagReload = 2.5, Cyclic = 300, @@ -139,7 +137,6 @@ ACF.RegisterWeapon("37mmSA", "SA", { Caliber = 37, Mass = 500, Year = 1940, - ROFMod = 0.7, MagSize = 5, MagReload = 3.7, Cyclic = 250, @@ -156,7 +153,6 @@ ACF.RegisterWeapon("45mmSA", "SA", { Caliber = 45, Mass = 750, Year = 1965, - ROFMod = 0.72, MagSize = 5, MagReload = 4.5, Cyclic = 225, @@ -173,7 +169,6 @@ ACF.RegisterWeapon("57mmSA", "SA", { Caliber = 57, Mass = 1000, Year = 1965, - ROFMod = 0.8, MagSize = 5, MagReload = 5.7, Cyclic = 200, @@ -190,7 +185,6 @@ ACF.RegisterWeapon("76mmSA", "SA", { Caliber = 76.2, Mass = 2000, Year = 1984, - ROFMod = 0.85, MagSize = 5, MagReload = 7.6, Cyclic = 150, diff --git a/lua/acf/shared/guns/shortcannon.lua b/lua/acf/shared/guns/shortcannon.lua index 95af09d21..a6dd30b50 100644 --- a/lua/acf/shared/guns/shortcannon.lua +++ b/lua/acf/shared/guns/shortcannon.lua @@ -103,7 +103,6 @@ ACF.RegisterWeaponClass("SC", { Name = "Short-Barrelled Cannon", Description = "Short cannons trade muzzle velocity and accuracy for lighter weight and smaller size, with more penetration than howitzers and lighter than cannons.", MuzzleFlash = "cannon_muzzleflash_noscale", - ROFMod = 1.7, Spread = 0.2, Sound = "weapons/ACF_Gun/cannon_new.mp3", Caliber = { @@ -118,7 +117,6 @@ ACF.RegisterWeapon("37mmSC", "SC", { Model = "models/tankgun/tankgun_short_37mm.mdl", Caliber = 37, Mass = 200, - ROFMod = 1.4, Year = 1915, Sound = "weapons/ACF_Gun/ac_fire4.mp3", Round = { @@ -133,7 +131,6 @@ ACF.RegisterWeapon("50mmSC", "SC", { Model = "models/tankgun/tankgun_short_50mm.mdl", Caliber = 50, Mass = 330, - ROFMod = 1.4, Year = 1915, Sound = "weapons/ACF_Gun/ac_fire4.mp3", Round = { diff --git a/lua/acf/shared/guns/smokelauncher.lua b/lua/acf/shared/guns/smokelauncher.lua index bd7e6293b..82d74bcd2 100644 --- a/lua/acf/shared/guns/smokelauncher.lua +++ b/lua/acf/shared/guns/smokelauncher.lua @@ -55,7 +55,6 @@ ACF.RegisterWeaponClass("SL", { Name = "Smoke Launcher", Description = "Smoke launcher to block an attacker's line of sight.", MuzzleFlash = "gl_muzzleflash_noscale", - ROFMod = 45, Spread = 0.32, Sound = "weapons/acf_gun/smoke_launch.mp3", LimitConVar = { @@ -91,7 +90,6 @@ ACF.RegisterWeapon("40mmCL", "SL", { Model = "models/launcher/40mmgl.mdl", Caliber = 40, Mass = 20, - ROFMod = 0.015, Year = 1950, MagSize = 6, MagReload = 40, diff --git a/lua/entities/acf_gun/init.lua b/lua/entities/acf_gun/init.lua index dc8131b24..ab426532e 100644 --- a/lua/entities/acf_gun/init.lua +++ b/lua/entities/acf_gun/init.lua @@ -70,8 +70,6 @@ do -- Spawn and Update functions -------------------------------- Entity.ReloadTime = Entity.Cyclic or 1 Entity.Spread = Class.Spread Entity.MinLengthBonus = 0.75 * 3.1416 * (Caliber * 0.5) ^ 2 * Weapon.Round.MaxLength - Entity.PGRoFmod = math.max(0.01, Weapon.ROFMod or 1) - Entity.RoFmod = Class.ROFMod Entity.HitBoxes = ACF.HitBoxes[Weapon.Model] Entity.Long = Class.LongBarrel Entity.NormalMuzzle = Entity:WorldToLocal(Entity:GetAttachment(Entity:LookupAttachment("muzzle")).Pos) From 9c82b6b9a006d3046016bf90badadd9b95bdf3de Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Tue, 28 Apr 2020 00:44:41 -0400 Subject: [PATCH 078/279] Ported readded ammo types and smoothbores - Ported APCR, APDS, AFSDS and HEATFS ammo types to the new definition format. - Ported smoothbore cannons to the new definition format. --- lua/acf/shared/ammo_types/apcr.lua | 54 ++++++++++++++++++++++++ lua/acf/shared/ammo_types/apds.lua | 53 ++++++++++++++++++++++++ lua/acf/shared/ammo_types/apfsds.lua | 51 +++++++++++++++++++++++ lua/acf/shared/ammo_types/heatfs.lua | 62 ++++++++++++++++++++++++++++ lua/acf/shared/guns/smoothbore.lua | 53 +++++++++++++++++++++++- 5 files changed, 272 insertions(+), 1 deletion(-) create mode 100644 lua/acf/shared/ammo_types/apcr.lua create mode 100644 lua/acf/shared/ammo_types/apds.lua create mode 100644 lua/acf/shared/ammo_types/apfsds.lua create mode 100644 lua/acf/shared/ammo_types/heatfs.lua diff --git a/lua/acf/shared/ammo_types/apcr.lua b/lua/acf/shared/ammo_types/apcr.lua new file mode 100644 index 000000000..d13284fa7 --- /dev/null +++ b/lua/acf/shared/ammo_types/apcr.lua @@ -0,0 +1,54 @@ +local Ammo = ACF.RegisterAmmoType("APCR", "AP") + +function Ammo:OnLoaded() + Ammo.BaseClass.OnLoaded(self) + + self.Name = "Armor Piercing Composite Rigid" + self.Description = "A hardened core munition designed for weapons in the 1940s." + self.Blacklist = ACF.GetWeaponBlacklist({ + AL = true, + AC = true, + SA = true, + SC = true, + C = true, + }) +end + +function Ammo:UpdateRoundData(ToolData, Data, GUIData) + GUIData = GUIData or Data + + ACF.UpdateRoundSpecs(ToolData, Data, GUIData) + + Data.ProjMass = Data.FrArea * Data.ProjLength * 0.0079 * 1.1111 --Volume of the projectile as a cylinder * density of steel + Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass) * 1.2 + Data.DragCoef = Data.FrArea * 0.0001 / Data.ProjMass + + for K, V in pairs(self:GetDisplayData(Data)) do + GUIData[K] = V + end +end + +function Ammo:BaseConvert(_, ToolData) + if not ToolData.Projectile then ToolData.Projectile = 0 end + if not ToolData.Propellant then ToolData.Propellant = 0 end + + local Data, GUIData = ACF.RoundBaseGunpowder(ToolData, {}) + + Data.ShovePower = 0.2 + Data.PenArea = Data.FrArea ^ ACF.PenAreaMod + Data.LimitVel = 1000 --Most efficient penetration speed in m/s + Data.KETransfert = 0.1 --Kinetic energy transfert to the target for movement purposes + Data.Ricochet = 55 --Base ricochet angle + + self:UpdateRoundData(ToolData, Data, GUIData) + + return Data, GUIData +end + +function Ammo:Network(Crate, BulletData) + Ammo.BaseClass.Network(self, Crate, BulletData) + + Crate:SetNW2String("AmmoType", "APCR") +end + +ACF.RegisterAmmoDecal("APCR", "damage/apcr_pen", "damage/apcr_rico") diff --git a/lua/acf/shared/ammo_types/apds.lua b/lua/acf/shared/ammo_types/apds.lua new file mode 100644 index 000000000..869d92d04 --- /dev/null +++ b/lua/acf/shared/ammo_types/apds.lua @@ -0,0 +1,53 @@ +local Ammo = ACF.RegisterAmmoType("APDS", "AP") + +function Ammo:OnLoaded() + Ammo.BaseClass.OnLoaded(self) + + self.Name = "Armor Piercing Discarging Sabot" + self.Description = "A subcaliber munition designed to trade damage for penetration. Loses energy quickly over distance." + self.Blacklist = ACF.GetWeaponBlacklist({ + AL = true, + AC = true, + SA = true, + C = true, + }) +end + +function Ammo:UpdateRoundData(ToolData, Data, GUIData) + GUIData = GUIData or Data + + ACF.UpdateRoundSpecs(ToolData, Data, GUIData) + + Data.ProjMass = Data.FrArea * Data.ProjLength * 0.0079 --Volume of the projectile as a cylinder * density of steel + Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass) * 1.2 + Data.DragCoef = Data.FrArea * 0.0001 / Data.ProjMass + + for K, V in pairs(self:GetDisplayData(Data)) do + GUIData[K] = V + end +end + +function Ammo:BaseConvert(_, ToolData) + if not ToolData.Projectile then ToolData.Projectile = 0 end + if not ToolData.Propellant then ToolData.Propellant = 0 end + + local Data, GUIData = ACF.RoundBaseGunpowder(ToolData, {}) + + Data.ShovePower = 0.2 + Data.PenArea = Data.FrArea ^ ACF.PenAreaMod + Data.LimitVel = 1000 --Most efficient penetration speed in m/s + Data.KETransfert = 0.1 --Kinetic energy transfert to the target for movement purposes + Data.Ricochet = 65 --Base ricochet angle + + self:UpdateRoundData(ToolData, Data, GUIData) + + return Data, GUIData +end + +function Ammo:Network(Crate, BulletData) + Ammo.BaseClass.Network(self, Crate, BulletData) + + Crate:SetNW2String("AmmoType", "APDS") +end + +ACF.RegisterAmmoDecal("APDS", "damage/apcr_pen", "damage/apcr_rico") diff --git a/lua/acf/shared/ammo_types/apfsds.lua b/lua/acf/shared/ammo_types/apfsds.lua new file mode 100644 index 000000000..456c25ffe --- /dev/null +++ b/lua/acf/shared/ammo_types/apfsds.lua @@ -0,0 +1,51 @@ +local Ammo = ACF.RegisterAmmoType("APFSDS", "AP") + +function Ammo:OnLoaded() + Ammo.BaseClass.OnLoaded(self) + + self.Name = "Armor Piercing Fin Stabilized" + self.Model = "models/munitions/dart_100mm.mdl" + self.Description = "A fin stabilized sabot munition designed to trade damage for superior penetration and long range effectiveness." + self.Blacklist = ACF.GetWeaponBlacklist({ + SB = true, + }) +end + +function Ammo:UpdateRoundData(ToolData, Data, GUIData) + GUIData = GUIData or Data + + ACF.UpdateRoundSpecs(ToolData, Data, GUIData) + + Data.ProjMass = Data.FrArea * Data.ProjLength * 0.0079 * 0.6666 --Volume of the projectile as a cylinder * density of steel + Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass) * 1.5 + Data.DragCoef = Data.FrArea * 0.0001 / Data.ProjMass + + for K, V in pairs(self:GetDisplayData(Data)) do + GUIData[K] = V + end +end + +function Ammo:BaseConvert(_, ToolData) + if not ToolData.Projectile then ToolData.Projectile = 0 end + if not ToolData.Propellant then ToolData.Propellant = 0 end + + local Data, GUIData = ACF.RoundBaseGunpowder(ToolData, {}) + + Data.ShovePower = 0.2 + Data.PenArea = Data.FrArea ^ ACF.PenAreaMod + Data.LimitVel = 1200 --Most efficient penetration speed in m/s + Data.KETransfert = 0.1 --Kinetic energy transfert to the target for movement purposes + Data.Ricochet = 75 --Base ricochet angle + + self:UpdateRoundData(ToolData, Data, GUIData) + + return Data, GUIData +end + +function Ammo:Network(Crate, BulletData) + Ammo.BaseClass.Network(self, Crate, BulletData) + + Crate:SetNW2String("AmmoType", "APFSDS") +end + +ACF.RegisterAmmoDecal("APFSDS", "damage/apcr_pen", "damage/apcr_rico") diff --git a/lua/acf/shared/ammo_types/heatfs.lua b/lua/acf/shared/ammo_types/heatfs.lua new file mode 100644 index 000000000..77fd7e393 --- /dev/null +++ b/lua/acf/shared/ammo_types/heatfs.lua @@ -0,0 +1,62 @@ +local Ammo = ACF.RegisterAmmoType("HEATFS", "HEAT") + +function Ammo:OnLoaded() + Ammo.BaseClass.OnLoaded(self) + + self.Name = "High Explosive Anti-Tank Fin Stabilized" + self.Description = "An improved HEAT round with higher penetration and muzzle velocity." + self.Blacklist = ACF.GetWeaponBlacklist({ + SB = true, + }) +end + +function Ammo:UpdateRoundData(ToolData, Data, GUIData) + GUIData = GUIData or Data + + ACF.UpdateRoundSpecs(ToolData, Data, GUIData) + + local MaxConeAng = math.deg(math.atan((Data.ProjLength - Data.Caliber * 0.002) / (Data.Caliber * 0.05))) + local LinerAngle = math.Clamp(ToolData.LinerAngle, GUIData.MinConeAng, MaxConeAng) + local _, ConeArea, AirVol = self:ConeCalc(LinerAngle, Data.Caliber * 0.05) + + local LinerRad = math.rad(LinerAngle * 0.5) + local SlugCaliber = Data.Caliber * 0.1 - Data.Caliber * (math.sin(LinerRad) * 0.5 + math.cos(LinerRad) * 1.5) * 0.05 + local SlugFrArea = 3.1416 * (SlugCaliber * 0.5) ^ 2 + local ConeVol = ConeArea * Data.Caliber * 0.002 + local ProjMass = math.max(GUIData.ProjVolume - ToolData.FillerMass, 0) * 0.0079 + math.min(ToolData.FillerMass, GUIData.ProjVolume) * ACF.HEDensity * 0.001 + ConeVol * 0.0079 --Volume of the projectile as a cylinder - Volume of the filler - Volume of the crush cone * density of steel + Volume of the filler * density of TNT + Area of the cone * thickness * density of steel + local MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, ProjMass) + local Energy = ACF_Kinetic(MuzzleVel * 39.37, ProjMass, Data.LimitVel) + local MaxVol = ACF.RoundShellCapacity(Energy.Momentum, Data.FrArea, Data.Caliber, Data.ProjLength) + + GUIData.MaxConeAng = MaxConeAng + GUIData.MaxFillerVol = math.max(math.Round(MaxVol - AirVol - ConeVol, 2), GUIData.MinFillerVol) + GUIData.FillerVol = math.Clamp(ToolData.FillerMass, GUIData.MinFillerVol, GUIData.MaxFillerVol) + + Data.ConeAng = LinerAngle + Data.FillerMass = GUIData.FillerVol * ACF.HEDensity * 0.00069 + Data.ProjMass = math.max(GUIData.ProjVolume - GUIData.FillerVol - AirVol - ConeVol, 0) * 0.0079 + Data.FillerMass + ConeVol * 0.0079 + Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass) * 1.25 + Data.SlugMass = ConeVol * 0.0079 + Data.SlugCaliber = SlugCaliber + Data.SlugPenArea = (SlugFrArea ^ ACF.PenAreaMod) * 0.6666 + Data.SlugDragCoef = SlugFrArea * 0.0001 / Data.SlugMass + + local _, HEATFiller, BoomFiller = self:CrushCalc(Data.MuzzleVel, Data.FillerMass) + + Data.BoomFillerMass = BoomFiller + Data.SlugMV = self:CalcSlugMV(Data, HEATFiller) + Data.CasingMass = Data.ProjMass - Data.FillerMass - ConeVol * 0.0079 + Data.DragCoef = Data.FrArea * 0.0001 / Data.ProjMass + + for K, V in pairs(self:GetDisplayData(Data)) do + GUIData[K] = V + end +end + +function Ammo:Network(Crate, BulletData) + Ammo.BaseClass.Network(self, Crate, BulletData) + + Crate:SetNW2String("AmmoType", "HEATFS") +end + +ACF.RegisterAmmoDecal("HEATFS", "damage/heat_pen", "damage/heat_rico", function(Caliber) return Caliber * 0.1667 end) diff --git a/lua/acf/shared/guns/smoothbore.lua b/lua/acf/shared/guns/smoothbore.lua index 30c4573b9..2c9d5eb5e 100644 --- a/lua/acf/shared/guns/smoothbore.lua +++ b/lua/acf/shared/guns/smoothbore.lua @@ -69,4 +69,55 @@ ACF_defineGun("170mmC", { propweight = 34 } } ) -]]-- \ No newline at end of file +]]-- + +ACF.RegisterWeaponClass("SB", { + Name = "Smoothbore Cannon", + Description = "More modern smoothbore cannons that can only fire munitions that do not rely on spinning for accuracy.", + MuzzleFlash = "cannon_muzzleflash_noscale", + Spread = 0.08, + Sound = "weapons/ACF_Gun/cannon_new.mp3", + Caliber = { + Min = 20, + Max = 140, + }, +}) + +ACF.RegisterWeapon("105mmSB", "SB", { + Name = "105mm Smoothbore Cannon", + Description = "The 105mm was a benchmark for the early cold war period, and has great muzzle velocity and hitting power, while still boasting a respectable, if small, payload.", + Model = "models/tankgun_old/tankgun_100mm.mdl", + Caliber = 105, + Mass = 3550, + Year = 1970, + Round = { + MaxLength = 101, + PropMass = 9, + } +}) + +ACF.RegisterWeapon("120mmSB", "SB", { + Name = "120mm Smoothbore Cannon", + Description = "Often found in MBTs, the 120mm shreds lighter armor with utter impunity, and is formidable against even the big boys.", + Model = "models/tankgun_old/tankgun_120mm.mdl", + Caliber = 120, + Mass = 6000, + Year = 1975, + Round = { + MaxLength = 145, + PropMass = 18, + } +}) + +ACF.RegisterWeapon("140mmSB", "SB", { + Name = "140mm Smoothbore Cannon", + Description = "The 140mm fires a massive shell with enormous penetrative capability, but has a glacial reload speed and a very hefty weight.", + Model = "models/tankgun_old/tankgun_140mm.mdl", + Caliber = 140, + Mass = 8980, + Year = 1990, + Round = { + MaxLength = 145, + PropMass = 28, + } +}) From 9cd87a42222ac27141ef15d16170b821fffdbeb2 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Thu, 30 Apr 2020 03:50:14 -0400 Subject: [PATCH 079/279] Improved new ACF Menu CanTool - Whenever the new menu attempts to check if the tool can be used on something, it'll try to use CPPICanTool or just call the CanTool hook if the previous is not available. --- lua/acf/shared/tool_operations/acf_menu.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lua/acf/shared/tool_operations/acf_menu.lua b/lua/acf/shared/tool_operations/acf_menu.lua index a44c1bb62..85bcf0dbf 100644 --- a/lua/acf/shared/tool_operations/acf_menu.lua +++ b/lua/acf/shared/tool_operations/acf_menu.lua @@ -43,9 +43,9 @@ end local function CanTool(Player, Entity) if not IsValid(Entity) then return false end - if not CPPI then return true end + if CPPI then return Entity:CPPICanTool(Player, "acf_menu2") end - return Entity:CPPICanTool(Player, "#Tool.acf_menu2.name") + return hook.Run("CanTool", Player, { Hit = true, Entity = Entity }, "acf_menu2") end do -- Spawner operation From 7b2bf0a9102b9d7061a7e4fc7343e2953a7d85b8 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Thu, 30 Apr 2020 03:52:37 -0400 Subject: [PATCH 080/279] Added ACF.SaveEntity and ACF.RestoreEntity - Added ACF.SaveEntity and ACF.RestoreEntity for cases like entity updating. - Now every entity that can be fully updated will use these functions. --- lua/acf/base/util/sv_util.lua | 47 ++++++++++++++++++++++++++++++ lua/entities/acf_engine/init.lua | 41 ++++---------------------- lua/entities/acf_fueltank/init.lua | 40 +++---------------------- lua/entities/acf_gun/init.lua | 40 +++---------------------- 4 files changed, 60 insertions(+), 108 deletions(-) diff --git a/lua/acf/base/util/sv_util.lua b/lua/acf/base/util/sv_util.lua index c5741c8f5..bc0ddd74e 100644 --- a/lua/acf/base/util/sv_util.lua +++ b/lua/acf/base/util/sv_util.lua @@ -139,6 +139,53 @@ do -- Tool data functions end end +do -- Entity saving and restoring + local Constraints = duplicator.ConstraintType + local Saved = {} + + function ACF.SaveEntity(Entity) + if not IsValid(Entity) then return end + + local PhysObj = Entity:GetPhysicsObject() + + Saved[Entity] = { + Constraints = constraint.GetTable(Entity), + Gravity = PhysObj:IsGravityEnabled(), + Motion = PhysObj:IsMotionEnabled(), + } + + Entity:CallOnRemove("ACF_RestoreEntity", function() + Saved[Entity] = nil + end) + end + + function ACF.RestoreEntity(Entity) + if not IsValid(Entity) then return end + if not Saved[Entity] then return end + + local PhysObj = Entity:GetPhysicsObject() + local EntData = Saved[Entity] + + PhysObj:EnableGravity(EntData.Gravity) + PhysObj:EnableMotion(EntData.Motion) + + for _, Data in ipairs(EntData.Constraints) do + local Constraint = Constraints[Data.Type] + local Args = {} + + for Index, Name in ipairs(Constraint.Args) do + Args[Index] = Data[Name] + end + + Constraint.Func(unpack(Args)) + end + + Saved[Entity] = nil + + Entity:RemoveCallOnRemove("ACF_RestoreEntity") + end +end + function ACF_GetHitAngle(HitNormal, HitVector) return math.min(math.deg(math.acos(HitNormal:Dot(-HitVector:GetNormalized()))), 89.999) end \ No newline at end of file diff --git a/lua/entities/acf_engine/init.lua b/lua/entities/acf_engine/init.lua index 42568d704..d53bf0d2b 100644 --- a/lua/entities/acf_engine/init.lua +++ b/lua/entities/acf_engine/init.lua @@ -386,36 +386,7 @@ do -- Spawn and Update functions ACF.RegisterLinkSource("acf_engine", "FuelTanks") ACF.RegisterLinkSource("acf_engine", "Gearboxes") - local function SavePhysObj(Entity) - local PhysObj = Entity:GetPhysicsObject() - - return { - Gravity = PhysObj:IsGravityEnabled(), - Motion = PhysObj:IsMotionEnabled(), - } - end - - local function RestorePhysObj(Entity, PhysData) - local PhysObj = Entity:GetPhysicsObject() - - PhysObj:EnableGravity(PhysData.Gravity) - PhysObj:EnableMotion(PhysData.Motion) - end - - local function RestoreConstraints(List) - local Constraints = duplicator.ConstraintType - - for _, Data in ipairs(List) do - local Constraint = Constraints[Data.Type] - local Args = {} - - for Index, Name in ipairs(Constraint.Args) do - Args[Index] = Data[Name] - end - - Constraint.Func(unpack(Args)) - end - end + ------------------- Updating --------------------- function ENT:Update(Data) if self.Active then return false, "Turn off the engine before updating it!" end @@ -426,19 +397,18 @@ do -- Spawn and Update functions local Class = ACF.GetClassGroup(Engines, Data.Id) local EngineData = Class.Lookup[Data.Id] - local Constraints = constraint.GetTable(self) - local PhysData = SavePhysObj(self) local Feedback = "" + ACF.SaveEntity(self) + UpdateEngine(self, Data, Class, EngineData) + ACF.RestoreEntity(self) + if Class.OnUpdate then Class.OnUpdate(self, Data, Class, EngineData) end - RestorePhysObj(self, PhysData) - RestoreConstraints(Constraints) - if next(self.Gearboxes) then local Count, Total = 0, 0 @@ -699,7 +669,6 @@ function ENT:CalcRPM() FuelTank.Fuel = max(FuelTank.Fuel - Consumption, 0) FuelTank:UpdateMass() FuelTank:UpdateOverlay() - FuelTank:UpdateOutputs() elseif self.RequiresFuel then SetActive(self, false) --shut off if no fuel and requires it diff --git a/lua/entities/acf_fueltank/init.lua b/lua/entities/acf_fueltank/init.lua index 101774077..238962d71 100644 --- a/lua/entities/acf_fueltank/init.lua +++ b/lua/entities/acf_fueltank/init.lua @@ -163,37 +163,6 @@ do -- Spawn and Update functions ------------------- Updating --------------------- - local function SavePhysObj(Entity) - local PhysObj = Entity:GetPhysicsObject() - - return { - Gravity = PhysObj:IsGravityEnabled(), - Motion = PhysObj:IsMotionEnabled(), - } - end - - local function RestorePhysObj(Entity, PhysData) - local PhysObj = Entity:GetPhysicsObject() - - PhysObj:EnableGravity(PhysData.Gravity) - PhysObj:EnableMotion(PhysData.Motion) - end - - local function RestoreConstraints(List) - local Constraints = duplicator.ConstraintType - - for _, Data in ipairs(List) do - local Constraint = Constraints[Data.Type] - local Args = {} - - for Index, Name in ipairs(Constraint.Args) do - Args[Index] = Data[Name] - end - - Constraint.Func(unpack(Args)) - end - end - function ENT:Update(Data) VerifyData(Data) @@ -201,19 +170,18 @@ do -- Spawn and Update functions local Class = ACF.GetClassGroup(FuelTanks, Data.Id) local FuelTank = Class.Lookup[Data.Id] - local Constraints = constraint.GetTable(self) - local PhysData = SavePhysObj(self) local Feedback = "" + ACF.SaveEntity(self) + UpdateFuelTank(self, Data, Class, FuelTank) + ACF.RestoreEntity(self) + if Class.OnUpdate then Class.OnUpdate(self, Data, Class, FuelTank) end - RestorePhysObj(self, PhysData) - RestoreConstraints(Constraints) - if next(self.Engines) then local FuelType = self.FuelType local NoLinks = self.NoLinks diff --git a/lua/entities/acf_gun/init.lua b/lua/entities/acf_gun/init.lua index ab426532e..631502c42 100644 --- a/lua/entities/acf_gun/init.lua +++ b/lua/entities/acf_gun/init.lua @@ -157,37 +157,6 @@ do -- Spawn and Update functions -------------------------------- ------------------- Updating --------------------- - local function SavePhysObj(Entity) - local PhysObj = Entity:GetPhysicsObject() - - return { - Gravity = PhysObj:IsGravityEnabled(), - Motion = PhysObj:IsMotionEnabled(), - } - end - - local function RestorePhysObj(Entity, PhysData) - local PhysObj = Entity:GetPhysicsObject() - - PhysObj:EnableGravity(PhysData.Gravity) - PhysObj:EnableMotion(PhysData.Motion) - end - - local function RestoreConstraints(List) - local Constraints = duplicator.ConstraintType - - for _, Data in ipairs(List) do - local Constraint = Constraints[Data.Type] - local Args = {} - - for Index, Name in ipairs(Constraint.Args) do - Args[Index] = Data[Name] - end - - Constraint.Func(unpack(Args)) - end - end - function ENT:Update(Data) if self.Firing then return false, "Stop firing before updating the weapon!" end @@ -197,22 +166,21 @@ do -- Spawn and Update functions -------------------------------- local Class = ACF.GetClassGroup(Weapons, Data.Id) local Weapon = Class.Lookup[Data.Id] - local Constraints = constraint.GetTable(self) - local PhysData = SavePhysObj(self) if self.State ~= "Empty" then self:Unload() end + ACF.SaveEntity(self) + UpdateWeapon(self, Data, Class, Weapon) + ACF.RestoreEntity(self) + if Class.OnUpdate then Class.OnUpdate(self, Data, Class, Weapon) end - RestorePhysObj(self, PhysData) - RestoreConstraints(Constraints) - if next(self.Crates) then for Crate in pairs(self.Crates) do self:Unlink(Crate) From daa28ec39d5b59fb50d3d4d0e88581ee95067878 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Thu, 30 Apr 2020 18:10:26 -0400 Subject: [PATCH 081/279] Improved tool data functions - ACF.WriteValue now allows to send any type value to the server instead of just strings. - Clientside ACF.GetToolData will now return a copy of the tool data table instead of the actual table. --- lua/acf/base/util/cl_util.lua | 32 ++++++++++++-------------------- lua/acf/base/util/sv_util.lua | 9 +++------ 2 files changed, 15 insertions(+), 26 deletions(-) diff --git a/lua/acf/base/util/cl_util.lua b/lua/acf/base/util/cl_util.lua index 78f7f49ff..0debfda28 100644 --- a/lua/acf/base/util/cl_util.lua +++ b/lua/acf/base/util/cl_util.lua @@ -72,7 +72,13 @@ do -- Tool data functions do -- Read functions function ACF.GetToolData() - return ToolData + local Result = {} + + for K, V in pairs(ToolData) do + Result[K] = V + end + + return Result end function ACF.ReadBool(Key) @@ -104,24 +110,9 @@ do -- Tool data functions do -- Write function local LastSent = {} - local KeyPattern = "^[%w]+" - local ValuePattern = "[%w]*[%.]?[%w]+$" - - local function IsValidKey(Key) - if not Key then return false end - - return Key:match(KeyPattern) and true or false - end - - local function IsValidValue(Value) - if Value == nil then return false end - - return tostring(Value):match(ValuePattern) and true or false - end function ACF.WriteValue(Key, Value) - if not IsValidKey(Key) then return end - if not IsValidValue(Value) then return end + if not isstring(Key) then return end if ToolData[Key] == Value then return end ToolData[Key] = Value @@ -132,7 +123,7 @@ do -- Tool data functions if timer.Exists("ACF WriteValue " .. Key) then return end timer.Create("ACF WriteValue " .. Key, 0, 1, function() - local NewValue = tostring(ToolData[Key]) + local NewValue = ToolData[Key] -- Preventing network message spam if value hasn't really changed if LastSent[Key] == NewValue then return end @@ -140,10 +131,11 @@ do -- Tool data functions LastSent[Key] = NewValue net.Start("ACF_ToolData") - net.WriteString(Key .. ":" .. NewValue) + net.WriteString(Key) + net.WriteType(NewValue) net.SendToServer() - print("Sent", LocalPlayer(), Key, NewValue) + print("Sent", LocalPlayer(), Key, NewValue, type(NewValue)) end) end end diff --git a/lua/acf/base/util/sv_util.lua b/lua/acf/base/util/sv_util.lua index bc0ddd74e..a50c48b81 100644 --- a/lua/acf/base/util/sv_util.lua +++ b/lua/acf/base/util/sv_util.lua @@ -65,18 +65,15 @@ do -- Tool data functions do -- Data syncronization util.AddNetworkString("ACF_ToolData") - local function TranslateData(String) - return unpack(string.Explode(":", String)) - end - net.Receive("ACF_ToolData", function(_, Player) if not IsValid(Player) then return end - local Key, Value = TranslateData(net.ReadString()) + local Key = net.ReadString() + local Value = net.ReadType() ToolData[Player][Key] = Value - print("Received", Player, Key, Value) + print("Received", Player, Key, Value, type(Value)) end) hook.Add("PlayerInitialSpawn", "ACF Tool Data", function(Player) From fbd391de78731deb0abf144059d85e9f37a1ded4 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sat, 2 May 2020 07:26:12 -0400 Subject: [PATCH 082/279] Removed ID check on entity update - Entity updating won't be aborted if the entity shares the same ID as the update data. --- lua/entities/acf_engine/init.lua | 10 ++++------ lua/entities/acf_fueltank/init.lua | 9 +++------ lua/entities/acf_gun/init.lua | 2 -- 3 files changed, 7 insertions(+), 14 deletions(-) diff --git a/lua/entities/acf_engine/init.lua b/lua/entities/acf_engine/init.lua index d53bf0d2b..485e59e92 100644 --- a/lua/entities/acf_engine/init.lua +++ b/lua/entities/acf_engine/init.lua @@ -393,8 +393,6 @@ do -- Spawn and Update functions VerifyData(Data) - if self.Id == Data.Id then return false, "This engine is already the one you want it to update to!" end - local Class = ACF.GetClassGroup(Engines, Data.Id) local EngineData = Class.Lookup[Data.Id] local Feedback = "" @@ -423,9 +421,9 @@ do -- Spawn and Update functions end if Count == Total then - Feedback = Feedback .. " Unlinked all gearboxes due to excessive driveshaft angle." + Feedback = Feedback .. "\nUnlinked all gearboxes due to excessive driveshaft angle." elseif Count > 0 then - local Text = Feedback .. " Unlinked %s out of %s gearboxes due to excessive driveshaft angle." + local Text = Feedback .. "\nUnlinked %s out of %s gearboxes due to excessive driveshaft angle." Feedback = Text:format(Count, Total) end @@ -445,9 +443,9 @@ do -- Spawn and Update functions end if Count == Total then - Feedback = Feedback .. " Unlinked all fuel tanks due to fuel type change." + Feedback = Feedback .. "\nUnlinked all fuel tanks due to fuel type change." elseif Count > 0 then - local Text = Feedback .. " Unlinked %s out of %s fuel tanks due to fuel type change." + local Text = Feedback .. "\nUnlinked %s out of %s fuel tanks due to fuel type change." Feedback = Text:format(Count, Total) end diff --git a/lua/entities/acf_fueltank/init.lua b/lua/entities/acf_fueltank/init.lua index 238962d71..db855f3bc 100644 --- a/lua/entities/acf_fueltank/init.lua +++ b/lua/entities/acf_fueltank/init.lua @@ -42,7 +42,6 @@ do -- Spawn and Update functions Data.Id = Data.FuelTank elseif Data.SizeId then -- Backwards compatibility with ACF-2 dupes Data.Id = Data.SizeId - Data.SizeId = nil end local Class = ACF.GetClassGroup(FuelTanks, Data.Id) @@ -158,7 +157,7 @@ do -- Spawn and Update functions return Tank end - ACF.RegisterEntityClass("acf_fueltank", MakeACF_FuelTank, "Id", "FuelType", "SizeId") + ACF.RegisterEntityClass("acf_fueltank", MakeACF_FuelTank, "Id", "FuelType") ACF.RegisterLinkSource("acf_fueltank", "Engines") ------------------- Updating --------------------- @@ -166,8 +165,6 @@ do -- Spawn and Update functions function ENT:Update(Data) VerifyData(Data) - if self.Id == Data.Id then return false, "This fuel tank is already the one you want it to update to!" end - local Class = ACF.GetClassGroup(FuelTanks, Data.Id) local FuelTank = Class.Lookup[Data.Id] local Feedback = "" @@ -198,9 +195,9 @@ do -- Spawn and Update functions end if Count == Total then - Feedback = " Unlinked from all engines due to fuel type or model change." + Feedback = "\nUnlinked from all engines due to fuel type or model change." elseif Count > 0 then - local Text = " Unlinked from %s out of %s engines due to fuel type or model change." + local Text = "\nUnlinked from %s out of %s engines due to fuel type or model change." Feedback = Text:format(Count, Total) end diff --git a/lua/entities/acf_gun/init.lua b/lua/entities/acf_gun/init.lua index 631502c42..755a91bbc 100644 --- a/lua/entities/acf_gun/init.lua +++ b/lua/entities/acf_gun/init.lua @@ -162,8 +162,6 @@ do -- Spawn and Update functions -------------------------------- VerifyData(Data) - if self.Id == Data.Id then return false, "This weapon is already the one you want it to update to!" end - local Class = ACF.GetClassGroup(Weapons, Data.Id) local Weapon = Class.Lookup[Data.Id] From 2f2620bc44f55d7ef896d1b9c8f0989239ffc1e4 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sat, 2 May 2020 07:32:16 -0400 Subject: [PATCH 083/279] Adapted acf_gearbox to work with the new menu - The new menu tool will now be capable of spawning ACF Gearboxes. Attempting to do this with the old menu tool with throw errors. - Gearboxes can now be fully updated with the new menu tool. - Gearboxes will now have their own limit convar, `sbox_max_acf_gearbox`, instead of using the `_acf_misc` convar. Extension developers can also define custom convars inside each gearbox class definition if they desire. - Fixed players being capable of setting gears outside the -1 to 1 bounds. Duped gearboxes will be also checked. - Fixed automatic gearboxes being unable to use their reverse gear. --- lua/acf/base/sh_classes.lua | 14 +- lua/acf/client/menu_items/gearboxes_menu.lua | 5 + lua/entities/acf_gearbox/cl_init.lua | 10 +- lua/entities/acf_gearbox/init.lua | 601 +++++++++++-------- 4 files changed, 392 insertions(+), 238 deletions(-) diff --git a/lua/acf/base/sh_classes.lua b/lua/acf/base/sh_classes.lua index b8fd166cb..bee86fdd1 100644 --- a/lua/acf/base/sh_classes.lua +++ b/lua/acf/base/sh_classes.lua @@ -354,7 +354,19 @@ do -- Gearbox registration functions local Gearboxes = ACF.Classes.Gearboxes function ACF.RegisterGearboxClass(ID, Data) - return AddClassGroup(ID, Gearboxes, Data) + local Group = AddClassGroup(ID, Gearboxes, Data) + + if not Group.LimitConVar then + Group.LimitConVar = { + Name = "_acf_gearbox", + Amount = 24, + Text = "Maximum amount of gearboxes a player can create." + } + end + + AddSboxLimit(Group.LimitConVar) + + return Group end function ACF.RegisterGearbox(ID, ClassID, Data) diff --git a/lua/acf/client/menu_items/gearboxes_menu.lua b/lua/acf/client/menu_items/gearboxes_menu.lua index ee7306a6f..a2a20b053 100644 --- a/lua/acf/client/menu_items/gearboxes_menu.lua +++ b/lua/acf/client/menu_items/gearboxes_menu.lua @@ -49,6 +49,7 @@ local function CreateMenu(Menu) Selected[Choices] = Index ACF.WriteValue("GearboxClass", Data.ID) + ACF.WriteValue("MaxGears", Data.Gears.Max) LoadSortedList(GearboxList, Data.Items, "ID") end @@ -308,6 +309,8 @@ do -- Default Menus Menu:AddLabel("Upshift Speed Unit :") + ACF.WriteValue("ShiftUnit", UnitMult) + local Unit = Menu:AddComboBox() Unit:AddChoice("KPH", 10.936) Unit:AddChoice("MPH", 17.6) @@ -325,6 +328,8 @@ do -- Default Menus ACF.WriteValue(Var, Old * Delta) end + ACF.WriteValue("ShiftUnit", Mult) + UnitMult = Mult end diff --git a/lua/entities/acf_gearbox/cl_init.lua b/lua/entities/acf_gearbox/cl_init.lua index 3e416960c..146d8d18d 100644 --- a/lua/entities/acf_gearbox/cl_init.lua +++ b/lua/entities/acf_gearbox/cl_init.lua @@ -2,11 +2,15 @@ include("shared.lua") local SeatedInfo = CreateClientConVar("ACF_GearboxInfoWhileSeated", 0, true, false) +language.Add("Undone_acf_gearbox", "Undone ACF Gearbox") +language.Add("SBoxLimit__acf_gearbox", "You've reached the ACF Gearboxes limit!") + -- copied from base_wire_entity: DoNormalDraw's notip arg isn't accessible from ENT:Draw defined there. function ENT:Draw() - local lply = LocalPlayer() - local hideBubble = not SeatedInfo:GetBool() and IsValid(lply) and lply:InVehicle() - self.BaseClass.DoNormalDraw(self, false, hideBubble) + local Player = LocalPlayer() + local HideBubble = IsValid(Player) and Player:InVehicle() and not SeatedInfo:GetBool() + + self.BaseClass.DoNormalDraw(self, false, HideBubble) Wire_Render(self) if self.GetBeamLength and (not self.GetShowBeam or self:GetShowBeam()) then diff --git a/lua/entities/acf_gearbox/init.lua b/lua/entities/acf_gearbox/init.lua index 616bda387..31fdf9e3b 100644 --- a/lua/entities/acf_gearbox/init.lua +++ b/lua/entities/acf_gearbox/init.lua @@ -154,53 +154,17 @@ ACF.RegisterClassUnlink("acf_gearbox", "tire", UnlinkWheel) local CheckLegal = ACF_CheckLegal local ClassLink = ACF.GetClassLink local ClassUnlink = ACF.GetClassUnlink +local Gearboxes = ACF.Classes.Gearboxes local Clamp = math.Clamp -local function CreateInputsOutputs(Gearbox) - local Inputs = { "Gear", "Gear Up", "Gear Down" } - - if Gearbox.CVT then - Inputs[#Inputs + 1] = "CVT Ratio" - elseif Gearbox.DoubleDiff then - Inputs[#Inputs + 1] = "Steer Rate" - elseif Gearbox.Auto then - Inputs[#Inputs + 1] = "Hold Gear" - Inputs[#Inputs + 1] = "Shift Speed Scale" - - Gearbox.Hold = false - end - - if Gearbox.Dual then - Inputs[#Inputs + 1] = "Left Clutch" - Inputs[#Inputs + 1] = "Right Clutch" - Inputs[#Inputs + 1] = "Left Brake" - Inputs[#Inputs + 1] = "Right Brake" - else - Inputs[#Inputs + 1] = "Clutch" - Inputs[#Inputs + 1] = "Brake" - end - - local Outputs = { "Ratio", "Entity [ENTITY]", "Current Gear" } - - if Gearbox.CVT then - Outputs[#Outputs + 1] = "Min Target RPM" - Outputs[#Outputs + 1] = "Max Target RPM" - end - - Gearbox.Inputs = WireLib.CreateInputs(Gearbox, Inputs) - Gearbox.Outputs = WireLib.CreateOutputs(Gearbox, Outputs) - - WireLib.TriggerOutput(Gearbox, "Entity", Gearbox) -end - local function ChangeGear(Entity, Value) - Value = Clamp(math.floor(Value), 0, Entity.Gears) + Value = Clamp(math.floor(Value), Entity.MinGear, Entity.MaxRealGear) if Entity.Gear == Value then return end Entity.Gear = Value - Entity.GearRatio = Entity.GearTable[Value] * Entity.GearTable.Final - Entity.ChangeFinished = CurTime() + Entity.SwitchTime + Entity.GearRatio = Entity.Gears[Value] * Entity.Gears.Final + Entity.ChangeFinished = ACF.CurTime + Entity.SwitchTime Entity.InGear = false Entity:EmitSound("buttons/lever7.wav", 250, 100) @@ -218,103 +182,7 @@ local function ChangeDrive(Entity, Value) Entity.Drive = Value - ChangeGear(Entity, Entity.Drive == 2 and Entity.Reverse or Entity.Drive) -end - -local function UpdateGearboxData(Entity, GearboxData, Id, Data1, Data2, Data3, Data4, Data5, Data6, Data7, Data8, Data9, Data10) - if Entity.Id ~= Id then - Entity.Id = Id - Entity.Name = GearboxData.name - Entity.ShortName = Entity.Id - Entity.EntType = GearboxData.category - Entity.Model = GearboxData.model - Entity.Mass = GearboxData.weight - Entity.SwitchTime = GearboxData.switch - Entity.MaxTorque = GearboxData.maxtq - Entity.Gears = GearboxData.gears - Entity.Dual = GearboxData.doubleclutch - Entity.CVT = GearboxData.cvt - Entity.DoubleDiff = GearboxData.doublediff - Entity.Auto = GearboxData.auto - Entity.LClutch = Entity.MaxTorque - Entity.RClutch = Entity.MaxTorque - - CreateInputsOutputs(Entity) - - local PhysObj = Entity:GetPhysicsObject() - - if IsValid(PhysObj) then - PhysObj:SetMass(Entity.Mass) - end - end - - Entity.GearTable = {} - - for K, V in pairs(GearboxData.geartable) do - Entity.GearTable[K] = V - end - - Entity.GearTable[1] = Data1 - Entity.GearTable[2] = Data2 - Entity.GearTable[3] = Data3 - Entity.GearTable[4] = Data4 - Entity.GearTable[5] = Data5 - Entity.GearTable[6] = Data6 - Entity.GearTable[7] = Data7 - Entity.GearTable[8] = Data8 - Entity.GearTable[9] = Data9 - Entity.GearTable.Final = Data10 - - Entity.Gear0 = Data10 - Entity.Gear1 = Data1 - Entity.Gear2 = Data2 - Entity.Gear3 = Data3 - Entity.Gear4 = Data4 - Entity.Gear5 = Data5 - Entity.Gear6 = Data6 - Entity.Gear7 = Data7 - Entity.Gear8 = Data8 - Entity.Gear9 = Data9 - Entity.GearRatio = Entity.GearTable[0] * Entity.GearTable.Final - - if Entity.CVT then - Entity.TargetMinRPM = Data3 - Entity.TargetMaxRPM = math.max(Data4, Data3 + 100) - Entity.CVTRatio = 0 - - WireLib.TriggerOutput(Entity, "Min Target RPM", Entity.TargetMinRPM) - WireLib.TriggerOutput(Entity, "Max Target RPM", Entity.TargetMaxRPM) - - elseif Entity.Auto then - Entity.ShiftPoints = {} - - for part in string.gmatch(Data9, "[^,]+") do - Entity.ShiftPoints[#Entity.ShiftPoints + 1] = tonumber(part) - end - - Entity.ShiftPoints[0] = -1 - Entity.Reverse = Entity.Gears + 1 - Entity.GearTable[Entity.Reverse] = Data8 - Entity.Drive = 1 - Entity.ShiftScale = 1 - end - - if Entity.Dual or Entity.DoubleDiff then - Entity:SetBodygroup(1, 1) - else - Entity:SetBodygroup(1, 0) - end - - ChangeGear(Entity, 1) - - Entity:SetNWString("WireName", Entity.Name) - - ACF_Activate(Entity) - - Entity.ACF.LegalMass = Entity.Mass - Entity.ACF.Model = Entity.Model - - Entity:UpdateOverlay() + ChangeGear(Entity, Value == 2 and Entity.Reverse or Value) end local function CheckRopes(Entity, Target) @@ -322,7 +190,7 @@ local function CheckRopes(Entity, Target) for Ent, Link in pairs(Entity[Target]) do local OutPos = Entity:LocalToWorld(Link.Output) - local InPos = Ent.IsGeartrain and Ent:LocalToWorld(Ent.In) or Ent:GetPos() + local InPos = Ent.In and Ent:LocalToWorld(Ent.In) or Ent:GetPos() -- make sure it is not stretched too far if OutPos:Distance(InPos) > Link.RopeLen * 1.5 then @@ -366,7 +234,7 @@ end local Inputs = { Gear = function(Entity, Value) - if Entity.Auto then + if Entity.Automatic then ChangeDrive(Entity, Value) else ChangeGear(Entity, Value) @@ -375,7 +243,7 @@ local Inputs = { ["Gear Up"] = function(Entity, Value) if Value == 0 then return end - if Entity.Auto then + if Entity.Automatic then ChangeDrive(Entity, Entity.Drive + 1) else ChangeGear(Entity, Entity.Gear + 1) @@ -384,7 +252,7 @@ local Inputs = { ["Gear Down"] = function(Entity, Value) if Value == 0 then return end - if Entity.Auto then + if Entity.Automatic then ChangeDrive(Entity, Entity.Drive - 1) else ChangeGear(Entity, Entity.Gear - 1) @@ -426,80 +294,361 @@ local Inputs = { --===============================================================================================-- -function MakeACF_Gearbox(Owner, Pos, Angle, Id, ...) - if not Owner:CheckLimit("_acf_misc") then return end +do -- Spawn and Update functions + local function VerifyData(Data) + Data.Id = Data.Gearbox or Data.Id - local GearboxData = ACF.Weapons.Mobility[Id] + local Class = ACF.GetClassGroup(Gearboxes, Data.Id) - if not GearboxData then return end + if not Class then + Data.Id = "2Gear-T-S" + end - local Gearbox = ents.Create("acf_gearbox") + if Data.Gearbox then -- Entity was created via menu tool + local Mult = Data.ShiftUnit + local Points = { [0] = -1 } + local Gears = { [0] = 0 } - if not IsValid(Gearbox) then return end + for I = 1, Data.MaxGears do + Gears[I] = Clamp(Data["Gear" .. I], -1, 1) - Gearbox:SetModel(GearboxData.model) - Gearbox:SetPlayer(Owner) - Gearbox:SetAngles(Angle) - Gearbox:SetPos(Pos) - Gearbox:Spawn() + if Data["Shift" .. I] then + local Value = tonumber(Data["Shift" .. I]) * Mult - Gearbox:PhysicsInit(SOLID_VPHYSICS) - Gearbox:SetMoveType(MOVETYPE_VPHYSICS) + Points[I] = Clamp(Value, 0, 9999) + end + end - Owner:AddCount("_acf_misc", Gearbox) - Owner:AddCleanup("acfmenu", Gearbox) + Gears.Final = Clamp(Data.FinalDrive, -1, 1) - Gearbox.Owner = Owner - Gearbox.IsGeartrain = true - Gearbox.Engines = {} - Gearbox.Wheels = {} -- a "Link" has these components: Ent, Side, Axis, Rope, RopeLen, Output, ReqTq, Vel - Gearbox.GearboxIn = {} - Gearbox.GearboxOut = {} - Gearbox.TotalReqTq = 0 - Gearbox.TorqueOutput = 0 - Gearbox.LBrake = 0 - Gearbox.RBrake = 0 - Gearbox.SteerRate = 0 - Gearbox.Gear = 0 - Gearbox.ChangeFinished = 0 - Gearbox.InGear = false - Gearbox.CanUpdate = true - Gearbox.LastActive = 0 + if Data.Reverse then + Gears.Reverse = Clamp(Data.Reverse, -1, 1) + end - Gearbox.In = Gearbox:WorldToLocal(Gearbox:GetAttachment(Gearbox:LookupAttachment("input")).Pos) - Gearbox.OutL = Gearbox:WorldToLocal(Gearbox:GetAttachment(Gearbox:LookupAttachment("driveshaftL")).Pos) - Gearbox.OutR = Gearbox:WorldToLocal(Gearbox:GetAttachment(Gearbox:LookupAttachment("driveshaftR")).Pos) + if Data.MinRPM then + Gears.MinRPM = Clamp(Data.MinRPM, 1, 9900) + Gears.MaxRPM = Clamp(Data.MaxRPM, Gears.MinRPM + 100, 10000) + end - UpdateGearboxData(Gearbox, GearboxData, Id, ...) - Gearbox:UpdateOverlay(true) + Data.Gears = Gears + Data.ShiftPoints = Points - CheckLegal(Gearbox) + elseif Data.Gear0 then -- Backwards compatibility with ACF-2 dupes + local Points = { [0] = -1 } + local Gears = { [0] = 0 } + local Count = 0 - timer.Create("ACF Gearbox Clock " .. Gearbox:EntIndex(), 3, 0, function() - if IsValid(Gearbox) then - CheckRopes(Gearbox, "GearboxOut") - CheckRopes(Gearbox, "Wheels") + Gears.Final = Clamp(Data.Gear0, -1, 1) + Gears.MinRPM = Clamp(Data.Gear3, 1, 9900) + Gears.MaxRPM = Clamp(Data.Gear4, Gears.MinRPM + 100, 10000) + Gears.Reverse = Clamp(Data.Gear8, -1, 1) + + for Point in string.gmatch(Data.Gear9, "[^,]+") do + local Value = tonumber(Point) + + Count = Count + 1 + + Points[Count] = Value and Clamp(Value, 0, 9999) + end + + for I = 1, 8 do + Gears[I] = Clamp(Data["Gear" .. I], -1, 1) + end + + Data.Gears = Gears + Data.ShiftPoints = Points + end + end + + local function CreateInputs(Entity) + local List = { "Gear", "Gear Up", "Gear Down" } + + if Entity.CVT then + List[#List + 1] = "CVT Ratio" + elseif Entity.DoubleDiff then + List[#List + 1] = "Steer Rate" + elseif Entity.Automatic then + List[#List + 1] = "Hold Gear" + List[#List + 1] = "Shift Speed Scale" + end + + if Entity.DualClutch then + List[#List + 1] = "Left Clutch" + List[#List + 1] = "Right Clutch" + List[#List + 1] = "Left Brake" + List[#List + 1] = "Right Brake" else - timer.Remove("ACF Engine Clock " .. Gearbox:EntIndex()) + List[#List + 1] = "Clutch" + List[#List + 1] = "Brake" end - end) - return Gearbox -end + Entity.Inputs = WireLib.CreateInputs(Entity, List) + end + + local function CreateOutputs(Entity) + local List = { "Ratio", "Entity [ENTITY]", "Current Gear" } + + if Entity.CVT then + List[#List + 1] = "Min Target RPM" + List[#List + 1] = "Max Target RPM" + end + + Entity.Outputs = WireLib.CreateOutputs(Entity, List) + + WireLib.TriggerOutput(Entity, "Entity", Entity) + end + + local function UpdateGearbox(Entity, Data, Class, Gearbox) + Entity:SetModel(Gearbox.Model) + + Entity:PhysicsInit(SOLID_VPHYSICS) + Entity:SetMoveType(MOVETYPE_VPHYSICS) + + -- Storing all the relevant information on the entity for duping + for _, V in ipairs(Entity.DataStore) do + Entity[V] = Data[V] + end + + Entity.Name = Gearbox.Name + Entity.ShortName = Entity.Id + Entity.EntType = Class.ID + Entity.SwitchTime = Gearbox.Switch + Entity.MaxTorque = Gearbox.MaxTorque + Entity.MinGear = Class.Gears.Min + Entity.MaxGear = Class.Gears.Max + Entity.MaxRealGear = Entity.MaxGear + Entity.DualClutch = Gearbox.DualClutch + Entity.CVT = Gearbox.CVT + Entity.DoubleDiff = Gearbox.DoubleDiff + Entity.Automatic = Gearbox.Automatic + Entity.LClutch = Entity.MaxTorque + Entity.RClutch = Entity.MaxTorque + Entity.In = Entity:WorldToLocal(Entity:GetAttachment(Entity:LookupAttachment("input")).Pos) + Entity.OutL = Entity:WorldToLocal(Entity:GetAttachment(Entity:LookupAttachment("driveshaftL")).Pos) + Entity.OutR = Entity:WorldToLocal(Entity:GetAttachment(Entity:LookupAttachment("driveshaftR")).Pos) + + CreateInputs(Entity) + CreateOutputs(Entity) + + local Gears = Entity.Gears + + if Entity.CVT then + Entity.CVTRatio = 0 + + Gears[1] = 0.01 + + WireLib.TriggerOutput(Entity, "Min Target RPM", Gears.MinRPM) + WireLib.TriggerOutput(Entity, "Max Target RPM", Gears.MaxRPM) + + Entity.ShiftPoints = nil + Gears.Reverse = nil + + elseif Entity.Automatic then + Entity.MaxRealGear = Entity.MaxGear + 1 + Entity.Reverse = Entity.MaxRealGear + Entity.ShiftScale = 1 + Entity.Hold = false + Entity.Drive = 1 + + Gears[Entity.Reverse] = Gears.Reverse + Gears.MinRPM = nil + Gears.MaxRPM = nil + else + Entity.ShiftPoints = nil + Gears.Reverse = nil + Gears.MinRPM = nil + Gears.MaxRPM = nil + end + + if Entity.DualClutch or Entity.DoubleDiff then + Entity:SetBodygroup(1, 1) + else + Entity:SetBodygroup(1, 0) + end + + Entity:SetNWString("WireName", Entity.Name) + + ACF_Activate(Entity, true) + + Entity.ACF.LegalMass = Gearbox.Mass + Entity.ACF.Model = Gearbox.Model + + local Phys = Entity:GetPhysicsObject() + if IsValid(Phys) then Phys:SetMass(Gearbox.Mass) end + + ChangeGear(Entity, 1) + + Entity:UpdateOverlay(true) + + CheckLegal(Entity) + end + + function MakeACF_Gearbox(Player, Pos, Angle, Data) + VerifyData(Data) -list.Set("ACFCvars", "acf_gearbox", {"id", "data1", "data2", "data3", "data4", "data5", "data6", "data7", "data8", "data9", "data10"}) -duplicator.RegisterEntityClass("acf_gearbox", MakeACF_Gearbox, "Pos", "Angle", "Id", "Gear1", "Gear2", "Gear3", "Gear4", "Gear5", "Gear6", "Gear7", "Gear8", "Gear9", "Gear0") -ACF.RegisterLinkSource("acf_gearbox", "GearboxIn") -ACF.RegisterLinkSource("acf_gearbox", "GearboxOut") -ACF.RegisterLinkSource("acf_gearbox", "Engines") -ACF.RegisterLinkSource("acf_gearbox", "Wheels") + local Class = ACF.GetClassGroup(Gearboxes, Data.Id) + local GearboxData = Class.Lookup[Data.Id] + local Limit = Class.LimitConVar.Name + + if not Player:CheckLimit(Limit) then return end + + local Gearbox = ents.Create("acf_gearbox") + + if not IsValid(Gearbox) then return end + + Gearbox:SetPlayer(Player) + Gearbox:SetAngles(Angle) + Gearbox:SetPos(Pos) + Gearbox:Spawn() + + Player:AddCleanup("acfmenu", Gearbox) + Player:AddCount(Limit, Gearbox) + + Gearbox.Owner = Player -- MUST be stored on ent for PP + Gearbox.Engines = {} + Gearbox.Wheels = {} -- a "Link" has these components: Ent, Side, Axis, Rope, RopeLen, Output, ReqTq, Vel + Gearbox.GearboxIn = {} + Gearbox.GearboxOut = {} + Gearbox.TotalReqTq = 0 + Gearbox.TorqueOutput = 0 + Gearbox.LBrake = 0 + Gearbox.RBrake = 0 + Gearbox.SteerRate = 0 + Gearbox.Gear = 0 + Gearbox.ChangeFinished = 0 + Gearbox.InGear = false + Gearbox.LastActive = 0 + Gearbox.DataStore = ACF.GetEntClassVars("acf_gearbox") + + UpdateGearbox(Gearbox, Data, Class, GearboxData) + + if Class.OnSpawn then + Class.OnSpawn(Gearbox, Data, Class, GearboxData) + end + + timer.Create("ACF Gearbox Clock " .. Gearbox:EntIndex(), 3, 0, function() + if IsValid(Gearbox) then + CheckRopes(Gearbox, "GearboxOut") + CheckRopes(Gearbox, "Wheels") + else + timer.Remove("ACF Engine Clock " .. Gearbox:EntIndex()) + end + end) + + return Gearbox + end + + ACF.RegisterEntityClass("acf_gearbox", MakeACF_Gearbox, "Id", "Gears", "ShiftPoints") + ACF.RegisterLinkSource("acf_gearbox", "GearboxIn") + ACF.RegisterLinkSource("acf_gearbox", "GearboxOut") + ACF.RegisterLinkSource("acf_gearbox", "Engines") + ACF.RegisterLinkSource("acf_gearbox", "Wheels") + + ------------------- Updating --------------------- + + function ENT:Update(Data) + VerifyData(Data) + + local Class = ACF.GetClassGroup(Gearboxes, Data.Id) + local GearboxData = Class.Lookup[Data.Id] + local Feedback = "" + + ACF.SaveEntity(self) + + UpdateGearbox(self, Data, Class, GearboxData) + + ACF.RestoreEntity(self) + + if Class.OnUpdate then + Class.OnUpdate(self, Data, Class, GearboxData) + end + + if next(self.Engines) then + local Count, Total = 0, 0 + + for Engine in pairs(self.Engines) do + self:Unlink(Engine) + + local Result = self:Link(Engine) + + if not Result then Count = Count + 1 end + + Total = Total + 1 + end + + if Count == Total then + Feedback = Feedback .. "\nUnlinked all engines due to excessive driveshaft angle." + elseif Count > 0 then + local Text = Feedback .. "\nUnlinked %s out of %s engines due to excessive driveshaft angle." + + Feedback = Text:format(Count, Total) + end + end + + if next(self.Wheels) then + local Count, Total = 0, 0 + + for Wheel in pairs(self.Wheels) do + self:Unlink(Wheel) + + local Result = self:Link(Wheel) + + if not Result then Count = Count + 1 end + + Total = Total + 1 + end + + if Count == Total then + Feedback = Feedback .. "\nUnlinked all wheels due to excessive driveshaft angle." + elseif Count > 0 then + local Text = Feedback .. "\nUnlinked %s out of %s wheels due to excessive driveshaft angle." + + Feedback = Text:format(Count, Total) + end + end + + if next(self.GearboxIn) or next(self.GearboxOut) then + local Count, Total = 0, 0 + + for Gearbox in pairs(self.GearboxIn) do + Gearbox:Unlink(self) + + local Result = Gearbox:Link(self) + + if not Result then Count = Count + 1 end + + Total = Total + 1 + end + + for Gearbox in pairs(self.GearboxOut) do + self:Unlink(Gearbox) + + local Result = self:Link(Gearbox) + + if not Result then Count = Count + 1 end + + Total = Total + 1 + end + + if Count == Total then + Feedback = Feedback .. "\nUnlinked all gearboxes due to excessive driveshaft angle." + elseif Count > 0 then + local Text = Feedback .. "\nUnlinked %s out of %s gearboxes due to excessive driveshaft angle." + + Feedback = Text:format(Count, Total) + end + end + + return true, "Gearbox updated successfully!" .. Feedback + end +end --===============================================================================================-- -- Meta Funcs --===============================================================================================-- function ENT:Enable() - if self.Auto then + if self.Automatic then ChangeDrive(self, self.OldGear) else ChangeGear(self, self.OldGear) @@ -511,9 +660,9 @@ function ENT:Enable() end function ENT:Disable() - self.OldGear = self.Auto and self.Drive or self.Gear + self.OldGear = self.Automatic and self.Drive or self.Gear - if self.Auto then + if self.Automatic then ChangeDrive(self, 0) else ChangeGear(self, 0) @@ -522,49 +671,33 @@ function ENT:Disable() self:UpdateOverlay() end -function ENT:Update(ArgsTable) - if ArgsTable[1] ~= self.Owner then return false, "You don't own that gearbox!" end - - local Id = ArgsTable[4] -- Argtable[4] is the engine ID - local GearboxData = ACF.Weapons.Mobility[Id] - - if not GearboxData then return false, "Invalid gearbox type!" end - if GearboxData.model ~= self.Model then return false, "The new gearbox must have the same model!" end - - UpdateGearboxData(self, GearboxData, unpack(ArgsTable, 4, 14)) - - return true, "Gearbox updated successfully!" -end - local function Overlay(Ent) local Text if Ent.DisableReason then - Text = "Disabled: " .. Ent.DisableReason + Text = "Disabled: " .. Ent.DisableReason .. "\n\n" else - Text = "Current Gear: " .. Ent.Gear + Text = "Current Gear: " .. Ent.Gear .. "\n\n" end - Text = Text .. "\n\n" .. Ent.Name .. "\n" - if Ent.CVT then - Text = "Reverse Gear: " .. math.Round(Ent.GearTable[2], 2) .. - "\nTarget: " .. math.Round(Ent.TargetMinRPM) .. " - " .. math.Round(Ent.TargetMaxRPM) .. " RPM\n" - elseif Ent.Auto then - for i = 1, Ent.Gears do - Text = Text .. "Gear " .. i .. ": " .. math.Round(Ent.GearTable[i], 2) .. + Text = Text .. "Reverse Gear: " .. math.Round(Ent.Gears[2], 2) .. + "\nTarget: " .. math.Round(Ent.Gears.MinRPM) .. " - " .. math.Round(Ent.Gears.MaxRPM) .. " RPM\n" + elseif Ent.Automatic then + for i = 1, Ent.MaxGear do + Text = Text .. "Gear " .. i .. ": " .. math.Round(Ent.Gears[i], 2) .. ", Upshift @ " .. math.Round(Ent.ShiftPoints[i] / 10.936, 1) .. " kph / " .. math.Round(Ent.ShiftPoints[i] / 17.6, 1) .. " mph\n" end - Text = Text .. "Reverse gear: " .. math.Round(Ent.GearTable[Ent.Reverse], 2) .. "\n" + Text = Text .. "Reverse gear: " .. math.Round(Ent.Gears[Ent.Reverse], 2) .. "\n" else - for i = 1, Ent.Gears do - Text = Text .. "Gear " .. i .. ": " .. math.Round(Ent.GearTable[i], 2) .. "\n" + for i = 1, Ent.MaxGear do + Text = Text .. "Gear " .. i .. ": " .. math.Round(Ent.Gears[i], 2) .. "\n" end end - Text = Text .. "Final Drive: " .. math.Round(Ent.Gear0, 2) .. "\n" + Text = Text .. "Final Drive: " .. math.Round(Ent.Gears.Final, 2) .. "\n" Text = Text .. "Torque Rating: " .. Ent.MaxTorque .. " Nm / " .. math.Round(Ent.MaxTorque * 0.73) .. " ft-lb\n" Text = Text .. "Torque Output: " .. math.floor(Ent.TorqueOutput) .. " Nm / " .. math.Round(Ent.TorqueOutput * 0.73) .. " ft-lb" @@ -601,9 +734,9 @@ end function ENT:Calc(InputRPM, InputInertia) if self.Disabled then return 0 end - if self.LastActive == CurTime() then return self.TorqueOutput end + if self.LastActive == ACF.CurTime then return self.TorqueOutput end - if self.ChangeFinished < CurTime() then + if self.ChangeFinished < ACF.CurTime then self.InGear = true end @@ -612,20 +745,20 @@ function ENT:Calc(InputRPM, InputInertia) if self.CVT and self.Gear == 1 then if self.CVTRatio > 0 then - self.GearTable[1] = Clamp(self.CVTRatio, 0.01, 1) + self.Gears[1] = Clamp(self.CVTRatio, 0.01, 1) else - self.GearTable[1] = Clamp((InputRPM - self.TargetMinRPM) / (self.TargetMaxRPM - self.TargetMinRPM), 0.05, 1) + self.Gears[1] = Clamp((InputRPM - self.Gears.MinRPM) / (self.Gears.MaxRPM - self.Gears.MinRPM), 0.05, 1) end - self.GearRatio = self.GearTable[1] * self.GearTable.Final + self.GearRatio = self.Gears[1] * self.Gears.Final WireLib.TriggerOutput(self, "Ratio", self.GearRatio) end - if self.Auto and self.Drive == 1 and self.InGear then + if self.Automatic and self.Drive == 1 and self.InGear then local PhysVel = BoxPhys:GetVelocity():Length() - if not self.Hold and self.Gear ~= self.Gears and PhysVel > (self.ShiftPoints[self.Gear] * self.ShiftScale) then + if not self.Hold and self.Gear ~= self.MaxGear and PhysVel > (self.ShiftPoints[self.Gear] * self.ShiftScale) then ChangeGear(self, self.Gear + 1) elseif PhysVel < (self.ShiftPoints[self.Gear - 1] * self.ShiftScale) then ChangeGear(self, self.Gear - 1) @@ -693,7 +826,7 @@ function ENT:Act(Torque, DeltaTime, MassRatio) if self.Disabled then return end local Loss = Clamp(((1 - 0.4) / 0.5) * ((self.ACF.Health / self.ACF.MaxHealth) - 1) + 1, 0.4, 1) --internal torque loss from damaged - local Slop = self.Auto and 0.9 or 1 --internal torque loss from inefficiency + local Slop = self.Automatic and 0.9 or 1 --internal torque loss from inefficiency local ReactTq = 0 -- Calculate the ratio of total requested torque versus what's avaliable, and then multiply it but the current gearratio local AvailTq = 0 @@ -723,7 +856,7 @@ function ENT:Act(Torque, DeltaTime, MassRatio) end end - self.LastActive = CurTime() + self.LastActive = ACF.CurTime end function ENT:Link(Target) @@ -764,13 +897,13 @@ function ENT:PreEntityCopy() end if next(self.GearboxOut) then - local Gearboxes = {} + local Entities = {} for Ent in pairs(self.GearboxOut) do - Gearboxes[#Gearboxes + 1] = Ent:EntIndex() + Entities[#Entities + 1] = Ent:EntIndex() end - duplicator.StoreEntityModifier(self, "ACFGearboxes", Gearboxes) + duplicator.StoreEntityModifier(self, "ACFGearboxes", Entities) end --Wire dupe info From 61c55aa3732d0557f8694a054c751032a96c5327 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Mon, 4 May 2020 22:03:22 -0400 Subject: [PATCH 084/279] Improved ACF-2 dupe gearbox data verification - Fixed a few cases where gearboxes from ACF-2 would silently error while being spawned with the duplicator tool due to non-numerical values being used with the math library. --- lua/acf/base/acf_globals.lua | 2 +- lua/entities/acf_gearbox/init.lua | 18 +++++++++++++----- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/lua/acf/base/acf_globals.lua b/lua/acf/base/acf_globals.lua index ce2670bf2..cb00620ee 100644 --- a/lua/acf/base/acf_globals.lua +++ b/lua/acf/base/acf_globals.lua @@ -42,7 +42,7 @@ do -- ACF global vars ACF.PDensity = 1.6 --Gun propellant density (Real powders go from 0.7 to 1.6, i"m using higher densities to simulate case bottlenecking) ACF.TorqueBoost = 1.25 --torque multiplier from using fuel ACF.FuelRate = 1 --multiplier for fuel usage, 1.0 is approx real world - ACF.ElecRate = 1.5 --multiplier for electrics + ACF.ElecRate = 1 --multiplier for electrics ACF.TankVolumeMul = 1 -- multiplier for fuel tank capacity, 1.0 is approx real world ACF.LiIonED = 0.458 -- li-ion energy density: kw hours / liter ACF.CuIToLiter = 0.0163871 -- cubic inches to liters diff --git a/lua/entities/acf_gearbox/init.lua b/lua/entities/acf_gearbox/init.lua index 31fdf9e3b..cd8652ec5 100644 --- a/lua/entities/acf_gearbox/init.lua +++ b/lua/entities/acf_gearbox/init.lua @@ -337,11 +337,15 @@ do -- Spawn and Update functions local Points = { [0] = -1 } local Gears = { [0] = 0 } local Count = 0 + local Final = tonumber(Data.Gear0) or 1 + local MinRPM = tonumber(Data.Gear3) or 1 + local MaxRPM = tonumber(Data.Gear4) or 101 + local Reverse = tonumber(Data.Gear8) or -1 - Gears.Final = Clamp(Data.Gear0, -1, 1) - Gears.MinRPM = Clamp(Data.Gear3, 1, 9900) - Gears.MaxRPM = Clamp(Data.Gear4, Gears.MinRPM + 100, 10000) - Gears.Reverse = Clamp(Data.Gear8, -1, 1) + Gears.Final = Clamp(Final, -1, 1) + Gears.MinRPM = Clamp(MinRPM, 1, 9900) + Gears.MaxRPM = Clamp(MaxRPM, MinRPM + 100, 10000) + Gears.Reverse = Clamp(Reverse, -1, 1) for Point in string.gmatch(Data.Gear9, "[^,]+") do local Value = tonumber(Point) @@ -352,7 +356,11 @@ do -- Spawn and Update functions end for I = 1, 8 do - Gears[I] = Clamp(Data["Gear" .. I], -1, 1) + local Value = tonumber(Data["Gear" .. I]) + + if Value then + Gears[I] = Clamp(Data["Gear" .. I], -1, 1) + end end Data.Gears = Gears From 9b758007c47b08e7f140c1ab9a22b782720ae995 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sat, 9 May 2020 04:32:55 -0400 Subject: [PATCH 085/279] Added component and sensor limit convars. - Sensor entities will now, by default, use the `sbox_max_acf_sensor` limit convar. - Components will reuse the already existing `acf_max_acf_misc`. - Weapons will now use the `_acf_weapon` instead of `_acf_gun` limit convar. - Changed all help texts to specify the convars are about ACF entity limits. - Removed an unused convar from the old legal checks. --- lua/acf/base/acf_globals.lua | 5 ---- lua/acf/base/sh_classes.lua | 38 ++++++++++++++++++++++----- lua/acf/shared/guns/smokelauncher.lua | 2 +- 3 files changed, 32 insertions(+), 13 deletions(-) diff --git a/lua/acf/base/acf_globals.lua b/lua/acf/base/acf_globals.lua index 669a5c5df..a72b808ac 100644 --- a/lua/acf/base/acf_globals.lua +++ b/lua/acf/base/acf_globals.lua @@ -96,7 +96,6 @@ end do -- ACF Convars/Callbacks ------------------------ CreateConVar("sbox_max_acf_ammo", 32) - CreateConVar("sbox_max_acf_misc", 32) CreateConVar("acf_meshvalue", 1) CreateConVar("sbox_acf_restrictinfo", 1) -- 0=any, 1=owned -- Cvars for recoil/he push @@ -108,7 +107,6 @@ do -- ACF Convars/Callbacks ------------------------ CreateConVar("acf_ammomod", 1) CreateConVar("acf_spalling", 0) CreateConVar("acf_gunfire", 1) - CreateConVar("acf_modelswap_legal", 0) cvars.AddChangeCallback("acf_healthmod", ACF_CVarChangeCallback) cvars.AddChangeCallback("acf_armormod", ACF_CVarChangeCallback) @@ -233,9 +231,6 @@ function ACF_CVarChangeCallback(CVar, _, New) end print("ACF Gunfire has been " .. text) - elseif CVar == "acf_modelswap_legal" then - ACF.LegalSettings.CanModelSwap = tobool(New) - print("ACF model swapping is set to " .. (ACF.LegalSettings.CanModelSwap and "legal" or "not legal")) end end diff --git a/lua/acf/base/sh_classes.lua b/lua/acf/base/sh_classes.lua index bee86fdd1..bf1c15530 100644 --- a/lua/acf/base/sh_classes.lua +++ b/lua/acf/base/sh_classes.lua @@ -203,9 +203,9 @@ do -- Weapon registration functions if not Group.LimitConVar then Group.LimitConVar = { - Name = "_acf_gun", + Name = "_acf_weapon", Amount = 16, - Text = "Maximum amount of weapons a player can create." + Text = "Maximum amount of ACF weapons a player can create." } end @@ -272,7 +272,7 @@ do -- Engine registration functions Group.LimitConVar = { Name = "_acf_engine", Amount = 16, - Text = "Maximum amount of engines a player can create." + Text = "Maximum amount of ACF engines a player can create." } end @@ -314,7 +314,7 @@ do -- Fuel tank registration functions Group.LimitConVar = { Name = "_acf_fueltank", Amount = 24, - Text = "Maximum amount of fuel tanks a player can create." + Text = "Maximum amount of ACF fuel tanks a player can create." } end @@ -360,7 +360,7 @@ do -- Gearbox registration functions Group.LimitConVar = { Name = "_acf_gearbox", Amount = 24, - Text = "Maximum amount of gearboxes a player can create." + Text = "Maximum amount of ACF gearboxes a player can create." } end @@ -390,7 +390,19 @@ do -- Component registration functions local Components = ACF.Classes.Components function ACF.RegisterComponentClass(ID, Data) - return AddClassGroup(ID, Components, Data) + local Group = AddClassGroup(ID, Components, Data) + + if not Group.LimitConVar then + Group.LimitConVar = { + Name = "_acf_misc", + Amount = 32, + Text = "Maximum amount of ACF components a player can create." + } + end + + AddSboxLimit(Group.LimitConVar) + + return Group end function ACF.RegisterComponent(ID, ClassID, Data) @@ -404,7 +416,19 @@ do -- Sensor registration functions local Sensors = ACF.Classes.Sensors function ACF.RegisterSensorClass(ID, Data) - return AddClassGroup(ID, Sensors, Data) + local Group = AddClassGroup(ID, Sensors, Data) + + if not Group.LimitConVar then + Group.LimitConVar = { + Name = "_acf_sensor", + Amount = 16, + Text = "Maximum amount of ACF sensors a player can create." + } + end + + AddSboxLimit(Group.LimitConVar) + + return Group end function ACF.RegisterSensor(ID, ClassID, Data) diff --git a/lua/acf/shared/guns/smokelauncher.lua b/lua/acf/shared/guns/smokelauncher.lua index 82d74bcd2..ae0506fa5 100644 --- a/lua/acf/shared/guns/smokelauncher.lua +++ b/lua/acf/shared/guns/smokelauncher.lua @@ -60,7 +60,7 @@ ACF.RegisterWeaponClass("SL", { LimitConVar = { Name = "_acf_smokelauncher", Amount = 10, - Text = "Maximum amount of smoke launchers a player can create." + Text = "Maximum amount of ACF smoke launchers a player can create." }, Caliber = { Min = 40, From 6eb3059569da32f0a61a5f06a92a83737bede9ac Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sat, 9 May 2020 04:45:15 -0400 Subject: [PATCH 086/279] Improved custom menus for sensors and components - Sensor and component menus will now use either the currently selected entity data or its respective class data's create menu function. --- lua/acf/client/menu_items/components_menu.lua | 6 ++++-- lua/acf/client/menu_items/sensors_menu.lua | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/lua/acf/client/menu_items/components_menu.lua b/lua/acf/client/menu_items/components_menu.lua index f4f026475..2b662d03f 100644 --- a/lua/acf/client/menu_items/components_menu.lua +++ b/lua/acf/client/menu_items/components_menu.lua @@ -76,8 +76,10 @@ local function CreateMenu(Menu) Menu:ClearTemporal(self) Menu:StartTemporal(self) - if Data.CreateMenu then - Data:CreateMenu(Menu) + local CustomMenu = Data.CreateMenu or ClassData.CreateMenu + + if CustomMenu then + CustomMenu(Data, Menu) end Menu:EndTemporal(self) diff --git a/lua/acf/client/menu_items/sensors_menu.lua b/lua/acf/client/menu_items/sensors_menu.lua index 779815793..8b258abca 100644 --- a/lua/acf/client/menu_items/sensors_menu.lua +++ b/lua/acf/client/menu_items/sensors_menu.lua @@ -76,8 +76,10 @@ local function CreateMenu(Menu) Menu:ClearTemporal(self) Menu:StartTemporal(self) - if Data.CreateMenu then - Data:CreateMenu(Menu) + local CustomMenu = Data.CreateMenu or ClassData.CreateMenu + + if CustomMenu then + CustomMenu(Data, Menu) end Menu:EndTemporal(self) From 636a6dd5e06965e8aa6db5fa0a630c2d17ee0672 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sun, 10 May 2020 05:08:41 -0400 Subject: [PATCH 087/279] Fixed ACF_CheckLegal calls - Fixed ACF_CheckLegal being called multiple times, as it should once be called once for every entity. --- lua/entities/acf_engine/init.lua | 4 ++-- lua/entities/acf_fueltank/init.lua | 4 ++-- lua/entities/acf_gearbox/init.lua | 4 ++-- lua/entities/acf_gun/init.lua | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lua/entities/acf_engine/init.lua b/lua/entities/acf_engine/init.lua index 4d14a4352..a92bdb15b 100644 --- a/lua/entities/acf_engine/init.lua +++ b/lua/entities/acf_engine/init.lua @@ -332,8 +332,6 @@ do -- Spawn and Update functions if IsValid(Phys) then Phys:SetMass(EngineData.Mass) end Entity:UpdateOverlay(true) - - CheckLegal(Entity) end function MakeACF_Engine(Player, Pos, Angle, Data) @@ -379,6 +377,8 @@ do -- Spawn and Update functions Class.OnSpawn(Engine, Data, Class, EngineData) end + CheckLegal(Engine) + return Engine end diff --git a/lua/entities/acf_fueltank/init.lua b/lua/entities/acf_fueltank/init.lua index db855f3bc..b0c69306c 100644 --- a/lua/entities/acf_fueltank/init.lua +++ b/lua/entities/acf_fueltank/init.lua @@ -109,8 +109,6 @@ do -- Spawn and Update functions Entity:UpdateMass(true) Entity:UpdateOverlay(true) - - CheckLegal(Entity) end function MakeACF_FuelTank(Player, Pos, Angle, Data) @@ -154,6 +152,8 @@ do -- Spawn and Update functions Class.OnSpawn(Tank, Data, Class, FuelTank) end + CheckLegal(Tank) + return Tank end diff --git a/lua/entities/acf_gearbox/init.lua b/lua/entities/acf_gearbox/init.lua index cd8652ec5..e21b5a2f8 100644 --- a/lua/entities/acf_gearbox/init.lua +++ b/lua/entities/acf_gearbox/init.lua @@ -487,8 +487,6 @@ do -- Spawn and Update functions ChangeGear(Entity, 1) Entity:UpdateOverlay(true) - - CheckLegal(Entity) end function MakeACF_Gearbox(Player, Pos, Angle, Data) @@ -534,6 +532,8 @@ do -- Spawn and Update functions Class.OnSpawn(Gearbox, Data, Class, GearboxData) end + CheckLegal(Gearbox) + timer.Create("ACF Gearbox Clock " .. Gearbox:EntIndex(), 3, 0, function() if IsValid(Gearbox) then CheckRopes(Gearbox, "GearboxOut") diff --git a/lua/entities/acf_gun/init.lua b/lua/entities/acf_gun/init.lua index 124169699..1f5b8c13a 100644 --- a/lua/entities/acf_gun/init.lua +++ b/lua/entities/acf_gun/init.lua @@ -99,8 +99,6 @@ do -- Spawn and Update functions -------------------------------- if IsValid(Phys) then Phys:SetMass(Weapon.Mass) end Entity:UpdateOverlay(true) - - CheckLegal(Entity) end function MakeACF_Weapon(Player, Pos, Angle, Data) @@ -147,6 +145,8 @@ do -- Spawn and Update functions -------------------------------- Class.OnSpawn(Gun, Data, Class, Weapon) end + CheckLegal(Gun) + return Gun end From 54d02a7b301174b6e3d047d78974270b97e4b7dc Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sun, 10 May 2020 05:43:39 -0400 Subject: [PATCH 088/279] Adjusted readded 14.5mm RAC to the new format - Registered the recently readded 14.5mm RAC with the new functions, allowing it to be spawned with the new menu. --- lua/acf/shared/guns/rotaryautocannon.lua | 24 ++++++++++++++++++++---- lua/entities/acf_gun/init.lua | 1 - 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/lua/acf/shared/guns/rotaryautocannon.lua b/lua/acf/shared/guns/rotaryautocannon.lua index 1fefdad67..12fdc6f18 100644 --- a/lua/acf/shared/guns/rotaryautocannon.lua +++ b/lua/acf/shared/guns/rotaryautocannon.lua @@ -77,6 +77,22 @@ ACF.RegisterWeaponClass("RAC", { }, }) +ACF.RegisterWeapon("14.5mmRAC", "RAC", { + Name = "14.5mm Rotary Autocannon", + Description = "A lightweight rotary autocannon, used primarily against infantry and light vehicles.", + Model = "models/rotarycannon/kw/14_5mmrac.mdl", + Caliber = 14.5, + Mass = 400, + Year = 1962, + MagSize = 250, + MagReload = 15, + Cyclic = 2250, + Round = { + MaxLength = 25, + PropMass = 0.06, + } +}) + ACF.RegisterWeapon("20mmRAC", "RAC", { Name = "20mm Rotary Autocannon", Description = "The 20mm is able to chew up light armor with decent penetration or put up a big flak screen. Typically mounted on ground attack aircraft, SPAAGs and the ocassional APC. Suffers from a moderate cooldown period between bursts to avoid overheating the barrels.", @@ -85,8 +101,8 @@ ACF.RegisterWeapon("20mmRAC", "RAC", { Mass = 760, Year = 1965, MagSize = 200, - MagReload = 25, - Cyclic = 4000, + MagReload = 20, + Cyclic = 2000, Round = { MaxLength = 30, PropMass = 0.12, @@ -101,8 +117,8 @@ ACF.RegisterWeapon("30mmRAC", "RAC", { Mass = 1500, Year = 1975, MagSize = 100, - MagReload = 35, - Cyclic = 3000, + MagReload = 30, + Cyclic = 1500, Round = { MaxLength = 40, PropMass = 0.350, diff --git a/lua/entities/acf_gun/init.lua b/lua/entities/acf_gun/init.lua index 1f5b8c13a..943704cf9 100644 --- a/lua/entities/acf_gun/init.lua +++ b/lua/entities/acf_gun/init.lua @@ -22,7 +22,6 @@ do -- Spawn and Update functions -------------------------------- local Updated = { ["20mmHRAC"] = "20mmRAC", ["30mmHRAC"] = "30mmRAC", - ["14.5mmRAC"] = "20mmRAC", } local function VerifyData(Data) From fb099119fc2173f6e80f104ab4b8c30382e12efc Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sun, 10 May 2020 06:18:32 -0400 Subject: [PATCH 089/279] Added ACF prefix to WireNames --- lua/entities/acf_engine/init.lua | 2 +- lua/entities/acf_fueltank/init.lua | 2 +- lua/entities/acf_gearbox/init.lua | 2 +- lua/entities/acf_gun/init.lua | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lua/entities/acf_engine/init.lua b/lua/entities/acf_engine/init.lua index a92bdb15b..0dfac5f67 100644 --- a/lua/entities/acf_engine/init.lua +++ b/lua/entities/acf_engine/init.lua @@ -303,7 +303,7 @@ do -- Spawn and Update functions Entity.HealthMult = EngineType.HealthMult Entity.Out = Entity:WorldToLocal(Entity:GetAttachment(Entity:LookupAttachment("driveshaft")).Pos) - Entity:SetNWString("WireName", Entity.Name) + Entity:SetNWString("WireName", "ACF" .. Entity.Name) --calculate boosted peak kw if EngineType.CalculatePeakEnergy then diff --git a/lua/entities/acf_fueltank/init.lua b/lua/entities/acf_fueltank/init.lua index b0c69306c..ed8201665 100644 --- a/lua/entities/acf_fueltank/init.lua +++ b/lua/entities/acf_fueltank/init.lua @@ -94,7 +94,7 @@ do -- Spawn and Update functions } } - Entity:SetNWString("WireName", Entity.Name) + Entity:SetNWString("WireName", "ACF " .. Entity.Name) if Entity.FuelType == "Electric" then Entity.Liters = Entity.Capacity --batteries capacity is different from internal volume diff --git a/lua/entities/acf_gearbox/init.lua b/lua/entities/acf_gearbox/init.lua index e21b5a2f8..451724666 100644 --- a/lua/entities/acf_gearbox/init.lua +++ b/lua/entities/acf_gearbox/init.lua @@ -474,7 +474,7 @@ do -- Spawn and Update functions Entity:SetBodygroup(1, 0) end - Entity:SetNWString("WireName", Entity.Name) + Entity:SetNWString("WireName", "ACF " .. Entity.Name) ACF_Activate(Entity, true) diff --git a/lua/entities/acf_gun/init.lua b/lua/entities/acf_gun/init.lua index 943704cf9..203720599 100644 --- a/lua/entities/acf_gun/init.lua +++ b/lua/entities/acf_gun/init.lua @@ -73,7 +73,7 @@ do -- Spawn and Update functions -------------------------------- Entity.Muzzle = Entity.NormalMuzzle -- Set NWvars - Entity:SetNWString("WireName", Weapon.Name) + Entity:SetNWString("WireName", "ACF " .. Weapon.Name) Entity:SetNWString("Class", Entity.Class) Entity:SetNWString("ID", Entity.Id) From 09d7d20680ef8085c1e03841327a30515bcbf464 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sun, 10 May 2020 06:19:18 -0400 Subject: [PATCH 090/279] Fixed typo --- lua/entities/acf_engine/init.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/entities/acf_engine/init.lua b/lua/entities/acf_engine/init.lua index 0dfac5f67..a83ea8c7e 100644 --- a/lua/entities/acf_engine/init.lua +++ b/lua/entities/acf_engine/init.lua @@ -303,7 +303,7 @@ do -- Spawn and Update functions Entity.HealthMult = EngineType.HealthMult Entity.Out = Entity:WorldToLocal(Entity:GetAttachment(Entity:LookupAttachment("driveshaft")).Pos) - Entity:SetNWString("WireName", "ACF" .. Entity.Name) + Entity:SetNWString("WireName", "ACF " .. Entity.Name) --calculate boosted peak kw if EngineType.CalculatePeakEnergy then From 0205e78cd4746dc87edbb99db5e1a6928c4a89ec Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sat, 16 May 2020 06:19:13 -0400 Subject: [PATCH 091/279] Updated sound paths - Updated sound paths to comply with the latest changes. --- lua/acf/shared/engines/b4.lua | 6 +++--- lua/acf/shared/engines/b6.lua | 8 ++++---- lua/acf/shared/engines/electric.lua | 12 ++++++------ lua/acf/shared/engines/i2.lua | 4 ++-- lua/acf/shared/engines/i3.lua | 12 ++++++------ lua/acf/shared/engines/i4.lua | 12 ++++++------ lua/acf/shared/engines/i5.lua | 8 ++++---- lua/acf/shared/engines/i6.lua | 12 ++++++------ lua/acf/shared/engines/radial.lua | 8 ++++---- lua/acf/shared/engines/rotary.lua | 6 +++--- lua/acf/shared/engines/single.lua | 6 +++--- lua/acf/shared/engines/special.lua | 12 ++++++------ lua/acf/shared/engines/turbine.lua | 24 ++++++++++++------------ lua/acf/shared/engines/v10.lua | 6 +++--- lua/acf/shared/engines/v12.lua | 14 +++++++------- lua/acf/shared/engines/v2.lua | 6 +++--- lua/acf/shared/engines/v4.lua | 4 ++-- lua/acf/shared/engines/v6.lua | 10 +++++----- lua/acf/shared/engines/v8.lua | 12 ++++++------ lua/acf/shared/guns/autocannon.lua | 2 +- lua/acf/shared/guns/autoloader.lua | 2 +- lua/acf/shared/guns/cannon.lua | 6 +++--- lua/acf/shared/guns/grenadelauncher.lua | 2 +- lua/acf/shared/guns/heavymachinegun.lua | 2 +- lua/acf/shared/guns/howitzer.lua | 2 +- lua/acf/shared/guns/machinegun.lua | 2 +- lua/acf/shared/guns/mortar.lua | 2 +- lua/acf/shared/guns/rotaryautocannon.lua | 2 +- lua/acf/shared/guns/semiauto.lua | 2 +- lua/acf/shared/guns/shortcannon.lua | 6 +++--- lua/acf/shared/guns/smokelauncher.lua | 2 +- lua/acf/shared/guns/smoothbore.lua | 2 +- 32 files changed, 108 insertions(+), 108 deletions(-) diff --git a/lua/acf/shared/engines/b4.lua b/lua/acf/shared/engines/b4.lua index d29218132..a0fe542c3 100644 --- a/lua/acf/shared/engines/b4.lua +++ b/lua/acf/shared/engines/b4.lua @@ -78,7 +78,7 @@ do Name = "1.4L Flat 4 Petrol", Description = "Small air cooled flat four, most commonly found in nazi insects", Model = "models/engines/b4small.mdl", - Sound = "acf_engines/b4_petrolsmall.wav", + Sound = "acf_base/engines/b4_petrolsmall.wav", Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 60, @@ -96,7 +96,7 @@ do Name = "2.1L Flat 4 Petrol", Description = "Tuned up flat four, probably find this in things that go fast in a desert.", Model = "models/engines/b4small.mdl", - Sound = "acf_engines/b4_petrolmedium.wav", + Sound = "acf_base/engines/b4_petrolmedium.wav", Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 125, @@ -132,7 +132,7 @@ do Name = "3.2L Flat 4 Petrol", Description = "Bored out fuckswindleton batshit flat four. Fuck yourself.", Model = "models/engines/b4med.mdl", - Sound = "acf_engines/b4_petrollarge.wav", + Sound = "acf_base/engines/b4_petrollarge.wav", Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 210, diff --git a/lua/acf/shared/engines/b6.lua b/lua/acf/shared/engines/b6.lua index 41072542f..86fac1f77 100644 --- a/lua/acf/shared/engines/b6.lua +++ b/lua/acf/shared/engines/b6.lua @@ -79,7 +79,7 @@ do Name = "2.8L Flat 6 Petrol", Description = "Car sized flat six engine, sporty and light", Model = "models/engines/b6small.mdl", - Sound = "acf_engines/b6_petrolsmall.wav", + Sound = "acf_base/engines/b6_petrolsmall.wav", Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 100, @@ -97,7 +97,7 @@ do Name = "5.0L Flat 6 Petrol", Description = "Sports car grade flat six, renown for their smooth operation and light weight", Model = "models/engines/b6med.mdl", - Sound = "acf_engines/b6_petrolmedium.wav", + Sound = "acf_base/engines/b6_petrolmedium.wav", Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 240, @@ -115,7 +115,7 @@ do Name = "8.3L Flat 6 Multifuel", Description = "Military-grade multifuel boxer engine. Although heavy, it is compact, durable, and has excellent performance under adverse conditions.", Model = "models/engines/b6med.mdl", - Sound = "acf_engines/v8_diesel.wav", + Sound = "acf_base/engines/v8_diesel.wav", Fuel = { Petrol = true, Diesel = true }, Type = "GenericDiesel", Mass = 480, @@ -133,7 +133,7 @@ do Name = "15.8L Flat 6 Petrol", Description = "Monstrous aircraft-grade boxer with a high rev range biased powerband", Model = "models/engines/b6large.mdl", - Sound = "acf_engines/b6_petrollarge.wav", + Sound = "acf_base/engines/b6_petrollarge.wav", Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 725, diff --git a/lua/acf/shared/engines/electric.lua b/lua/acf/shared/engines/electric.lua index 78d716c26..13067fae0 100644 --- a/lua/acf/shared/engines/electric.lua +++ b/lua/acf/shared/engines/electric.lua @@ -148,7 +148,7 @@ do -- Electric Motors Name = "Small Electric Motor", Description = "A small electric motor, loads of torque, but low power.", Model = "models/engines/emotorsmall.mdl", - Sound = "acf_engines/electric_small.wav", + Sound = "acf_base/engines/electric_small.wav", Fuel = { Electric = true }, Type = "Electric", Mass = 250, @@ -168,7 +168,7 @@ do -- Electric Motors Name = "Medium Electric Motor", Description = "A medium electric motor, loads of torque, but low power.", Model = "models/engines/emotormed.mdl", - Sound = "acf_engines/electric_medium.wav", + Sound = "acf_base/engines/electric_medium.wav", Fuel = { Electric = true }, Type = "Electric", Mass = 850, @@ -188,7 +188,7 @@ do -- Electric Motors Name = "Large Electric Motor", Description = "A huge electric motor, loads of torque, but low power.", Model = "models/engines/emotorlarge.mdl", - Sound = "acf_engines/electric_large.wav", + Sound = "acf_base/engines/electric_large.wav", Fuel = { Electric = true }, Type = "Electric", Mass = 1900, @@ -215,7 +215,7 @@ do -- Electric Standalone Motors Name = "Small Electric Standalone Motor", Description = "A small standalone electric motor, loads of torque, but low power.", Model = "models/engines/emotor-standalone-sml.mdl", - Sound = "acf_engines/electric_small.wav", + Sound = "acf_base/engines/electric_small.wav", Fuel = { Electric = true }, Type = "Electric", Mass = 125, @@ -236,7 +236,7 @@ do -- Electric Standalone Motors Name = "Medium Electric Standalone Motor", Description = "A medium standalone electric motor, loads of torque, but low power.", Model = "models/engines/emotor-standalone-mid.mdl", - Sound = "acf_engines/electric_medium.wav", + Sound = "acf_base/engines/electric_medium.wav", Fuel = { Electric = true }, Type = "Electric", Mass = 575, @@ -257,7 +257,7 @@ do -- Electric Standalone Motors Name = "Large Electric Standalone Motor", Description = "A huge standalone electric motor, loads of torque, but low power.", Model = "models/engines/emotor-standalone-big.mdl", - Sound = "acf_engines/electric_large.wav", + Sound = "acf_base/engines/electric_large.wav", Fuel = { Electric = true }, Type = "Electric", Mass = 1500, diff --git a/lua/acf/shared/engines/i2.lua b/lua/acf/shared/engines/i2.lua index 816b553b3..3134a57c2 100644 --- a/lua/acf/shared/engines/i2.lua +++ b/lua/acf/shared/engines/i2.lua @@ -46,7 +46,7 @@ do Name = "0.8L I2 Diesel", Description = "For when a 3 banger is still too bulky for your micro-needs.", Model = "models/engines/inline2s.mdl", - Sound = "acf_engines/i4_diesel2.wav", + Sound = "acf_base/engines/i4_diesel2.wav", Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 45, @@ -64,7 +64,7 @@ do Name = "10.0L I2 Diesel", Description = "TORQUE.", Model = "models/engines/inline2b.mdl", - Sound = "acf_engines/vtwin_large.wav", + Sound = "acf_base/engines/vtwin_large.wav", Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 800, diff --git a/lua/acf/shared/engines/i3.lua b/lua/acf/shared/engines/i3.lua index 27187cc74..ecf876ae9 100644 --- a/lua/acf/shared/engines/i3.lua +++ b/lua/acf/shared/engines/i3.lua @@ -116,7 +116,7 @@ do -- Petrol Engines Name = "1.2L I3 Petrol", Description = "Tiny microcar engine, efficient but weak.", Model = "models/engines/inline3s.mdl", - Sound = "acf_engines/i4_petrolsmall2.wav", + Sound = "acf_base/engines/i4_petrolsmall2.wav", Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 40, @@ -134,7 +134,7 @@ do -- Petrol Engines Name = "3.4L I3 Petrol", Description = "Short block engine for light utility use.", Model = "models/engines/inline3m.mdl", - Sound = "acf_engines/i4_petrolmedium2.wav", + Sound = "acf_base/engines/i4_petrolmedium2.wav", Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 170, @@ -152,7 +152,7 @@ do -- Petrol Engines Name = "13.5L I3 Petrol", Description = "Short block light tank engine, likes sideways mountings.", Model = "models/engines/inline3b.mdl", - Sound = "acf_engines/i4_petrollarge.wav", + Sound = "acf_base/engines/i4_petrollarge.wav", Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 500, @@ -172,7 +172,7 @@ do -- Diesel Engines Name = "1.1L I3 Diesel", Description = "ATV grade 3-banger, enormous rev band but a choppy idle, great for light utility work.", Model = "models/engines/inline3s.mdl", - Sound = "acf_engines/i4_diesel2.wav", + Sound = "acf_base/engines/i4_diesel2.wav", Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 65, @@ -190,7 +190,7 @@ do -- Diesel Engines Name = "2.8L I3 Diesel", Description = "Medium utility grade I3 diesel, for tractors", Model = "models/engines/inline3m.mdl", - Sound = "acf_engines/i4_dieselmedium.wav", + Sound = "acf_base/engines/i4_dieselmedium.wav", Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 200, @@ -208,7 +208,7 @@ do -- Diesel Engines Name = "11.0L I3 Diesel", Description = "Light tank duty engine, compact yet grunts hard.", Model = "models/engines/inline3b.mdl", - Sound = "acf_engines/i4_diesellarge.wav", + Sound = "acf_base/engines/i4_diesellarge.wav", Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 650, diff --git a/lua/acf/shared/engines/i4.lua b/lua/acf/shared/engines/i4.lua index 59380efc6..0d1aa2fd5 100644 --- a/lua/acf/shared/engines/i4.lua +++ b/lua/acf/shared/engines/i4.lua @@ -116,7 +116,7 @@ do -- Petrol Engines Name = "1.5L I4 Petrol", Description = "Small car engine, not a whole lot of git.", Model = "models/engines/inline4s.mdl", - Sound = "acf_engines/i4_petrolsmall2.wav", + Sound = "acf_base/engines/i4_petrolsmall2.wav", Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 50, @@ -134,7 +134,7 @@ do -- Petrol Engines Name = "3.7L I4 Petrol", Description = "Large inline 4, sees most use in light trucks.", Model = "models/engines/inline4m.mdl", - Sound = "acf_engines/i4_petrolmedium2.wav", + Sound = "acf_base/engines/i4_petrolmedium2.wav", Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 200, @@ -152,7 +152,7 @@ do -- Petrol Engines Name = "16.0L I4 Petrol", Description = "Giant, thirsty I4 petrol, most commonly used in boats.", Model = "models/engines/inline4l.mdl", - Sound = "acf_engines/i4_petrollarge.wav", + Sound = "acf_base/engines/i4_petrollarge.wav", Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 600, @@ -172,7 +172,7 @@ do -- Diesel Engines Name = "1.6L I4 Diesel", Description = "Small and light diesel, for low power applications requiring a wide powerband.", Model = "models/engines/inline4s.mdl", - Sound = "acf_engines/i4_diesel2.wav", + Sound = "acf_base/engines/i4_diesel2.wav", Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 90, @@ -190,7 +190,7 @@ do -- Diesel Engines Name = "3.1L I4 Diesel", Description = "Light truck duty diesel, good overall grunt.", Model = "models/engines/inline4m.mdl", - Sound = "acf_engines/i4_dieselmedium.wav", + Sound = "acf_base/engines/i4_dieselmedium.wav", Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 250, @@ -208,7 +208,7 @@ do -- Diesel Engines Name = "15.0L I4 Diesel", Description = "Small boat sized diesel, with large amounts of torque.", Model = "models/engines/inline4l.mdl", - Sound = "acf_engines/i4_diesellarge.wav", + Sound = "acf_base/engines/i4_diesellarge.wav", Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 800, diff --git a/lua/acf/shared/engines/i5.lua b/lua/acf/shared/engines/i5.lua index 94fb2e5de..509949a07 100644 --- a/lua/acf/shared/engines/i5.lua +++ b/lua/acf/shared/engines/i5.lua @@ -82,7 +82,7 @@ do -- Petrol Engines Name = "2.3L I5 Petrol", Description = "Sedan-grade 5-cylinder, solid and dependable.", Model = "models/engines/inline5s.mdl", - Sound = "acf_engines/i5_petrolsmall.wav", + Sound = "acf_base/engines/i5_petrolsmall.wav", Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 100, @@ -100,7 +100,7 @@ do -- Petrol Engines Name = "3.9L I5 Petrol", Description = "Truck sized inline 5, strong with a good balance of revs and torque.", Model = "models/engines/inline5m.mdl", - Sound = "acf_engines/i5_petrolmedium.wav", + Sound = "acf_base/engines/i5_petrolmedium.wav", Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 250, @@ -120,7 +120,7 @@ do -- Diesel Engines Name = "2.9L I5 Diesel", Description = "Aging fuel-injected diesel, low in horsepower but very forgiving and durable.", Model = "models/engines/inline5s.mdl", - Sound = "acf_engines/i5_dieselsmall2.wav", + Sound = "acf_base/engines/i5_dieselsmall2.wav", Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 130, @@ -138,7 +138,7 @@ do -- Diesel Engines Name = "4.1L I5 Diesel", Description = "Heavier duty diesel, found in things that work hard.", Model = "models/engines/inline5m.mdl", - Sound = "acf_engines/i5_dieselmedium.wav", + Sound = "acf_base/engines/i5_dieselmedium.wav", Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 400, diff --git a/lua/acf/shared/engines/i6.lua b/lua/acf/shared/engines/i6.lua index 45f12bec6..f5632fd32 100644 --- a/lua/acf/shared/engines/i6.lua +++ b/lua/acf/shared/engines/i6.lua @@ -116,7 +116,7 @@ do -- Petrol Engines Name = "2.2L I6 Petrol", Description = "Car sized I6 petrol with power in the high revs.", Model = "models/engines/inline6s.mdl", - Sound = "acf_engines/l6_petrolsmall2.wav", + Sound = "acf_base/engines/l6_petrolsmall2.wav", Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 120, @@ -134,7 +134,7 @@ do -- Petrol Engines Name = "4.8L I6 Petrol", Description = "Light truck duty I6, good for offroad applications.", Model = "models/engines/inline6m.mdl", - Sound = "acf_engines/l6_petrolmedium.wav", + Sound = "acf_base/engines/l6_petrolmedium.wav", Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 300, @@ -152,7 +152,7 @@ do -- Petrol Engines Name = "17.2L I6 Petrol", Description = "Heavy tractor duty petrol I6, decent overall powerband.", Model = "models/engines/inline6l.mdl", - Sound = "acf_engines/l6_petrollarge2.wav", + Sound = "acf_base/engines/l6_petrollarge2.wav", Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 850, @@ -172,7 +172,7 @@ do -- Diesel Engines Name = "3.0L I6 Diesel", Description = "Car sized I6 diesel, good, wide powerband.", Model = "models/engines/inline6s.mdl", - Sound = "acf_engines/l6_dieselsmall.wav", + Sound = "acf_base/engines/l6_dieselsmall.wav", Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 150, @@ -190,7 +190,7 @@ do -- Diesel Engines Name = "6.5L I6 Diesel", Description = "Truck duty I6, good overall powerband and torque.", Model = "models/engines/inline6m.mdl", - Sound = "acf_engines/l6_dieselmedium4.wav", + Sound = "acf_base/engines/l6_dieselmedium4.wav", Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 450, @@ -208,7 +208,7 @@ do -- Diesel Engines Name = "20.0L I6 Diesel", Description = "Heavy duty diesel I6, used in generators and heavy movers.", Model = "models/engines/inline6l.mdl", - Sound = "acf_engines/l6_diesellarge2.wav", + Sound = "acf_base/engines/l6_diesellarge2.wav", Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 1200, diff --git a/lua/acf/shared/engines/radial.lua b/lua/acf/shared/engines/radial.lua index 8824964a6..e20102000 100644 --- a/lua/acf/shared/engines/radial.lua +++ b/lua/acf/shared/engines/radial.lua @@ -79,7 +79,7 @@ do Name = "3.8L R7 Petrol", Description = "A tiny, old worn-out radial.", Model = "models/engines/radial7s.mdl", - Sound = "acf_engines/r7_petrolsmall.wav", + Sound = "acf_base/engines/r7_petrolsmall.wav", Fuel = { Petrol = true }, Type = "Radial", Mass = 210, @@ -97,7 +97,7 @@ do Name = "11.0L R7 Petrol", Description = "Mid range radial, thirsty and smooth.", Model = "models/engines/radial7m.mdl", - Sound = "acf_engines/r7_petrolmedium.wav", + Sound = "acf_base/engines/r7_petrolmedium.wav", Fuel = { Petrol = true }, Type = "Radial", Mass = 385, @@ -115,7 +115,7 @@ do Name = "8.0L R7 Diesel", Description = "Heavy and with a narrow powerband, but efficient, and well-optimized to cruising.", Model = "models/engines/radial7m.mdl", - Sound = "acf_engines/r7_petrolmedium.wav", + Sound = "acf_base/engines/r7_petrolmedium.wav", Fuel = { Petrol = true, Diesel = true }, Type = "GenericDiesel", Mass = 450, @@ -133,7 +133,7 @@ do Name = "24.0L R7 Petrol", Description = "Massive American radial monster, destined for fighter aircraft and heavy tanks.", Model = "models/engines/radial7l.mdl", - Sound = "acf_engines/r7_petrollarge.wav", + Sound = "acf_base/engines/r7_petrollarge.wav", Fuel = { Petrol = true }, Type = "Radial", Mass = 952, diff --git a/lua/acf/shared/engines/rotary.lua b/lua/acf/shared/engines/rotary.lua index 92e7134fd..6af84d405 100644 --- a/lua/acf/shared/engines/rotary.lua +++ b/lua/acf/shared/engines/rotary.lua @@ -62,7 +62,7 @@ do Name = "0.9L Rotary", Description = "Small 2-rotor Wankel, suited for yard use.", Model = "models/engines/wankel_2_small.mdl", - Sound = "acf_engines/wankel_small.wav", + Sound = "acf_base/engines/wankel_small.wav", Fuel = { Petrol = true }, Type = "Wankel", Mass = 50, @@ -80,7 +80,7 @@ do Name = "1.3L Rotary", Description = "Medium 2-rotor Wankel.", Model = "models/engines/wankel_2_med.mdl", - Sound = "acf_engines/wankel_medium.wav", + Sound = "acf_base/engines/wankel_medium.wav", Fuel = { Petrol = true }, Type = "Wankel", Mass = 140, @@ -98,7 +98,7 @@ do Name = "2.0L Rotary", Description = "High performance 3-rotor Wankel.", Model = "models/engines/wankel_3_med.mdl", - Sound = "acf_engines/wankel_large.wav", + Sound = "acf_base/engines/wankel_large.wav", Fuel = { Petrol = true }, Type = "Wankel", Mass = 200, diff --git a/lua/acf/shared/engines/single.lua b/lua/acf/shared/engines/single.lua index 429ea4dc8..0fc815610 100644 --- a/lua/acf/shared/engines/single.lua +++ b/lua/acf/shared/engines/single.lua @@ -61,7 +61,7 @@ do Name = "250cc Single Cylinder", Description = "Tiny bike engine.", Model = "models/engines/1cylsml.mdl", - Sound = "acf_engines/i1_small.wav", + Sound = "acf_base/engines/i1_small.wav", Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 15, @@ -79,7 +79,7 @@ do Name = "500cc Single Cylinder", Description = "Large single cylinder bike engine.", Model = "models/engines/1cylmed.mdl", - Sound = "acf_engines/i1_medium.wav", + Sound = "acf_base/engines/i1_medium.wav", Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 20, @@ -97,7 +97,7 @@ do Name = "1300cc Single Cylinder", Description = "Ridiculously large single cylinder engine, seriously what the fuck.", Model = "models/engines/1cylbig.mdl", - Sound = "acf_engines/i1_large.wav", + Sound = "acf_base/engines/i1_large.wav", Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 50, diff --git a/lua/acf/shared/engines/special.lua b/lua/acf/shared/engines/special.lua index 33ffc599f..4c694daf6 100644 --- a/lua/acf/shared/engines/special.lua +++ b/lua/acf/shared/engines/special.lua @@ -210,7 +210,7 @@ do -- Special Rotary Engines Name = "2.6L Rotary", Description = "4 rotor racing Wankel, high revving and high strung.", Model = "models/engines/wankel_4_med.mdl", - Sound = "acf_engines/wankel_large.wav", + Sound = "acf_base/engines/wankel_large.wav", Fuel = { Petrol = true }, Type = "Wankel", Mass = 260, @@ -272,7 +272,7 @@ do -- Special I4 Engines Name = "1.9L I4 Petrol", Description = "Supercharged racing 4 cylinder, most of the power in the high revs.", Model = "models/engines/inline4s.mdl", - Sound = "acf_engines/i4_special.wav", + Sound = "acf_base/engines/i4_special.wav", Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 150, @@ -314,7 +314,7 @@ do -- Special I6 Engines Name = "3.8L I6 Petrol", Description = "Large racing straight six, powerful and high revving, but lacking in torque.", Model = "models/engines/inline6m.mdl", - Sound = "acf_engines/l6_special.wav", + Sound = "acf_base/engines/l6_special.wav", Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 180, @@ -356,7 +356,7 @@ do -- Special V8 Engines Name = "2.9L V8 Petrol", Description = "Racing V8, very high revving and loud", Model = "models/engines/v8s.mdl", - Sound = "acf_engines/v8_special.wav", + Sound = "acf_base/engines/v8_special.wav", Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 180, @@ -375,7 +375,7 @@ do -- Special V8 Engines Name = "7.2L V8 Petrol", Description = "Very high revving, glorious v8 of ear rapetasticalness.", Model = "models/engines/v8m.mdl", - Sound = "acf_engines/v8_special2.wav", + Sound = "acf_base/engines/v8_special2.wav", Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 400, @@ -396,7 +396,7 @@ do -- Special V10 Engines Name = "5.3L V10 Special", Description = "Extreme performance v10", Model = "models/engines/v10sml.mdl", - Sound = "acf_engines/v10_special.wav", + Sound = "acf_base/engines/v10_special.wav", Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 300, diff --git a/lua/acf/shared/engines/turbine.lua b/lua/acf/shared/engines/turbine.lua index 6eb73000d..be6fece07 100644 --- a/lua/acf/shared/engines/turbine.lua +++ b/lua/acf/shared/engines/turbine.lua @@ -265,7 +265,7 @@ do -- Forward-facing Gas Turbines Name = "Small Gas Turbine", Description = "A small gas turbine, high power and a very wide powerband.", Model = "models/engines/gasturbine_s.mdl", - Sound = "acf_engines/turbine_small.wav", + Sound = "acf_base/engines/turbine_small.wav", Fuel = { Petrol = true, Diesel = true }, Type = "Turbine", Mass = 200, @@ -286,7 +286,7 @@ do -- Forward-facing Gas Turbines Name = "Medium Gas Turbine", Description = "A medium gas turbine, moderate power but a very wide powerband.", Model = "models/engines/gasturbine_m.mdl", - Sound = "acf_engines/turbine_medium.wav", + Sound = "acf_base/engines/turbine_medium.wav", Fuel = { Petrol = true, Diesel = true }, Type = "Turbine", Mass = 400, @@ -307,7 +307,7 @@ do -- Forward-facing Gas Turbines Name = "Large Gas Turbine", Description = "A large gas turbine, powerful with a wide powerband.", Model = "models/engines/gasturbine_l.mdl", - Sound = "acf_engines/turbine_large.wav", + Sound = "acf_base/engines/turbine_large.wav", Fuel = { Petrol = true, Diesel = true }, Type = "Turbine", Mass = 1100, @@ -330,7 +330,7 @@ do -- Transaxial Gas Turbines Name = "Small Transaxial Gas Turbine", Description = "A small gas turbine, high power and a very wide powerband. Outputs to the side instead of rear.", Model = "models/engines/turbine_s.mdl", - Sound = "acf_engines/turbine_small.wav", + Sound = "acf_base/engines/turbine_small.wav", Fuel = { Petrol = true, Diesel = true }, Type = "Turbine", Mass = 160, @@ -352,7 +352,7 @@ do -- Transaxial Gas Turbines Name = "Medium Transaxial Gas Turbine", Description = "A medium gas turbine, moderate power but a very wide powerband. Outputs to the side instead of rear.", Model = "models/engines/turbine_m.mdl", - Sound = "acf_engines/turbine_medium.wav", + Sound = "acf_base/engines/turbine_medium.wav", Fuel = { Petrol = true, Diesel = true }, Type = "Turbine", Mass = 320, @@ -374,7 +374,7 @@ do -- Transaxial Gas Turbines Name = "Large Transaxial Gas Turbine", Description = "A large gas turbine, powerful with a wide powerband. Outputs to the side instead of rear.", Model = "models/engines/turbine_l.mdl", - Sound = "acf_engines/turbine_large.wav", + Sound = "acf_base/engines/turbine_large.wav", Fuel = { Petrol = true, Diesel = true }, Type = "Turbine", Mass = 880, @@ -403,7 +403,7 @@ do -- Forward-facing Ground Gas Turbines Name = "Small Ground Gas Turbine", Description = "A small gas turbine, fitted with ground-use air filters and tuned for ground use.", Model = "models/engines/gasturbine_s.mdl", - Sound = "acf_engines/turbine_small.wav", + Sound = "acf_base/engines/turbine_small.wav", Fuel = { Petrol = true, Diesel = true }, Type = "Radial", Mass = 350, @@ -424,7 +424,7 @@ do -- Forward-facing Ground Gas Turbines Name = "Medium Ground Gas Turbine", Description = "A medium gas turbine, fitted with ground-use air filters and tuned for ground use.", Model = "models/engines/gasturbine_m.mdl", - Sound = "acf_engines/turbine_medium.wav", + Sound = "acf_base/engines/turbine_medium.wav", Fuel = { Petrol = true, Diesel = true }, Type = "Radial", --This is done to give proper fuel consumption and make the turbines not instant-torque from idle Mass = 600, @@ -446,7 +446,7 @@ do -- Forward-facing Ground Gas Turbines Name = "Large Ground Gas Turbine", Description = "A large gas turbine, fitted with ground-use air filters and tuned for ground use.", Model = "models/engines/gasturbine_l.mdl", - Sound = "acf_engines/turbine_large.wav", + Sound = "acf_base/engines/turbine_large.wav", Fuel = { Petrol = true, Diesel = true }, Type = "Radial", Mass = 1650, @@ -470,7 +470,7 @@ do -- Transaxial Ground Gas Turbines Name = "Small Transaxial Ground Gas Turbine", Description = "A small gas turbine fitted with ground-use air filters and tuned for ground use. Outputs to the side instead of rear.", Model = "models/engines/turbine_s.mdl", - Sound = "acf_engines/turbine_small.wav", + Sound = "acf_base/engines/turbine_small.wav", Fuel = { Petrol = true, Diesel = true }, Type = "Radial", Mass = 280, @@ -492,7 +492,7 @@ do -- Transaxial Ground Gas Turbines Name = "Medium Transaxial Ground Gas Turbine", Description = "A medium gas turbine fitted with ground-use air filters and tuned for ground use. Outputs to the side instead of rear.", Model = "models/engines/turbine_m.mdl", - Sound = "acf_engines/turbine_medium.wav", + Sound = "acf_base/engines/turbine_medium.wav", Fuel = { Petrol = true, Diesel = true }, Type = "Radial", Mass = 480, @@ -515,7 +515,7 @@ do -- Transaxial Ground Gas Turbines Name = "Large Transaxial Ground Gas Turbine", Description = "A large gas turbine fitted with ground-use air filters and tuned for ground use. Outputs to the side instead of rear.", Model = "models/engines/turbine_l.mdl", - Sound = "acf_engines/turbine_large.wav", + Sound = "acf_base/engines/turbine_large.wav", Fuel = { Petrol = true, Diesel = true }, Type = "Radial", Mass = 1320, diff --git a/lua/acf/shared/engines/v10.lua b/lua/acf/shared/engines/v10.lua index c43de32f4..a7eab9423 100644 --- a/lua/acf/shared/engines/v10.lua +++ b/lua/acf/shared/engines/v10.lua @@ -60,7 +60,7 @@ do Name = "4.3L V10 Petrol", Description = "Small-block V-10 gasoline engine, great for powering a hot rod lincoln", Model = "models/engines/v10sml.mdl", - Sound = "acf_engines/v10_petrolsmall.wav", + Sound = "acf_base/engines/v10_petrolsmall.wav", Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 160, @@ -78,7 +78,7 @@ do Name = "8.0L V10 Petrol", Description = "Beefy 10-cylinder gas engine, gets 9 kids to soccer practice", Model = "models/engines/v10med.mdl", - Sound = "acf_engines/v10_petrolmedium.wav", + Sound = "acf_base/engines/v10_petrolmedium.wav", Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 300, @@ -96,7 +96,7 @@ do Name = "22.0L V10 Multifuel", Description = "Heavy multifuel V-10, gearbox-shredding torque but very heavy.", Model = "models/engines/v10big.mdl", - Sound = "acf_engines/v10_diesellarge.wav", + Sound = "acf_base/engines/v10_diesellarge.wav", Fuel = { Petrol = true, Diesel = true }, Type = "GenericDiesel", Mass = 1600, diff --git a/lua/acf/shared/engines/v12.lua b/lua/acf/shared/engines/v12.lua index f90fc398c..dfd67e417 100644 --- a/lua/acf/shared/engines/v12.lua +++ b/lua/acf/shared/engines/v12.lua @@ -133,7 +133,7 @@ do -- Petrol Engines Name = "4.6L V12 Petrol", Description = "An elderly racecar engine; low on torque, but plenty of power", Model = "models/engines/v12s.mdl", - Sound = "acf_engines/v12_petrolsmall.wav", + Sound = "acf_base/engines/v12_petrolsmall.wav", Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 188, @@ -151,7 +151,7 @@ do -- Petrol Engines Name = "7.0L V12 Petrol", Description = "A high end V12; primarily found in very expensive cars", Model = "models/engines/v12m.mdl", - Sound = "acf_engines/v12_petrolmedium.wav", + Sound = "acf_base/engines/v12_petrolmedium.wav", Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 360, @@ -169,7 +169,7 @@ do -- Petrol Engines Name = "13.0L V12 Petrol", Description = "Thirsty gasoline v12, good torque and power for medium applications.", Model = "models/engines/v12m.mdl", - Sound = "acf_engines/v12_special.wav", + Sound = "acf_base/engines/v12_special.wav", Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 520, @@ -187,7 +187,7 @@ do -- Petrol Engines Name = "23.0L V12 Petrol", Description = "A large, thirsty gasoline V12, found in early cold war tanks", Model = "models/engines/v12l.mdl", - Sound = "acf_engines/v12_petrollarge.wav", + Sound = "acf_base/engines/v12_petrollarge.wav", Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 1350, @@ -207,7 +207,7 @@ do -- Diesel Engines Name = "4.0L V12 Diesel", Description = "Reliable truck-duty diesel; a lot of smooth torque", Model = "models/engines/v12s.mdl", - Sound = "acf_engines/v12_dieselsmall.wav", + Sound = "acf_base/engines/v12_dieselsmall.wav", Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 305, @@ -225,7 +225,7 @@ do -- Diesel Engines Name = "9.2L V12 Diesel", Description = "High torque light-tank V12, used mainly for vehicles that require balls", Model = "models/engines/v12m.mdl", - Sound = "acf_engines/v12_dieselmedium.wav", + Sound = "acf_base/engines/v12_dieselmedium.wav", Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 600, @@ -243,7 +243,7 @@ do -- Diesel Engines Name = "21.0L V12 Diesel", Description = "AVDS-1790-2 tank engine; massively powerful, but enormous and heavy", Model = "models/engines/v12l.mdl", - Sound = "acf_engines/v12_diesellarge.wav", + Sound = "acf_base/engines/v12_diesellarge.wav", Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 1800, diff --git a/lua/acf/shared/engines/v2.lua b/lua/acf/shared/engines/v2.lua index d2887134d..72a3ff763 100644 --- a/lua/acf/shared/engines/v2.lua +++ b/lua/acf/shared/engines/v2.lua @@ -61,7 +61,7 @@ do -- Petrol Engines Name = "600cc V-Twin", Description = "Twin cylinder bike engine, torquey for its size", Model = "models/engines/v-twins2.mdl", - Sound = "acf_engines/vtwin_small.wav", + Sound = "acf_base/engines/vtwin_small.wav", Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 30, @@ -79,7 +79,7 @@ do -- Petrol Engines Name = "1200cc V-Twin", Description = "Large displacement vtwin engine", Model = "models/engines/v-twinm2.mdl", - Sound = "acf_engines/vtwin_medium.wav", + Sound = "acf_base/engines/vtwin_medium.wav", Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 50, @@ -97,7 +97,7 @@ do -- Petrol Engines Name = "2400cc V-Twin", Description = "Huge fucking Vtwin 'MURRICA FUCK YEAH", Model = "models/engines/v-twinl2.mdl", - Sound = "acf_engines/vtwin_large.wav", + Sound = "acf_base/engines/vtwin_large.wav", Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 100, diff --git a/lua/acf/shared/engines/v4.lua b/lua/acf/shared/engines/v4.lua index 1fe6c5e0b..112d0793b 100644 --- a/lua/acf/shared/engines/v4.lua +++ b/lua/acf/shared/engines/v4.lua @@ -46,7 +46,7 @@ do -- Diesel Engines Name = "1.9L V4 Diesel", Description = "Torquey little lunchbox; for those smaller vehicles that don't agree with petrol powerbands", Model = "models/engines/v4s.mdl", - Sound = "acf_engines/i4_diesel2.wav", + Sound = "acf_base/engines/i4_diesel2.wav", Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 110, @@ -64,7 +64,7 @@ do -- Diesel Engines Name = "3.3L V4 Diesel", Description = "Compact cube of git; for moderate utility applications", Model = "models/engines/v4m.mdl", - Sound = "acf_engines/i4_dieselmedium.wav", + Sound = "acf_base/engines/i4_dieselmedium.wav", Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 275, diff --git a/lua/acf/shared/engines/v6.lua b/lua/acf/shared/engines/v6.lua index 8ef57035e..18201853a 100644 --- a/lua/acf/shared/engines/v6.lua +++ b/lua/acf/shared/engines/v6.lua @@ -96,7 +96,7 @@ do -- Petrol Engines Name = "3.6L V6 Petrol", Description = "Meaty Car sized V6, lots of torque.", Model = "models/engines/v6small.mdl", - Sound = "acf_engines/v6_petrolsmall.wav", + Sound = "acf_base/engines/v6_petrolsmall.wav", Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 190, @@ -114,7 +114,7 @@ do -- Petrol Engines Name = "6.2L V6 Petrol", Description = "Heavy duty 6V71 v6, throatier than an LA whore, but loaded with torque.", Model = "models/engines/v6med.mdl", - Sound = "acf_engines/v6_petrolmedium.wav", + Sound = "acf_base/engines/v6_petrolmedium.wav", Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 360, @@ -132,7 +132,7 @@ do -- Petrol Engines Name = "12.0L V6 Petrol", Description = "Fuck duty V6, guts ripped from god himself diluted in salt and shaped into an engine.", Model = "models/engines/v6large.mdl", - Sound = "acf_engines/v6_petrollarge.wav", + Sound = "acf_base/engines/v6_petrollarge.wav", Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 675, @@ -152,7 +152,7 @@ do -- Diesel Engines Name = "5.2L V6 Diesel", Description = "Light AFV-grade two-stroke diesel, high output but heavy.", Model = "models/engines/v6med.mdl", - Sound = "acf_engines/i5_dieselmedium.wav", + Sound = "acf_base/engines/i5_dieselmedium.wav", Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 520, @@ -170,7 +170,7 @@ do -- Diesel Engines Name = "15.0L V6 Diesel", Description = "Powerful military-grade large V6, with impressive output. Well suited to medium-sized AFVs.", Model = "models/engines/v6large.mdl", - Sound = "acf_engines/v6_diesellarge.wav", + Sound = "acf_base/engines/v6_diesellarge.wav", Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 900, diff --git a/lua/acf/shared/engines/v8.lua b/lua/acf/shared/engines/v8.lua index c2dfeffc4..b8743876b 100644 --- a/lua/acf/shared/engines/v8.lua +++ b/lua/acf/shared/engines/v8.lua @@ -116,7 +116,7 @@ do -- Petrol Engines Name = "5.7L V8 Petrol", Description = "Car sized petrol engine, good power and mid range torque", Model = "models/engines/v8s.mdl", - Sound = "acf_engines/v8_petrolsmall.wav", + Sound = "acf_base/engines/v8_petrolsmall.wav", Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 260, @@ -134,7 +134,7 @@ do -- Petrol Engines Name = "9.0L V8 Petrol", Description = "Thirsty, giant V8, for medium applications", Model = "models/engines/v8m.mdl", - Sound = "acf_engines/v8_petrolmedium.wav", + Sound = "acf_base/engines/v8_petrolmedium.wav", Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 400, @@ -152,7 +152,7 @@ do -- Petrol Engines Name = "18.0L V8 Petrol", Description = "American gasoline tank V8, good overall power and torque and fairly lightweight", Model = "models/engines/v8l.mdl", - Sound = "acf_engines/v8_petrollarge.wav", + Sound = "acf_base/engines/v8_petrollarge.wav", Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 850, @@ -172,7 +172,7 @@ do -- Diesel Engines Name = "4.5L V8 Diesel", Description = "Light duty diesel v8, good for light vehicles that require a lot of torque", Model = "models/engines/v8s.mdl", - Sound = "acf_engines/v8_dieselsmall.wav", + Sound = "acf_base/engines/v8_dieselsmall.wav", Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 320, @@ -190,7 +190,7 @@ do -- Diesel Engines Name = "7.8L V8 Diesel", Description = "Redneck chariot material. Truck duty V8 diesel, has a good, wide powerband", Model = "models/engines/v8m.mdl", - Sound = "acf_engines/v8_dieselmedium2.wav", + Sound = "acf_base/engines/v8_dieselmedium2.wav", Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 520, @@ -208,7 +208,7 @@ do -- Diesel Engines Name = "19.0L V8 Diesel", Description = "Heavy duty diesel V8, used in heavy construction equipment and tanks", Model = "models/engines/v8l.mdl", - Sound = "acf_engines/v8_diesellarge.wav", + Sound = "acf_base/engines/v8_diesellarge.wav", Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 1200, diff --git a/lua/acf/shared/guns/autocannon.lua b/lua/acf/shared/guns/autocannon.lua index 510075317..22e733b66 100644 --- a/lua/acf/shared/guns/autocannon.lua +++ b/lua/acf/shared/guns/autocannon.lua @@ -89,7 +89,7 @@ ACF.RegisterWeaponClass("AC", { Description = "Autocannons have a rather high weight and bulk for the ammo they fire, but they can fire it extremely fast.", MuzzleFlash = "auto_muzzleflash_noscale", Spread = 0.25, - Sound = "weapons/ACF_Gun/ac_fire4.mp3", + Sound = "acf_base/weapons/ac_fire4.mp3", Caliber = { Min = 20, Max = 50, diff --git a/lua/acf/shared/guns/autoloader.lua b/lua/acf/shared/guns/autoloader.lua index 9d6cf73d8..b57b56cf0 100644 --- a/lua/acf/shared/guns/autoloader.lua +++ b/lua/acf/shared/guns/autoloader.lua @@ -108,7 +108,7 @@ ACF.RegisterWeaponClass("AL", { Description = "A cannon with attached autoloading mechanism. While it allows for several quick shots, the mechanism adds considerable bulk, weight, and magazine reload time.", MuzzleFlash = "cannon_muzzleflash_noscale", Spread = 0.08, - Sound = "weapons/ACF_Gun/autoloader.mp3", + Sound = "acf_base/weapons/autoloader.mp3", Caliber = { Min = 75, Max = 140, diff --git a/lua/acf/shared/guns/cannon.lua b/lua/acf/shared/guns/cannon.lua index 8adb01ac0..c63cd6a1c 100644 --- a/lua/acf/shared/guns/cannon.lua +++ b/lua/acf/shared/guns/cannon.lua @@ -120,7 +120,7 @@ ACF.RegisterWeaponClass("C", { Description = "High velocity guns that can fire very powerful ammunition, but are rather slow to reload.", MuzzleFlash = "cannon_muzzleflash_noscale", Spread = 0.08, - Sound = "weapons/ACF_Gun/cannon_new.mp3", + Sound = "acf_base/weapons/cannon_new.mp3", Caliber = { Min = 20, Max = 140, @@ -134,7 +134,7 @@ ACF.RegisterWeapon("37mmC", "C", { Caliber = 37, Mass = 350, Year = 1919, - Sound = "weapons/ACF_Gun/ac_fire4.mp3", + Sound = "acf_base/weapons/ac_fire4.mp3", Round = { MaxLength = 48, PropMass = 1.125, @@ -148,7 +148,7 @@ ACF.RegisterWeapon("50mmC", "C", { Caliber = 50, Mass = 665, Year = 1935, - Sound = "weapons/ACF_Gun/ac_fire4.mp3", + Sound = "acf_base/weapons/ac_fire4.mp3", Round = { MaxLength = 63, PropMass = 2.1, diff --git a/lua/acf/shared/guns/grenadelauncher.lua b/lua/acf/shared/guns/grenadelauncher.lua index 9aa30905f..e9b61032b 100644 --- a/lua/acf/shared/guns/grenadelauncher.lua +++ b/lua/acf/shared/guns/grenadelauncher.lua @@ -33,7 +33,7 @@ ACF.RegisterWeaponClass("GL", { Description = "Grenade Launchers can fire shells with relatively large payloads at a fast rate, but with very limited velocities and poor accuracy.", MuzzleFlash = "gl_muzzleflash_noscale", Spread = 0.32, - Sound = "weapons/acf_gun/grenadelauncher.mp3", + Sound = "acf_base/weapons/grenadelauncher.mp3", Caliber = { Min = 25, Max = 40, diff --git a/lua/acf/shared/guns/heavymachinegun.lua b/lua/acf/shared/guns/heavymachinegun.lua index 612aaefc1..615fd636b 100644 --- a/lua/acf/shared/guns/heavymachinegun.lua +++ b/lua/acf/shared/guns/heavymachinegun.lua @@ -93,7 +93,7 @@ ACF.RegisterWeaponClass("HMG", { Description = "Designed as autocannons for aircraft, HMGs are rapid firing, lightweight, and compact but sacrifice accuracy, magazine size, and reload times.", MuzzleFlash = "mg_muzzleflash_noscale", Spread = 1.3, - Sound = "weapons/ACF_Gun/mg_fire3.mp3", + Sound = "acf_base/weapons/mg_fire3.mp3", Caliber = { Min = 13, Max = 40, diff --git a/lua/acf/shared/guns/howitzer.lua b/lua/acf/shared/guns/howitzer.lua index dfd8cf52d..45a90c911 100644 --- a/lua/acf/shared/guns/howitzer.lua +++ b/lua/acf/shared/guns/howitzer.lua @@ -117,7 +117,7 @@ ACF.RegisterWeaponClass("HW", { Description = "Howitzers are limited to rather mediocre muzzle velocities, but can fire extremely heavy projectiles with large useful payload capacities.", MuzzleFlash = "howie_muzzleflash_noscale", Spread = 0.12, - Sound = "weapons/ACF_Gun/howitzer_new2.mp3", + Sound = "acf_base/weapons/howitzer_new2.mp3", Caliber = { Min = 75, Max = 203, diff --git a/lua/acf/shared/guns/machinegun.lua b/lua/acf/shared/guns/machinegun.lua index d66c7f59d..71e047410 100644 --- a/lua/acf/shared/guns/machinegun.lua +++ b/lua/acf/shared/guns/machinegun.lua @@ -71,7 +71,7 @@ ACF.RegisterWeaponClass("MG", { Description = "Machineguns are light guns that fire equally light bullets at a fast rate.", MuzzleFlash = "mg_muzzleflash_noscale", Spread = 0.24, - Sound = "weapons/ACF_Gun/mg_fire4.mp3", + Sound = "acf_base/weapons/mg_fire4.mp3", Caliber = { Min = 5.56, Max = 14.5, diff --git a/lua/acf/shared/guns/mortar.lua b/lua/acf/shared/guns/mortar.lua index 930efac9a..44131499a 100644 --- a/lua/acf/shared/guns/mortar.lua +++ b/lua/acf/shared/guns/mortar.lua @@ -104,7 +104,7 @@ ACF.RegisterWeaponClass("MO", { Description = "Mortars are able to fire shells with usefull payloads from a light weight gun, at the price of limited velocities.", MuzzleFlash = "mortar_muzzleflash_noscale", Spread = 0.64, - Sound = "weapons/ACF_Gun/mortar_new.mp3", + Sound = "acf_base/weapons/mortar_new.mp3", Caliber = { Min = 37, Max = 150, diff --git a/lua/acf/shared/guns/rotaryautocannon.lua b/lua/acf/shared/guns/rotaryautocannon.lua index a188fc8e9..fdc72d954 100644 --- a/lua/acf/shared/guns/rotaryautocannon.lua +++ b/lua/acf/shared/guns/rotaryautocannon.lua @@ -70,7 +70,7 @@ ACF.RegisterWeaponClass("RAC", { Description = "Rotary Autocannons sacrifice weight, bulk and accuracy over classic autocannons to get the highest rate of fire possible.", MuzzleFlash = "mg_muzzleflash_noscale", Spread = 0.4, - Sound = "weapons/acf_gun/mg_fire3.mp3", + Sound = "acf_base/weapons/mg_fire3.mp3", Caliber = { Min = 7.62, Max = 30, diff --git a/lua/acf/shared/guns/semiauto.lua b/lua/acf/shared/guns/semiauto.lua index 4262faa48..424bbd9db 100644 --- a/lua/acf/shared/guns/semiauto.lua +++ b/lua/acf/shared/guns/semiauto.lua @@ -107,7 +107,7 @@ ACF.RegisterWeaponClass("SA", { Description = "Semiautomatic cannons offer light weight, small size, and high rates of fire at the cost of often reloading and low accuracy.", MuzzleFlash = "semi_muzzleflash_noscale", Spread = 1.1, - Sound = "weapons/acf_gun/sa_fire1.mp3", + Sound = "acf_base/weapons/sa_fire1.mp3", Caliber = { Min = 20, Max = 76, diff --git a/lua/acf/shared/guns/shortcannon.lua b/lua/acf/shared/guns/shortcannon.lua index 97b2c2150..ac89ebd28 100644 --- a/lua/acf/shared/guns/shortcannon.lua +++ b/lua/acf/shared/guns/shortcannon.lua @@ -104,7 +104,7 @@ ACF.RegisterWeaponClass("SC", { Description = "Short cannons trade muzzle velocity and accuracy for lighter weight and smaller size, with more penetration than howitzers and lighter than cannons.", MuzzleFlash = "cannon_muzzleflash_noscale", Spread = 0.2, - Sound = "weapons/ACF_Gun/cannon_new.mp3", + Sound = "acf_base/weapons/cannon_new.mp3", Caliber = { Min = 37, Max = 140, @@ -118,7 +118,7 @@ ACF.RegisterWeapon("37mmSC", "SC", { Caliber = 37, Mass = 200, Year = 1915, - Sound = "weapons/ACF_Gun/ac_fire4.mp3", + Sound = "acf_base/weapons/ac_fire4.mp3", Round = { MaxLength = 45, PropMass = 0.29, @@ -132,7 +132,7 @@ ACF.RegisterWeapon("50mmSC", "SC", { Caliber = 50, Mass = 330, Year = 1915, - Sound = "weapons/ACF_Gun/ac_fire4.mp3", + Sound = "acf_base/weapons/ac_fire4.mp3", Round = { MaxLength = 63, PropMass = 0.6, diff --git a/lua/acf/shared/guns/smokelauncher.lua b/lua/acf/shared/guns/smokelauncher.lua index a4f1403c2..d196dcc77 100644 --- a/lua/acf/shared/guns/smokelauncher.lua +++ b/lua/acf/shared/guns/smokelauncher.lua @@ -56,7 +56,7 @@ ACF.RegisterWeaponClass("SL", { Description = "Smoke launcher to block an attacker's line of sight.", MuzzleFlash = "gl_muzzleflash_noscale", Spread = 0.32, - Sound = "weapons/acf_gun/smoke_launch.mp3", + Sound = "acf_base/weapons/smoke_launch.mp3", LimitConVar = { Name = "_acf_smokelauncher", Amount = 10, diff --git a/lua/acf/shared/guns/smoothbore.lua b/lua/acf/shared/guns/smoothbore.lua index cc4487067..67a2d08f4 100644 --- a/lua/acf/shared/guns/smoothbore.lua +++ b/lua/acf/shared/guns/smoothbore.lua @@ -76,7 +76,7 @@ ACF.RegisterWeaponClass("SB", { Description = "More modern smoothbore cannons that can only fire munitions that do not rely on spinning for accuracy.", MuzzleFlash = "cannon_muzzleflash_noscale", Spread = 0.08, - Sound = "weapons/ACF_Gun/cannon_new.mp3", + Sound = "acf_base/weapons/cannon_new.mp3", Caliber = { Min = 20, Max = 140, From 3e48f6d9f01c22513e3c1b804b421fdd6c9b3cfd Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Thu, 21 May 2020 04:07:15 -0400 Subject: [PATCH 092/279] Moved entity link functions - Moved entity link related function to the serverside utils file. --- lua/acf/base/sv_validation.lua | 110 --------------------------------- lua/acf/base/util/sv_util.lua | 110 +++++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+), 110 deletions(-) diff --git a/lua/acf/base/sv_validation.lua b/lua/acf/base/sv_validation.lua index 9f4a860e9..4878dc5aa 100644 --- a/lua/acf/base/sv_validation.lua +++ b/lua/acf/base/sv_validation.lua @@ -162,116 +162,6 @@ function ACF_Activate(Entity, Recalc) end end -do -- Entity Links ------------------------------ - local EntityLink = {} - local function GetEntityLinks(Entity, VarName, SingleEntry) - if not Entity[VarName] then return {} end - - if SingleEntry then - return { [Entity[VarName]] = true } - end - - local Result = {} - - for K in pairs(Entity[VarName]) do - Result[K] = true - end - - return Result - end - - -- If your entity can link/unlink other entities, you should use this - function ACF.RegisterLinkSource(Class, VarName, SingleEntry) - local Data = EntityLink[Class] - - if not Data then - EntityLink[Class] = { - [VarName] = function(Entity) - return GetEntityLinks(Entity, VarName, SingleEntry) - end - } - else - Data[VarName] = function(Entity) - return GetEntityLinks(Entity, VarName, SingleEntry) - end - end - end - - function ACF.GetAllLinkSources(Class) - if not EntityLink[Class] then return {} end - - local Result = {} - - for K, V in pairs(EntityLink[Class]) do - Result[K] = V - end - - return Result - end - - function ACF.GetLinkSource(Class, VarName) - if not EntityLink[Class] then return end - - return EntityLink[Class][VarName] - end - - local ClassLink = { Link = {}, Unlink = {} } - local function RegisterNewLink(Action, Class1, Class2, Function) - if not isfunction(Function) then return end - - local Target = ClassLink[Action] - local Data1 = Target[Class1] - - if not Data1 then - Target[Class1] = { - [Class2] = function(Ent1, Ent2) - return Function(Ent1, Ent2) - end - } - else - Data1[Class2] = function(Ent1, Ent2) - return Function(Ent1, Ent2) - end - end - - if Class1 == Class2 then return end - - local Data2 = Target[Class2] - - if not Data2 then - Target[Class2] = { - [Class1] = function(Ent2, Ent1) - return Function(Ent1, Ent2) - end - } - else - Data2[Class1] = function(Ent2, Ent1) - return Function(Ent1, Ent2) - end - end - end - - function ACF.RegisterClassLink(Class1, Class2, Function) - RegisterNewLink("Link", Class1, Class2, Function) - end - - function ACF.GetClassLink(Class1, Class2) - if not ClassLink.Link[Class1] then return end - - return ClassLink.Link[Class1][Class2] - end - - function ACF.RegisterClassUnlink(Class1, Class2, Function) - RegisterNewLink("Unlink", Class1, Class2, Function) - end - - function ACF.GetClassUnlink(Class1, Class2) - if not ClassLink.Unlink[Class1] then return end - - return ClassLink.Unlink[Class1][Class2] - end -end --------------------------------------------- - -- Globalize ------------------------------------ ACF.GlobalFilter = Baddies ACF_IsLegal = IsLegal diff --git a/lua/acf/base/util/sv_util.lua b/lua/acf/base/util/sv_util.lua index a50c48b81..8ddeba080 100644 --- a/lua/acf/base/util/sv_util.lua +++ b/lua/acf/base/util/sv_util.lua @@ -183,6 +183,116 @@ do -- Entity saving and restoring end end +do -- Entity linking + local EntityLink = {} + local function GetEntityLinks(Entity, VarName, SingleEntry) + if not Entity[VarName] then return {} end + + if SingleEntry then + return { [Entity[VarName]] = true } + end + + local Result = {} + + for K in pairs(Entity[VarName]) do + Result[K] = true + end + + return Result + end + + -- If your entity can link/unlink other entities, you should use this + function ACF.RegisterLinkSource(Class, VarName, SingleEntry) + local Data = EntityLink[Class] + + if not Data then + EntityLink[Class] = { + [VarName] = function(Entity) + return GetEntityLinks(Entity, VarName, SingleEntry) + end + } + else + Data[VarName] = function(Entity) + return GetEntityLinks(Entity, VarName, SingleEntry) + end + end + end + + function ACF.GetAllLinkSources(Class) + if not EntityLink[Class] then return {} end + + local Result = {} + + for K, V in pairs(EntityLink[Class]) do + Result[K] = V + end + + return Result + end + + function ACF.GetLinkSource(Class, VarName) + if not EntityLink[Class] then return end + + return EntityLink[Class][VarName] + end + + local ClassLink = { Link = {}, Unlink = {} } + local function RegisterNewLink(Action, Class1, Class2, Function) + if not isfunction(Function) then return end + + local Target = ClassLink[Action] + local Data1 = Target[Class1] + + if not Data1 then + Target[Class1] = { + [Class2] = function(Ent1, Ent2) + return Function(Ent1, Ent2) + end + } + else + Data1[Class2] = function(Ent1, Ent2) + return Function(Ent1, Ent2) + end + end + + if Class1 == Class2 then return end + + local Data2 = Target[Class2] + + if not Data2 then + Target[Class2] = { + [Class1] = function(Ent2, Ent1) + return Function(Ent1, Ent2) + end + } + else + Data2[Class1] = function(Ent2, Ent1) + return Function(Ent1, Ent2) + end + end + end + + function ACF.RegisterClassLink(Class1, Class2, Function) + RegisterNewLink("Link", Class1, Class2, Function) + end + + function ACF.GetClassLink(Class1, Class2) + if not ClassLink.Link[Class1] then return end + + return ClassLink.Link[Class1][Class2] + end + + function ACF.RegisterClassUnlink(Class1, Class2, Function) + RegisterNewLink("Unlink", Class1, Class2, Function) + end + + function ACF.GetClassUnlink(Class1, Class2) + if not ClassLink.Unlink[Class1] then return end + + return ClassLink.Unlink[Class1][Class2] + end +end + function ACF_GetHitAngle(HitNormal, HitVector) return math.min(math.deg(math.acos(HitNormal:Dot(-HitVector:GetNormalized()))), 89.999) end \ No newline at end of file From 850226ff0552b07dd5860ba046945a1ac81f7f0a Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Thu, 21 May 2020 04:10:25 -0400 Subject: [PATCH 093/279] Added entity input actions functions - Added serverside ACF.AddInputAction function to simplify the process of adding new inputs to ACF entities. - Added serverside ACF.GetInputAction and ACF.GetInputActions functions to simplify the process of retreiving a specific input action of a specific entity class. --- lua/acf/base/util/sv_util.lua | 49 +++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/lua/acf/base/util/sv_util.lua b/lua/acf/base/util/sv_util.lua index 8ddeba080..1a9de6434 100644 --- a/lua/acf/base/util/sv_util.lua +++ b/lua/acf/base/util/sv_util.lua @@ -293,6 +293,55 @@ do -- Entity linking end end +do -- Entity inputs + local Inputs = {} + + local function GetClass(Class, Add) + if Add and not Inputs[Class] then + Inputs[Class] = {} + end + + return Inputs[Class] + end + + function ACF.AddInputAction(Class, Name, Action) + if not Class then return end + if not Name then return end + if not isfunction(Action) then return end + + local Data = GetClass(Class, true) + + Data[Name] = Action + end + + function ACF.GetInputAction(Class, Name) + if not Class then return end + if not Name then return end + + local Data = GetClass(Class) + + if not Data then return end + + return Data[Name] + end + + function ACF.GetInputActions(Class) + if not Class then return end + + local Data = GetClass(Class) + + if not Data then return end + + local Result = {} + + for K, V in pairs(Data) do + Result[K] = V + end + + return Result + end +end + function ACF_GetHitAngle(HitNormal, HitVector) return math.min(math.deg(math.acos(HitNormal:Dot(-HitVector:GetNormalized()))), 89.999) end \ No newline at end of file From 2b348dbcb2960b0671de6303bef0cfe3ffd16238 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Thu, 21 May 2020 05:38:09 -0400 Subject: [PATCH 094/279] Modified entities to use input action functions - All ACF entities will now use the recently added input action functions. - Using any of the input action functions will register a new class if it hasn't been registered before. - ACF.GetInputActions won't return a copy of the desired class input actions but the actual table of them. --- lua/acf/base/util/sv_util.lua | 20 +--- lua/entities/acf_ammo/init.lua | 18 ++-- lua/entities/acf_engine/init.lua | 28 +++--- lua/entities/acf_fueltank/init.lua | 42 +++++---- lua/entities/acf_gearbox/init.lua | 141 ++++++++++++++++------------- lua/entities/acf_gun/init.lua | 61 ++++++++----- 6 files changed, 170 insertions(+), 140 deletions(-) diff --git a/lua/acf/base/util/sv_util.lua b/lua/acf/base/util/sv_util.lua index 1a9de6434..f86659d36 100644 --- a/lua/acf/base/util/sv_util.lua +++ b/lua/acf/base/util/sv_util.lua @@ -296,8 +296,8 @@ end do -- Entity inputs local Inputs = {} - local function GetClass(Class, Add) - if Add and not Inputs[Class] then + local function GetClass(Class) + if not Inputs[Class] then Inputs[Class] = {} end @@ -309,7 +309,7 @@ do -- Entity inputs if not Name then return end if not isfunction(Action) then return end - local Data = GetClass(Class, true) + local Data = GetClass(Class) Data[Name] = Action end @@ -320,25 +320,13 @@ do -- Entity inputs local Data = GetClass(Class) - if not Data then return end - return Data[Name] end function ACF.GetInputActions(Class) if not Class then return end - local Data = GetClass(Class) - - if not Data then return end - - local Result = {} - - for K, V in pairs(Data) do - Result[K] = V - end - - return Result + return GetClass(Class) end end diff --git a/lua/entities/acf_ammo/init.lua b/lua/entities/acf_ammo/init.lua index f33a87ec7..23fb3808d 100644 --- a/lua/entities/acf_ammo/init.lua +++ b/lua/entities/acf_ammo/init.lua @@ -10,6 +10,7 @@ util.AddNetworkString("ACF_StopRefillEffect") local CheckLegal = ACF_CheckLegal local ClassLink = ACF.GetClassLink local ClassUnlink = ACF.GetClassUnlink +local Inputs = ACF.GetInputActions("acf_ammo") local RefillDist = ACF.RefillDistance * ACF.RefillDistance local TimerCreate = timer.Create local TimerExists = timer.Exists @@ -247,17 +248,22 @@ do -- Metamethods ------------------------------- do -- Inputs/Outputs/Linking ---------------- WireLib.AddInputAlias("Active", "Load") + ACF.AddInputAction("acf_ammo", "Load", function(Entity, Value) + Entity.Load = Entity.Ammo ~= 0 and tobool(Value) + + WireLib.TriggerOutput(Entity, "Loading", Entity.Load and 1 or 0) + end) + function ENT:TriggerInput(Name, Value) if self.Disabled then return end -- Ignore input if disabled - if Name == "Load" then - self.Load = self.Ammo ~= 0 and tobool(Value) + local Action = Inputs[Name] - WireLib.TriggerOutput(self, "Loading", self.Load and 1 or 0) - end + if Action then + Action(self, Value) - - self:UpdateOverlay() + self:UpdateOverlay() + end end function ENT:Link(Target) diff --git a/lua/entities/acf_engine/init.lua b/lua/entities/acf_engine/init.lua index a83ea8c7e..733ffe960 100644 --- a/lua/entities/acf_engine/init.lua +++ b/lua/entities/acf_engine/init.lua @@ -102,6 +102,7 @@ local ClassLink = ACF.GetClassLink local ClassUnlink = ACF.GetClassUnlink local Engines = ACF.Classes.Engines local EngineTypes = ACF.Classes.EngineTypes +local Inputs = ACF.GetInputActions("acf_engine") local UnlinkSound = "physics/metal/metal_box_impact_bullet%s.wav" local Round = math.Round local max = math.max @@ -241,15 +242,6 @@ local function SetActive(Entity, Value) end end -local Inputs = { - Throttle = function(Entity, Value) - Entity.Throttle = math.Clamp(Value, 0, 100) / 100 - end, - Active = function(Entity, Value) - SetActive(Entity, tobool(Value)) - end -} - --===============================================================================================-- do -- Spawn and Update functions @@ -530,11 +522,23 @@ function ENT:UpdateOverlay(Instant) end end -function ENT:TriggerInput(Input, Value) +ACF.AddInputAction("acf_engine", "Throttle", function(Entity, Value) + Entity.Throttle = math.Clamp(Value, 0, 100) * 0.01 +end) + +ACF.AddInputAction("acf_engine", "Active", function(Entity, Value) + SetActive(Entity, tobool(Value)) +end) + +function ENT:TriggerInput(Name, Value) if self.Disabled then return end - if Inputs[Input] then - Inputs[Input](self, Value) + local Action = Inputs[Name] + + if Action then + Action(self, Value) + + self:UpdateOverlay() end end diff --git a/lua/entities/acf_fueltank/init.lua b/lua/entities/acf_fueltank/init.lua index ed8201665..14949a457 100644 --- a/lua/entities/acf_fueltank/init.lua +++ b/lua/entities/acf_fueltank/init.lua @@ -13,27 +13,11 @@ local ClassUnlink = ACF.GetClassUnlink local FuelTanks = ACF.Classes.FuelTanks local FuelTypes = ACF.Classes.FuelTypes local ActiveTanks = ACF.FuelTanks +local Inputs = ACF.GetInputActions("acf_fueltank") local TimerCreate = timer.Create local TimerExists = timer.Exists local Wall = 0.03937 --wall thickness in inches (1mm) -local Inputs = { - Active = function(Entity, Value) - if not Entity.Inputs.Active.Path then - Value = true - end - - Entity.Active = tobool(Value) - - Entity:UpdateOverlay() - end, - ["Refuel Duty"] = function(Entity, Value) - local N = math.Clamp(tonumber(Value), 0, 2) - - Entity.SupplyFuel = N == 0 and nil or N - end -} - --===============================================================================================-- do -- Spawn and Update functions @@ -423,11 +407,29 @@ do -- Overlay Update end end -function ENT:TriggerInput(Input, Value) +ACF.AddInputAction("acf_fueltank", "Active", function(Entity, Value) + if not Entity.Inputs.Active.Path then + Value = true + end + + Entity.Active = tobool(Value) +end) + +ACF.AddInputAction("acf_fueltank", "Refuel Duty", function(Entity, Value) + local N = math.Clamp(tonumber(Value), 0, 2) + + Entity.SupplyFuel = N ~= 0 and N +end) + +function ENT:TriggerInput(Name, Value) if self.Disabled then return end - if Inputs[Input] then - Inputs[Input](self, Value) + local Action = Inputs[Name] + + if Action then + Action(self, Value) + + self:UpdateOverlay() end end diff --git a/lua/entities/acf_gearbox/init.lua b/lua/entities/acf_gearbox/init.lua index 451724666..5526e5860 100644 --- a/lua/entities/acf_gearbox/init.lua +++ b/lua/entities/acf_gearbox/init.lua @@ -155,6 +155,7 @@ local CheckLegal = ACF_CheckLegal local ClassLink = ACF.GetClassLink local ClassUnlink = ACF.GetClassUnlink local Gearboxes = ACF.Classes.Gearboxes +local Inputs = ACF.GetInputActions("acf_gearbox") local Clamp = math.Clamp local function ChangeGear(Entity, Value) @@ -232,66 +233,6 @@ local function ActWheel(Link, Wheel, Torque, Brake, DeltaTime) Phys:ApplyTorqueCenter(TorqueAxis * Clamp(math.deg(-Torque * 1.5 - BrakeMult) * DeltaTime, -500000, 500000)) end -local Inputs = { - Gear = function(Entity, Value) - if Entity.Automatic then - ChangeDrive(Entity, Value) - else - ChangeGear(Entity, Value) - end - end, - ["Gear Up"] = function(Entity, Value) - if Value == 0 then return end - - if Entity.Automatic then - ChangeDrive(Entity, Entity.Drive + 1) - else - ChangeGear(Entity, Entity.Gear + 1) - end - end, - ["Gear Down"] = function(Entity, Value) - if Value == 0 then return end - - if Entity.Automatic then - ChangeDrive(Entity, Entity.Drive - 1) - else - ChangeGear(Entity, Entity.Gear - 1) - end - end, - Clutch = function(Entity, Value) - Entity.LClutch = Clamp(1 - Value, 0, 1) * Entity.MaxTorque - Entity.RClutch = Clamp(1 - Value, 0, 1) * Entity.MaxTorque - end, - Brake = function(Entity, Value) - Entity.LBrake = Clamp(Value, 0, 100) - Entity.RBrake = Clamp(Value, 0, 100) - end, - ["Left Brake"] = function(Entity, Value) - Entity.LBrake = Clamp(Value, 0, 100) - end, - ["Right Brake"] = function(Entity, Value) - Entity.RBrake = Clamp(Value, 0, 100) - end, - ["Left Clutch"] = function(Entity, Value) - Entity.LClutch = Clamp(1 - Value, 0, 1) * Entity.MaxTorque - end, - ["Right Clutch"] = function(Entity, Value) - Entity.RClutch = Clamp(1 - Value, 0, 1) * Entity.MaxTorque - end, - ["CVT Ratio"] = function(Entity, Value) - Entity.CVTRatio = Clamp(Value, 0, 1) - end, - ["Steer Rate"] = function(Entity, Value) - Entity.SteerRate = Clamp(Value, -1, 1) - end, - ["Hold Gear"] = function(Entity, Value) - Entity.Hold = tobool(Value) - end, - ["Shift Speed Scale"] = function(Entity, Value) - Entity.ShiftScale = Clamp(Value, 0.1, 1.5) - end -} - --===============================================================================================-- do -- Spawn and Update functions @@ -732,11 +673,85 @@ function ENT:CanProperty(_, Property) return Property ~= "bodygroups" end -function ENT:TriggerInput(Input, Value) +ACF.AddInputAction("acf_gearbox", "Gear", function(Entity, Value) + if Entity.Automatic then + ChangeDrive(Entity, Value) + else + ChangeGear(Entity, Value) + end +end) + +ACF.AddInputAction("acf_gearbox", "Gear Up", function(Entity, Value) + if Value == 0 then return end + + if Entity.Automatic then + ChangeDrive(Entity, Entity.Drive + 1) + else + ChangeGear(Entity, Entity.Gear + 1) + end +end) + +ACF.AddInputAction("acf_gearbox", "Gear Down", function(Entity, Value) + if Value == 0 then return end + + if Entity.Automatic then + ChangeDrive(Entity, Entity.Drive - 1) + else + ChangeGear(Entity, Entity.Gear - 1) + end +end) + +ACF.AddInputAction("acf_gearbox", "Clutch", function(Entity, Value) + Entity.LClutch = Clamp(1 - Value, 0, 1) * Entity.MaxTorque + Entity.RClutch = Clamp(1 - Value, 0, 1) * Entity.MaxTorque +end) + +ACF.AddInputAction("acf_gearbox", "Left Clutch", function(Entity, Value) + Entity.LClutch = Clamp(1 - Value, 0, 1) * Entity.MaxTorque +end) + +ACF.AddInputAction("acf_gearbox", "Right Clutch", function(Entity, Value) + Entity.RClutch = Clamp(1 - Value, 0, 1) * Entity.MaxTorque +end) + +ACF.AddInputAction("acf_gearbox", "Brake", function(Entity, Value) + Entity.LBrake = Clamp(Value, 0, 100) + Entity.RBrake = Clamp(Value, 0, 100) +end) + +ACF.AddInputAction("acf_gearbox", "Left Brake", function(Entity, Value) + Entity.LBrake = Clamp(Value, 0, 100) +end) + +ACF.AddInputAction("acf_gearbox", "Right Brake", function(Entity, Value) + Entity.RBrake = Clamp(Value, 0, 100) +end) + +ACF.AddInputAction("acf_gearbox", "CVT Ratio", function(Entity, Value) + Entity.CVTRatio = Clamp(Value, 0, 1) +end) + +ACF.AddInputAction("acf_gearbox", "Steer Rate", function(Entity, Value) + Entity.SteerRate = Clamp(Value, -1, 1) +end) + +ACF.AddInputAction("acf_gearbox", "Hold Gear", function(Entity, Value) + Entity.Hold = tobool(Value) +end) + +ACF.AddInputAction("acf_gearbox", "Shift Speed Scale", function(Entity, Value) + Entity.ShiftScale = Clamp(Value, 0.1, 1.5) +end) + +function ENT:TriggerInput(Name, Value) if self.Disabled then return end - if Inputs[Input] then - Inputs[Input](self, Value) + local Action = Inputs[Name] + + if Action then + Action(self, Value) + + self:UpdateOverlay() end end diff --git a/lua/entities/acf_gun/init.lua b/lua/entities/acf_gun/init.lua index 7e7466ec8..a4a916d9a 100644 --- a/lua/entities/acf_gun/init.lua +++ b/lua/entities/acf_gun/init.lua @@ -10,6 +10,7 @@ local UnlinkSound = "physics/metal/metal_box_impact_bullet%s.wav" local CheckLegal = ACF_CheckLegal local Shove = ACF.KEShove local Weapons = ACF.Classes.Weapons +local Inputs = ACF.GetInputActions("acf_gun") local TraceRes = {} -- Output for traces local TraceData = {start = true, endpos = true, filter = true, mask = MASK_SOLID, output = TraceRes} local Trace = util.TraceLine @@ -280,36 +281,50 @@ do -- Metamethods -------------------------------- return FindUser(self, Input) end - function ENT:TriggerInput(Input, Value) - if self.Disabled then return end -- Ignore all input if the gun is disabled - + ACF.AddInputAction("acf_gun", "Fire", function(Entity, Value) local Bool = tobool(Value) - if Input == "Fire" then - self.Firing = Bool + Entity.Firing = Bool - if Bool then - self.User = self:GetUser(self.Inputs.Fire.Src) or self.Owner + if Bool then + Entity.User = Entity:GetUser(Entity.Inputs.Fire.Src) or Entity.Owner - if self:CanFire() then - self:Shoot() - end - end - elseif Input == "Fuze" then - self.SetFuze = Bool and math.abs(Value) or nil - elseif Input == "Unload" then - if Bool and self.State == "Loaded" then - self:Unload() + if Entity:CanFire() then + Entity:Shoot() end - elseif Input == "Reload" then - if Bool then - if self.State == "Loaded" then - self:Unload(true) -- Unload, then reload - elseif self.State == "Empty" then - self:Load() - end + end + end) + + ACF.AddInputAction("acf_gun", "Unload", function(Entity, Value) + if tobool(Value) and Entity.State == "Loaded" then + Entity:Unload() + end + end) + + ACF.AddInputAction("acf_gun", "Reload", function(Entity, Value) + if tobool(Value) then + if Entity.State == "Loaded" then + Entity:Unload(true) -- Unload, then reload + elseif Entity.State == "Empty" then + Entity:Load() end end + end) + + ACF.AddInputAction("acf_gun", "Fuze", function(Entity, Value) + Entity.SetFuze = tobool(Value) and math.abs(Value) + end) + + function ENT:TriggerInput(Name, Value) + if self.Disabled then return end + + local Action = Inputs[Name] + + if Action then + Action(self, Value) + + self:UpdateOverlay() + end end function ENT:Link(Target) From a63fbeda1d78f1a0e8d4370c002cd0ebdf9ed9fc Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Wed, 27 May 2020 21:16:16 -0400 Subject: [PATCH 095/279] Ported latest changes to ACF guns - Properly ported the latest changes to ACF guns, which weren't merged correctly. --- lua/entities/acf_gun/init.lua | 43 +++++++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/lua/entities/acf_gun/init.lua b/lua/entities/acf_gun/init.lua index f1efa0c98..44fc3014a 100644 --- a/lua/entities/acf_gun/init.lua +++ b/lua/entities/acf_gun/init.lua @@ -19,6 +19,19 @@ local TimerCreate = timer.Create local HookRun = hook.Run local EMPTY = { Type = "Empty", PropMass = 0, ProjMass = 0, Tracer = 0 } +-- Replace with CFrame as soon as it's available +local function UpdateTotalAmmo(Entity) + local Total = 0 + + for Crate in pairs(Entity.Crates) do + if Crate.Load and Crate.Ammo > 0 then + Total = Total + Crate.Ammo + end + end + + WireLib.TriggerOutput(Entity, "Total Ammo", Total) +end + do -- Spawn and Update functions -------------------------------- local Updated = { ["20mmHRAC"] = "20mmRAC", @@ -123,7 +136,7 @@ do -- Spawn and Update functions -------------------------------- Gun:Spawn() Gun.Owner = Player -- MUST be stored on ent for PP - Gun.Outputs = WireLib.CreateOutputs(Gun, { "Status [STRING]", "Entity [ENTITY]", "Shots Left", "Rate of Fire", "Reload Time", "Projectile Mass", "Muzzle Velocity" }) + Gun.Outputs = WireLib.CreateOutputs(Gun, { "Ready", "Status [STRING]", "Total Ammo", "Entity [ENTITY]", "Shots Left", "Rate of Fire", "Reload Time", "Projectile Mass", "Muzzle Velocity" }) Gun.Sound = Class.Sound Gun.BarrelFilter = { Gun } Gun.State = "Empty" @@ -132,16 +145,25 @@ do -- Spawn and Update functions -------------------------------- Gun.BulletData = { Type = "Empty", PropMass = 0, ProjMass = 0, Tracer = 0 } Gun.DataStore = ACF.GetEntClassVars("acf_gun") - Gun.Id = Id -- MUST be stored on ent to be duped - Gun.Owner = Player -- MUST be stored on ent for PP - Gun.Outputs = WireLib.CreateOutputs(Gun, { "Status [STRING]", "Entity [ENTITY]", "Shots Left", "Rate of Fire", "Reload Time", "Projectile Mass", "Muzzle Velocity" }) + Gun:SetNWString("Sound", Class.Sound) - if Caliber > ACF.MinFuzeCaliber then - Gun.Inputs = WireLib.CreateInputs(Gun, { "Fire", "Unload", "Reload", "Fuze" } ) - else - Gun.Inputs = WireLib.CreateInputs(Gun, {"Fire", "Unload", "Reload", "Fuze"}) + WireLib.TriggerOutput(Gun, "Status", "Empty") + WireLib.TriggerOutput(Gun, "Entity", Gun) + WireLib.TriggerOutput(Gun, "Projectile Mass", 1000) + WireLib.TriggerOutput(Gun, "Muzzle Velocity", 1000) + + UpdateWeapon(Gun, Data, Class, Weapon) + + if Class.OnSpawn then + Class.OnSpawn(Gun, Data, Class, Weapon) end + TimerCreate("ACF Ammo Left " .. Gun:EntIndex(), 1, 0, function() + if not IsValid(Gun) then return end + + UpdateTotalAmmo(Gun) + end) + CheckLegal(Gun) return Gun @@ -164,10 +186,7 @@ do -- Spawn and Update functions -------------------------------- self:Unload() end - WireLib.TriggerOutput(Gun, "Status", "Empty") - WireLib.TriggerOutput(Gun, "Entity", Gun) - WireLib.TriggerOutput(Gun, "Projectile Mass", 1000) - WireLib.TriggerOutput(Gun, "Muzzle Velocity", 1000) + ACF.SaveEntity(self) UpdateWeapon(self, Data, Class, Weapon) From d93a212936772930a521a4bba4f0dbd9183ff120 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sun, 31 May 2020 07:59:09 -0400 Subject: [PATCH 096/279] Added clientside ACF Trace and Visclip check - Added a clientside copy of the ACF.Trace and ACF_CheckClips functions. --- lua/acf/client/cl_ballistics.lua | 49 ++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/lua/acf/client/cl_ballistics.lua b/lua/acf/client/cl_ballistics.lua index f7de6bc87..4930b54b5 100644 --- a/lua/acf/client/cl_ballistics.lua +++ b/lua/acf/client/cl_ballistics.lua @@ -1,5 +1,52 @@ ACF.BulletEffect = ACF.BulletEffect or {} +local TraceLine = util.TraceLine + +local function HitClip(Ent, Pos) + if not IsValid(Ent) then return false end + if Ent.ClipData == nil then return false end -- Doesn't have clips + if Ent:GetClass() ~= "prop_physics" then return false end -- Only care about props + + local Center = Ent:LocalToWorld(Ent:OBBCenter()) + + for I = 1, #Ent.ClipData do + local Clip = Ent.ClipData[I] + local Normal = Ent:LocalToWorldAngles(Clip[1]):Forward() + local Origin = Center + Normal * Clip[2] + + if Normal:Dot((Origin - Pos):GetNormalized()) > 0 then return true end + end + + return false +end + +local function Trace(TraceData, Filter) -- Pass true on filter to have Trace make it's own copy of TraceData.filter to modify + if Filter == true then + Filter = TraceData.filter + local NewFilter = {} + + for I = 1, #Filter do + NewFilter[I] = Filter[I] + end + + TraceData.filter = NewFilter + end + + local T = TraceLine(TraceData) + + if T.HitNonWorld and HitClip(T.Entity, T.HitPos) then + TraceData.filter[#TraceData.filter + 1] = T.Entity + + return Trace(TraceData, Filter) + end + + if Filter then + TraceData.filter = Filter + end + + return T +end + local function BulletFlight(Bullet) local DeltaTime = CurTime() - Bullet.LastThink local Drag = Bullet.SimFlight:GetNormalized() * (Bullet.DragCoef * Bullet.SimFlight:Length() ^ 2 ) / ACF.DragDiv @@ -24,3 +71,5 @@ hook.Add("Think", "ACF_ManageBulletEffects", function() end) ACF_SimBulletFlight = BulletFlight +ACF_CheckClips = HitClip +ACF.Trace = Trace From bd0703a685729154d0350f82d6f00d6d06f448e5 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sun, 31 May 2020 08:00:37 -0400 Subject: [PATCH 097/279] Renamed ACF_UpdateHitboxes network message - Renamed ACF_UpdateHitboxes network message to ACF_UpdateEntity. This will now also call ENT:Update() instead of ENT:UpdateHitboxes on the clientside. --- lua/acf/base/acf_globals.lua | 8 ++++---- lua/entities/acf_fueltank/cl_init.lua | 4 ++-- lua/entities/acf_fueltank/init.lua | 2 +- lua/entities/acf_gun/cl_init.lua | 4 ++-- lua/entities/acf_gun/init.lua | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lua/acf/base/acf_globals.lua b/lua/acf/base/acf_globals.lua index e4a809892..cbd0e8a76 100644 --- a/lua/acf/base/acf_globals.lua +++ b/lua/acf/base/acf_globals.lua @@ -121,7 +121,7 @@ do -- ACF Convars/Callbacks ------------------------ end if SERVER then - util.AddNetworkString("ACF_UpdateHitboxes") + util.AddNetworkString("ACF_UpdateEntity") util.AddNetworkString("ACF_KilledByACF") util.AddNetworkString("ACF_RenderDamage") util.AddNetworkString("ACF_Notify") @@ -169,14 +169,14 @@ elseif CLIENT then --------------------------------------------- -- Hitbox Updating -------------------------- - net.Receive("ACF_UpdateHitboxes", function() + net.Receive("ACF_UpdateEntity", function() local Entity = net.ReadEntity() timer.Simple(0.1, function() if not IsValid(Entity) then return end - if not Entity.UpdateHitboxes then return end + if not isfunction(Entity.Update) then return end - Entity:UpdateHitboxes() + Entity:Update() end) end) --------------------------------------------- diff --git a/lua/entities/acf_fueltank/cl_init.lua b/lua/entities/acf_fueltank/cl_init.lua index 06d622cad..d2a15eb4f 100644 --- a/lua/entities/acf_fueltank/cl_init.lua +++ b/lua/entities/acf_fueltank/cl_init.lua @@ -6,10 +6,10 @@ language.Add("Undone_acf_fueltank", "Undone ACF Fuel Tank") language.Add("SBoxLimit__acf_fueltank", "You've reached the ACF Fuel Tanks limit!") function ENT:Initialize() - self:UpdateHitboxes() + self:Update() end -function ENT:UpdateHitboxes() +function ENT:Update() self.HitBoxes = { Main = { Pos = self:OBBCenter(), diff --git a/lua/entities/acf_fueltank/init.lua b/lua/entities/acf_fueltank/init.lua index 14949a457..c144cc7c5 100644 --- a/lua/entities/acf_fueltank/init.lua +++ b/lua/entities/acf_fueltank/init.lua @@ -187,7 +187,7 @@ do -- Spawn and Update functions end end - net.Start("ACF_UpdateHitboxes") + net.Start("ACF_UpdateEntity") net.WriteEntity(self) net.Send(self.Owner) diff --git a/lua/entities/acf_gun/cl_init.lua b/lua/entities/acf_gun/cl_init.lua index b46f3cc36..c6e896b69 100644 --- a/lua/entities/acf_gun/cl_init.lua +++ b/lua/entities/acf_gun/cl_init.lua @@ -15,12 +15,12 @@ function ENT:Initialize() self.FireAnim = self:LookupSequence("shoot") self.CloseAnim = self:LookupSequence("load") - self:UpdateHitboxes() + self:Update() self.BaseClass.Initialize(self) end -function ENT:UpdateHitboxes() +function ENT:Update() self.HitBoxes = ACF.HitBoxes[self:GetModel()] end diff --git a/lua/entities/acf_gun/init.lua b/lua/entities/acf_gun/init.lua index 44fc3014a..9cc2b61cf 100644 --- a/lua/entities/acf_gun/init.lua +++ b/lua/entities/acf_gun/init.lua @@ -202,7 +202,7 @@ do -- Spawn and Update functions -------------------------------- end end - net.Start("ACF_UpdateHitboxes") + net.Start("ACF_UpdateEntity") net.WriteEntity(self) net.Send(self.Owner) From f2beaaa81f77a433c4d9729632bb5a05bdf47890 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sun, 31 May 2020 08:42:06 -0400 Subject: [PATCH 098/279] Fixed ACF_UpdateEntity not being broadcasted - Fixed ACF_UpdateEntity network message not being broadcasted to all clients. --- lua/entities/acf_fueltank/init.lua | 2 +- lua/entities/acf_gun/init.lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lua/entities/acf_fueltank/init.lua b/lua/entities/acf_fueltank/init.lua index c144cc7c5..0a725b4cf 100644 --- a/lua/entities/acf_fueltank/init.lua +++ b/lua/entities/acf_fueltank/init.lua @@ -189,7 +189,7 @@ do -- Spawn and Update functions net.Start("ACF_UpdateEntity") net.WriteEntity(self) - net.Send(self.Owner) + net.Broadcast() return true, "Fuel tank updated successfully!" .. Feedback end diff --git a/lua/entities/acf_gun/init.lua b/lua/entities/acf_gun/init.lua index 9cc2b61cf..2f8195671 100644 --- a/lua/entities/acf_gun/init.lua +++ b/lua/entities/acf_gun/init.lua @@ -204,7 +204,7 @@ do -- Spawn and Update functions -------------------------------- net.Start("ACF_UpdateEntity") net.WriteEntity(self) - net.Send(self.Owner) + net.Broadcast() return true, "Weapon updated successfully!" end From f8cdce90da112b83d0f5071ec2b706abe98623ad Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Thu, 18 Jun 2020 03:00:29 -0400 Subject: [PATCH 099/279] Rectified files after several merge conflicts - Rectified all entities that didn't merge correctly into the menu branch - Removed some leftovers about ACF.TorqueBoost --- lua/acf/client/menu_items/engines_menu.lua | 16 ++--- lua/acf/shared/engines/electric.lua | 3 - lua/acf/shared/engines/special.lua | 11 ---- lua/acf/shared/engines/turbine.lua | 12 ---- lua/acf/shared/fueltanks/misc.lua | 2 +- lua/acf/shared/fueltanks/size_eight.lua | 2 +- lua/acf/shared/fueltanks/size_four.lua | 2 +- lua/acf/shared/fueltanks/size_one.lua | 2 +- lua/acf/shared/fueltanks/size_six.lua | 2 +- lua/acf/shared/fueltanks/size_two.lua | 2 +- lua/entities/acf_ammo/init.lua | 23 +++---- lua/entities/acf_engine/init.lua | 41 +++++-------- lua/entities/acf_fueltank/init.lua | 71 +++++++++++----------- lua/entities/acf_gearbox/init.lua | 67 ++++++++++---------- lua/entities/acf_gun/init.lua | 33 +++++----- 15 files changed, 121 insertions(+), 168 deletions(-) diff --git a/lua/acf/client/menu_items/engines_menu.lua b/lua/acf/client/menu_items/engines_menu.lua index f0dd55734..bdc2eae5c 100644 --- a/lua/acf/client/menu_items/engines_menu.lua +++ b/lua/acf/client/menu_items/engines_menu.lua @@ -55,7 +55,6 @@ local function UpdateEngineStats(Label, Data) local TorqueText = "\nPeak Torque : %s n/m - %s ft-lb" local PowerText = "\nPeak Power : %s kW - %s HP @ %s RPM" local Consumption, Power = "", "" - local Boost = Data.RequiresFuel and ACF.TorqueBoost or 1 for K in pairs(Data.Fuel) do if not FuelTypes[K] then continue end @@ -68,25 +67,18 @@ local function UpdateEngineStats(Label, Data) AddText = Fuel.ConsumptionText(PeakkW, PeakkWRPM, Type, Fuel) else local Text = "\n\n%s Consumption :\n%s L/min - %s gal/min @ %s RPM" - local Rate = ACF.FuelRate * Type.Efficiency * ACF.TorqueBoost * PeakkW / (60 * Fuel.Density) + local Rate = ACF.FuelRate * Type.Efficiency * PeakkW / (60 * Fuel.Density) AddText = Text:format(Fuel.Name, math.Round(Rate, 2), math.Round(Rate * 0.264, 2), PeakkWRPM) end - Consumption = Consumption .. AddText + Consumption = Consumption .. AddText .. "\n\nThis engine requires fuel." Data.Fuel[K] = Fuel -- Replace once engines use the proper class functions end - Power = Power .. "\n" .. PowerText:format(math.floor(PeakkW * Boost), math.floor(PeakkW * Boost * 1.34), PeakkWRPM) - Power = Power .. TorqueText:format(math.floor(Data.Torque * Boost), math.floor(Data.Torque * Boost * 0.73)) - - if Data.RequiresFuel then - Consumption = Consumption .. "\n\nThis engine requires fuel." - else - Power = Power .. "\n\nWhen Fueled :" .. PowerText:format(math.floor(PeakkW * ACF.TorqueBoost), math.floor(PeakkW * ACF.TorqueBoost * 1.34), PeakkWRPM) - Power = Power .. TorqueText:format(math.floor(Data.Torque * ACF.TorqueBoost), math.floor(Data.Torque * ACF.TorqueBoost * 0.73)) - end + Power = Power .. "\n" .. PowerText:format(math.floor(PeakkW), math.floor(PeakkW * 1.34), PeakkWRPM) + Power = Power .. TorqueText:format(math.floor(Data.Torque), math.floor(Data.Torque * 0.73)) LabelText = LabelText .. Consumption .. Power diff --git a/lua/acf/shared/engines/electric.lua b/lua/acf/shared/engines/electric.lua index cd205e643..8a2e304a6 100644 --- a/lua/acf/shared/engines/electric.lua +++ b/lua/acf/shared/engines/electric.lua @@ -218,7 +218,6 @@ do -- Electric Standalone Motors Torque = 384, FlywheelMass = 0.3, IsElectric = true, - RequiresFuel = true, RPM = { Idle = 10, PeakMin = 1, @@ -239,7 +238,6 @@ do -- Electric Standalone Motors Torque = 1152, FlywheelMass = 1.5, IsElectric = true, - RequiresFuel = true, RPM = { Idle = 10, PeakMin = 1, @@ -260,7 +258,6 @@ do -- Electric Standalone Motors Torque = 3360, FlywheelMass = 11.2, IsElectric = true, - RequiresFuel = true, RPM = { Idle = 10, PeakMin = 1, diff --git a/lua/acf/shared/engines/special.lua b/lua/acf/shared/engines/special.lua index 1c8379589..da0cfe841 100644 --- a/lua/acf/shared/engines/special.lua +++ b/lua/acf/shared/engines/special.lua @@ -205,7 +205,6 @@ do -- Special Rotary Engines Mass = 260, Torque = 250, FlywheelMass = 0.11, - RequiresFuel = true, RPM = { Idle = 1200, PeakMin = 4500, @@ -226,7 +225,6 @@ do -- Special I2 Engines Mass = 60, Torque = 116, FlywheelMass = 0.085, - RequiresFuel = true, RPM = { Idle = 750, PeakMin = 3125, @@ -247,7 +245,6 @@ do -- Special I4 Engines Mass = 78, Torque = 68, FlywheelMass = 0.031, - RequiresFuel = true, Pitch = 0.75, RPM = { Idle = 1200, @@ -267,7 +264,6 @@ do -- Special I4 Engines Mass = 150, Torque = 176, FlywheelMass = 0.06, - RequiresFuel = true, RPM = { Idle = 950, PeakMin = 5200, @@ -288,7 +284,6 @@ do -- Special V4 Engines Mass = 92, Torque = 124.8, FlywheelMass = 0.04, - RequiresFuel = true, RPM = { Idle = 900, PeakMin = 4600, @@ -309,7 +304,6 @@ do -- Special I6 Engines Mass = 180, Torque = 224, FlywheelMass = 0.1, - RequiresFuel = true, RPM = { Idle = 1100, PeakMin = 5200, @@ -330,7 +324,6 @@ do -- Special V6 Engines Mass = 134, Torque = 172, FlywheelMass = 0.075, - RequiresFuel = true, RPM = { Idle = 950, PeakMin = 4500, @@ -351,7 +344,6 @@ do -- Special V8 Engines Mass = 180, Torque = 200, FlywheelMass = 0.075, - RequiresFuel = true, RPM = { Idle = 1000, PeakMin = 5500, @@ -370,7 +362,6 @@ do -- Special V8 Engines Mass = 400, Torque = 340, FlywheelMass = 0.15, - RequiresFuel = true, RPM = { Idle = 1000, PeakMin = 5000, @@ -391,7 +382,6 @@ do -- Special V10 Engines Mass = 300, Torque = 320, FlywheelMass = 0.15, - RequiresFuel = true, RPM = { Idle = 1100, PeakMin = 5750, @@ -412,7 +402,6 @@ do -- Special V12 Engines Mass = 175, Torque = 248, FlywheelMass = 0.1, - RequiresFuel = true, Pitch = 0.85, RPM = { Idle = 1200, diff --git a/lua/acf/shared/engines/turbine.lua b/lua/acf/shared/engines/turbine.lua index 3657a1d15..c4c62686e 100644 --- a/lua/acf/shared/engines/turbine.lua +++ b/lua/acf/shared/engines/turbine.lua @@ -259,7 +259,6 @@ do -- Forward-facing Gas Turbines Mass = 200, Torque = 550, FlywheelMass = 2.9, - RequiresFuel = true, IsElectric = true, RPM = { Idle = 1400, @@ -280,7 +279,6 @@ do -- Forward-facing Gas Turbines Mass = 400, Torque = 813, FlywheelMass = 4.3, - RequiresFuel = true, IsElectric = true, RPM = { Idle = 1800, @@ -301,7 +299,6 @@ do -- Forward-facing Gas Turbines Mass = 1100, Torque = 1990, FlywheelMass = 10.5, - RequiresFuel = true, IsElectric = true, RPM = { Idle = 2000, @@ -324,7 +321,6 @@ do -- Transaxial Gas Turbines Mass = 160, Torque = 440, FlywheelMass = 2.3, - RequiresFuel = true, IsElectric = true, IsTrans = true, RPM = { @@ -346,7 +342,6 @@ do -- Transaxial Gas Turbines Mass = 320, Torque = 650, FlywheelMass = 3.4, - RequiresFuel = true, IsElectric = true, IsTrans = true, RPM = { @@ -368,7 +363,6 @@ do -- Transaxial Gas Turbines Mass = 880, Torque = 1592, FlywheelMass = 8.4, - RequiresFuel = true, IsElectric = true, IsTrans = true, RPM = { @@ -397,7 +391,6 @@ do -- Forward-facing Ground Gas Turbines Mass = 350, Torque = 800, FlywheelMass = 14.3, - RequiresFuel = true, IsElectric = true, RPM = { Idle = 700, @@ -418,7 +411,6 @@ do -- Forward-facing Ground Gas Turbines Mass = 600, Torque = 1200, FlywheelMass = 29.6, - RequiresFuel = true, IsElectric = true, Pitch = 1.15, RPM = { @@ -440,7 +432,6 @@ do -- Forward-facing Ground Gas Turbines Mass = 1650, Torque = 4000, FlywheelMass = 75, - RequiresFuel = true, IsElectric = true, Pitch = 1.35, RPM = { @@ -464,7 +455,6 @@ do -- Transaxial Ground Gas Turbines Mass = 280, Torque = 600, FlywheelMass = 11.4, - RequiresFuel = true, IsElectric = true, IsTrans = true, RPM = { @@ -486,7 +476,6 @@ do -- Transaxial Ground Gas Turbines Mass = 480, Torque = 900, FlywheelMass = 23.7, - RequiresFuel = true, IsElectric = true, IsTrans = true, Pitch = 1.15, @@ -509,7 +498,6 @@ do -- Transaxial Ground Gas Turbines Mass = 1320, Torque = 3000, FlywheelMass = 60, - RequiresFuel = true, IsElectric = true, IsTrans = true, Pitch = 1.35, diff --git a/lua/acf/shared/fueltanks/misc.lua b/lua/acf/shared/fueltanks/misc.lua index 770f9635a..a746993d0 100644 --- a/lua/acf/shared/fueltanks/misc.lua +++ b/lua/acf/shared/fueltanks/misc.lua @@ -1,6 +1,6 @@ ACF.RegisterFuelTankClass("FTS_M", { Name = "Miscellaneous", - Description = "Guaranteed to improve engine performance by " .. (ACF.TorqueBoost - 1) * 100 .. "%", + Description = "Random fuel tank models, some of them can only be used for refueling.", }) do diff --git a/lua/acf/shared/fueltanks/size_eight.lua b/lua/acf/shared/fueltanks/size_eight.lua index 8de1a289f..04d221665 100644 --- a/lua/acf/shared/fueltanks/size_eight.lua +++ b/lua/acf/shared/fueltanks/size_eight.lua @@ -1,6 +1,6 @@ ACF.RegisterFuelTankClass("FTS_8", { Name = "Size 8 Container", - Description = "Guaranteed to improve engine performance by " .. (ACF.TorqueBoost - 1) * 100 .. "%", + Description = "Size 8 fuel containers, required for engines to work.", }) do diff --git a/lua/acf/shared/fueltanks/size_four.lua b/lua/acf/shared/fueltanks/size_four.lua index 773e2c02e..c10a1d495 100644 --- a/lua/acf/shared/fueltanks/size_four.lua +++ b/lua/acf/shared/fueltanks/size_four.lua @@ -1,6 +1,6 @@ ACF.RegisterFuelTankClass("FTS_4", { Name = "Size 4 Container", - Description = "Guaranteed to improve engine performance by " .. (ACF.TorqueBoost - 1) * 100 .. "%", + Description = "Size 4 fuel containers, required for engines to work.", }) do diff --git a/lua/acf/shared/fueltanks/size_one.lua b/lua/acf/shared/fueltanks/size_one.lua index 587c2df37..065fef62f 100644 --- a/lua/acf/shared/fueltanks/size_one.lua +++ b/lua/acf/shared/fueltanks/size_one.lua @@ -1,6 +1,6 @@ ACF.RegisterFuelTankClass("FTS_1", { Name = "Size 1 Container", - Description = "Guaranteed to improve engine performance by " .. (ACF.TorqueBoost - 1) * 100 .. "%", + Description = "Size 1 fuel containers, required for engines to work.", }) do diff --git a/lua/acf/shared/fueltanks/size_six.lua b/lua/acf/shared/fueltanks/size_six.lua index 414a9403d..1456fdf9e 100644 --- a/lua/acf/shared/fueltanks/size_six.lua +++ b/lua/acf/shared/fueltanks/size_six.lua @@ -1,6 +1,6 @@ ACF.RegisterFuelTankClass("FTS_6", { Name = "Size 6 Container", - Description = "Guaranteed to improve engine performance by " .. (ACF.TorqueBoost - 1) * 100 .. "%", + Description = "Size 6 fuel containers, required for engines to work.", }) do diff --git a/lua/acf/shared/fueltanks/size_two.lua b/lua/acf/shared/fueltanks/size_two.lua index 21fe192e0..9214d5176 100644 --- a/lua/acf/shared/fueltanks/size_two.lua +++ b/lua/acf/shared/fueltanks/size_two.lua @@ -1,6 +1,6 @@ ACF.RegisterFuelTankClass("FTS_2", { Name = "Size 2 Container", - Description = "Guaranteed to improve engine performance by " .. (ACF.TorqueBoost - 1) * 100 .. "%", + Description = "Size 2 fuel containers, required for engines to work.", }) do diff --git a/lua/entities/acf_ammo/init.lua b/lua/entities/acf_ammo/init.lua index 65622e1c6..766dd0b4d 100644 --- a/lua/entities/acf_ammo/init.lua +++ b/lua/entities/acf_ammo/init.lua @@ -283,7 +283,6 @@ do -- Metamethods ------------------------------- function ENT:Link(Target) if not IsValid(Target) then return false, "Attempted to link an invalid entity." end if self == Target then return false, "Can't link a crate to itself." end - if table.HasValue(ACF.AmmoBlacklist[self.BulletData.Type], Target.Class) then return false, "The ammo type in this crate cannot be used for this weapon." end local Function = ClassLink(self:GetClass(), Target:GetClass()) @@ -328,23 +327,22 @@ do -- Metamethods ------------------------------- AmmoData = "\n" .. Ent.RoundData.cratetxt(Ent.BulletData) end - Ent:SetOverlayText(string.format(Text, Status, Ent.BulletData.Type .. Tracer, Ent.Ammo, Ent.Capacity, AmmoData)) + Ent:SetOverlayText(Text:format(Status, Ent.BulletData.Type .. Tracer, Ent.Ammo, Ent.Capacity, AmmoData)) end end function ENT:UpdateOverlay(Instant) if Instant then - Overlay(self) - return + return Overlay(self) end - if not TimerExists("ACF Overlay Buffer" .. self:EntIndex()) then - TimerCreate("ACF Overlay Buffer" .. self:EntIndex(), 1, 1, function() - if IsValid(self) then - Overlay(self) - end - end) - end + if TimerExists("ACF Overlay Buffer" .. self:EntIndex()) then return end + + TimerCreate("ACF Overlay Buffer" .. self:EntIndex(), 0.5, 1, function() + if not IsValid(self) then return end + + Overlay(self) + end) end end @@ -356,14 +354,12 @@ do -- Metamethods ------------------------------- self.Load = true end - self:UpdateOverlay(true) self:UpdateMass() end function ENT:Disable() self.Load = false - self:UpdateOverlay(true) self:UpdateMass() end end @@ -522,6 +518,7 @@ do -- Metamethods ------------------------------- for Gun in pairs(self.Weapons) do if table.HasValue(Blacklist, Gun.Class) then self:Unlink(Gun) + Gun:Unload() Message = "New round type cannot be used with linked gun, crate unlinked and gun unloaded." diff --git a/lua/entities/acf_engine/init.lua b/lua/entities/acf_engine/init.lua index 83d8272b5..1e6f7d97e 100644 --- a/lua/entities/acf_engine/init.lua +++ b/lua/entities/acf_engine/init.lua @@ -271,7 +271,6 @@ do -- Spawn and Update functions Entity.IsTrans = EngineData.IsTrans -- driveshaft outputs to the side Entity.FuelTypes = EngineData.Fuel or { Petrol = true } Entity.FuelType = next(EngineData.Fuel) - Entity.RequiresFuel = EngineData.RequiresFuel Entity.EngineType = EngineType.ID Entity.Efficiency = EngineType.Efficiency Entity.TorqueScale = EngineType.TorqueScale @@ -295,7 +294,7 @@ do -- Spawn and Update functions if EngineType.CalculateFuelUsage then Entity.FuelUse = EngineType.CalculateFuelUsage(Entity) else - Entity.FuelUse = ACF.TorqueBoost * ACF.FuelRate * Entity.Efficiency * Entity.peakkw / 3600 + Entity.FuelUse = ACF.FuelRate * Entity.Efficiency * Entity.peakkw / 3600 end ACF_Activate(Entity, true) @@ -473,39 +472,30 @@ local function Overlay(Ent) if Ent.Disabled then Ent:SetOverlayText("Disabled: " .. Ent.DisableReason .. "\n" .. Ent.DisableDescription) else + local Text = "%s\n\n%s\nPower: %s kW / %s hp\nTorque: %s Nm / %s ft-lb\nPowerband: %s - %s RPM\nRedline: %s RPM" + local State, Name = Ent.Active and "Active" or "Idle", Ent.Name + local Power, PowerFt = Round(Ent.peakkw), Round(Ent.peakkw * 1.34) + local Torque, TorqueFt = Round(Ent.PeakTorque), Round(Ent.PeakTorque * 0.73) local PowerbandMin = Ent.IsElectric and Ent.IdleRPM or Ent.PeakMinRPM local PowerbandMax = Ent.IsElectric and math.floor(Ent.LimitRPM / 2) or Ent.PeakMaxRPM - local Text + local Redline = Ent.LimitRPM - if Ent.DisableReason then - Text = "Disabled: " .. Ent.DisableReason - else - Text = Ent.Active and "Active" or "Idle" - end - - Text = Text .. "\n\n" .. Ent.Name .. "\n" .. - "Power: " .. Round(Ent.peakkw) .. " kW / " .. Round(Ent.peakkw * 1.34) .. " hp\n" .. - "Torque: " .. Round(Ent.PeakTorque) .. " Nm / " .. Round(Ent.PeakTorque * 0.73) .. " ft-lb\n" .. - "Powerband: " .. PowerbandMin .. " - " .. PowerbandMax .. " RPM\n" .. - "Redline: " .. Ent.LimitRPM .. " RPM" - - Ent:SetOverlayText(Text) + Ent:SetOverlayText(Text:format(State, Name, Power, PowerFt, Torque, TorqueFt, PowerbandMin, PowerbandMax, Redline)) end end function ENT:UpdateOverlay(Instant) if Instant then - Overlay(self) - return + return Overlay(self) end - if not TimerExists("ACF Overlay Buffer" .. self:EntIndex()) then - TimerCreate("ACF Overlay Buffer" .. self:EntIndex(), 1, 1, function() - if IsValid(self) then - Overlay(self) - end - end) - end + if TimerExists("ACF Overlay Buffer" .. self:EntIndex()) then return end + + TimerCreate("ACF Overlay Buffer" .. self:EntIndex(), 0.5, 1, function() + if not IsValid(self) then return end + + Overlay(self) + end) end ACF.AddInputAction("acf_engine", "Throttle", function(Entity, Value) @@ -648,7 +638,6 @@ function ENT:CalcRPM() FuelTank.Fuel = max(FuelTank.Fuel - Consumption, 0) FuelTank:UpdateMass() FuelTank:UpdateOverlay() - FuelTank:UpdateOutputs() else SetActive(self, false) diff --git a/lua/entities/acf_fueltank/init.lua b/lua/entities/acf_fueltank/init.lua index 0a725b4cf..640160304 100644 --- a/lua/entities/acf_fueltank/init.lua +++ b/lua/entities/acf_fueltank/init.lua @@ -351,59 +351,60 @@ do -- Mass Update if TimerExists("ACF Mass Buffer" .. self:EntIndex()) then return end TimerCreate("ACF Mass Buffer" .. self:EntIndex(), 1, 1, function() - if not IsValid(self) then - UpdateMass(self) - end + if not IsValid(self) then return end + + UpdateMass(self) end) end end do -- Overlay Update local function Overlay(Ent) - local Text - - if Ent.DisableReason then - Text = "Disabled: " .. Ent.DisableReason - elseif Ent.Leaking > 0 then - Text = "Leaking" + if Ent.Disabled then + Ent:SetOverlayText("Disabled: " .. Ent.DisableReason .. "\n" .. Ent.DisableDescription) else - Text = Ent.Active and "Providing Fuel" or "Idle" - end + local Text - Text = Text .. "\n\nFuel Type: " .. Ent.FuelType + if Ent.Leaking > 0 then + Text = "Leaking" + else + Text = Ent.Active and "Providing Fuel" or "Idle" + end - if Ent.FuelType == "Electric" then - local KiloWatt = math.Round(Ent.Fuel, 1) - local Joules = math.Round(Ent.Fuel * 3.6, 1) + Text = Text .. "\n\nFuel Type: " .. Ent.FuelType - Text = Text .. "\nCharge Level: " .. KiloWatt .. " kWh / " .. Joules .. " MJ" - else - local Liters = math.Round(Ent.Fuel, 1) - local Gallons = math.Round(Ent.Fuel * 0.264172, 1) + if Ent.FuelType == "Electric" then + local KiloWatt = math.Round(Ent.Fuel, 1) + local Joules = math.Round(Ent.Fuel * 3.6, 1) - Text = Text .. "\nFuel Remaining: " .. Liters .. " liters / " .. Gallons .. " gallons" - end + Text = Text .. "\nCharge Level: " .. KiloWatt .. " kWh / " .. Joules .. " MJ" + else + local Liters = math.Round(Ent.Fuel, 1) + local Gallons = math.Round(Ent.Fuel * 0.264172, 1) + + Text = Text .. "\nFuel Remaining: " .. Liters .. " liters / " .. Gallons .. " gallons" + end - WireLib.TriggerOutput(Ent, "Fuel", math.Round(Ent.Fuel, 2)) - WireLib.TriggerOutput(Ent, "Capacity", math.Round(Ent.Capacity, 2)) - WireLib.TriggerOutput(Ent, "Leaking", Ent.Leaking > 0 and 1 or 0) + WireLib.TriggerOutput(Ent, "Fuel", math.Round(Ent.Fuel, 2)) + WireLib.TriggerOutput(Ent, "Capacity", math.Round(Ent.Capacity, 2)) + WireLib.TriggerOutput(Ent, "Leaking", Ent.Leaking > 0 and 1 or 0) - Ent:SetOverlayText(Text) + Ent:SetOverlayText(Text) + end end function ENT:UpdateOverlay(Instant) if Instant then - Overlay(self) - return + return Overlay(self) end - if not TimerExists("ACF Overlay Buffer" .. self:EntIndex()) then - TimerCreate("ACF Overlay Buffer" .. self:EntIndex(), 1, 1, function() - if IsValid(self) then - Overlay(self) - end - end) - end + if TimerExists("ACF Overlay Buffer" .. self:EntIndex()) then return end + + TimerCreate("ACF Overlay Buffer" .. self:EntIndex(), 0.5, 1, function() + if not IsValid(self) then return end + + Overlay(self) + end) end end @@ -413,6 +414,8 @@ ACF.AddInputAction("acf_fueltank", "Active", function(Entity, Value) end Entity.Active = tobool(Value) + + print(Entity, Entity.Active) end) ACF.AddInputAction("acf_fueltank", "Refuel Duty", function(Entity, Value) diff --git a/lua/entities/acf_gearbox/init.lua b/lua/entities/acf_gearbox/init.lua index b98c75616..0efb10d3a 100644 --- a/lua/entities/acf_gearbox/init.lua +++ b/lua/entities/acf_gearbox/init.lua @@ -623,36 +623,38 @@ end local function Overlay(Ent) if Ent.Disabled then Ent:SetOverlayText("Disabled: " .. Ent.DisableReason .. "\n" .. Ent.DisableDescription) - else - local Text + else + local Text = "Current Gear: " .. Ent.Gear .. "\n\n" .. Ent.Name .. "\n" + local Gears = Ent.Gears - if Ent.DisableReason then - Text = "Disabled: " .. Ent.DisableReason - else - Text = "Current Gear: " .. Ent.Gear - end + if Ent.CVT then + local CVT = "Reverse Gear: %s\nTarget: %s - %s RPM\n" + local Reverse = math.Round(Gears[2], 2) + local Min = math.Round(Gears.MinRPM) + local Max = math.Round(Gears.MaxRPM) - Text = Text .. "\n\n" .. Ent.Name .. "\n" + Text = Text .. CVT:format(Reverse, Min, Max) + elseif Ent.Automatic then + local Gear = "Gear %s: %s, Upshift @ %s kph / %s mph\n" - if Ent.CVT then - Text = Text .. "Reverse Gear: " .. math.Round(Ent.Gears[2], 2) .. - "\nTarget: " .. math.Round(Ent.Gears.MinRPM) .. " - " .. math.Round(Ent.Gears.MaxRPM) .. " RPM\n" - elseif Ent.Automatic then - for i = 1, Ent.MaxGear do - Text = Text .. "Gear " .. i .. ": " .. math.Round(Ent.Gears[i], 2) .. - ", Upshift @ " .. math.Round(Ent.ShiftPoints[i] / 10.936, 1) .. " kph / " .. - math.Round(Ent.ShiftPoints[i] / 17.6, 1) .. " mph\n" - end + for i = 1, Ent.MaxGear do + local Ratio = math.Round(Gears[i], 2) + local KPH = math.Round(Ent.ShiftPoints[i] / 10.936, 1) + local MPH = math.Round(Ent.ShiftPoints[i] / 17.6, 1) - Text = Text .. "Reverse gear: " .. math.Round(Ent.Gears[Ent.Reverse], 2) .. "\n" - else - for i = 1, Ent.MaxGear do - Text = Text .. "Gear " .. i .. ": " .. math.Round(Ent.Gears[i], 2) .. "\n" + Text = Text .. Gear:format(i, Ratio, KPH, MPH) + end + + Text = Text .. "Reverse gear: " .. math.Round(Gears[Ent.Reverse], 2) .. "\n" + else + for i = 1, Ent.MaxGear do + Text = Text .. "Gear " .. i .. ": " .. math.Round(Gears[i], 2) .. "\n" + end end - Text = Text .. "Final Drive: " .. math.Round(Ent.Gears.Final, 2) .. "\n" - Text = Text .. "Torque Rating: " .. Ent.MaxTorque .. " Nm / " .. math.Round(Ent.MaxTorque * 0.73) .. " ft-lb\n" - Text = Text .. "Torque Output: " .. math.floor(Ent.TorqueOutput) .. " Nm / " .. math.Round(Ent.TorqueOutput * 0.73) .. " ft-lb" + Text = Text .. "Final Drive: " .. math.Round(Gears.Final, 2) .. "\n" + Text = Text .. "Torque Rating: " .. Ent.MaxTorque .. " Nm / " .. math.Round(Ent.MaxTorque * 0.73) .. " ft-lb\n" + Text = Text .. "Torque Output: " .. math.floor(Ent.TorqueOutput) .. " Nm / " .. math.Round(Ent.TorqueOutput * 0.73) .. " ft-lb" Ent:SetOverlayText(Text) end @@ -660,17 +662,16 @@ end function ENT:UpdateOverlay(Instant) if Instant then - Overlay(self) - return + return Overlay(self) end - if not TimerExists("ACF Overlay Buffer" .. self:EntIndex()) then - TimerCreate("ACF Overlay Buffer" .. self:EntIndex(), 1, 1, function() - if IsValid(self) then - Overlay(self) - end - end) - end + if TimerExists("ACF Overlay Buffer" .. self:EntIndex()) then return end + + TimerCreate("ACF Overlay Buffer" .. self:EntIndex(), 0.5, 1, function() + if not IsValid(self) then return end + + Overlay(self) + end) end -- prevent people from changing bodygroup diff --git a/lua/entities/acf_gun/init.lua b/lua/entities/acf_gun/init.lua index 1791d9121..5a2d065e6 100644 --- a/lua/entities/acf_gun/init.lua +++ b/lua/entities/acf_gun/init.lua @@ -227,7 +227,7 @@ do -- Metamethods -------------------------------- local Blacklist = ACF.AmmoBlacklist[Target.RoundType] if table.HasValue(Blacklist, Weapon.Class) then - return false, "That round type can't be used with this weapon." + return false, "The ammo type in this crate cannot be used for this weapon." end Weapon.Crates[Target] = true @@ -310,9 +310,8 @@ do -- Metamethods -------------------------------- Entity.Firing = Bool - if Bool and self:CanFire() then - self:Shoot() - end + if Bool and Entity:CanFire() then + Entity:Shoot() end end) @@ -664,14 +663,13 @@ do -- Metamethods -------------------------------- if Ent.Disabled then Ent:SetOverlayText("Disabled: " .. Ent.DisableReason .. "\n" .. Ent.DisableDescription) else - local Status + local Text = "%s\n\nRate of Fire: %s rpm\nShots Left: %s\nAmmo Available: %s" local AmmoType = Ent.BulletData.Type .. (Ent.BulletData.Tracer ~= 0 and "-T" or "") local Firerate = math.floor(60 / Ent.ReloadTime) local CrateAmmo = 0 + local Status - if Ent.DisableReason then - Status = "Disabled: " .. Ent.DisableReason - elseif not next(Ent.Crates) then + if not next(Ent.Crates) then Status = "Not linked to an ammo crate!" else Status = Ent.State == "Loaded" and "Loaded with " .. AmmoType or Ent.State @@ -683,23 +681,22 @@ do -- Metamethods -------------------------------- end end - Ent:SetOverlayText(string.format("%s\n\nRate of Fire: %s rpm\nShots Left: %s\nAmmo Available: %s", Status, Firerate, Ent.CurrentShot, CrateAmmo)) + Ent:SetOverlayText(Text:format(Status, Firerate, Ent.CurrentShot, CrateAmmo)) end end function ENT:UpdateOverlay(Instant) if Instant then - Overlay(self) - return + return Overlay(self) end - if not TimerExists("ACF Overlay Buffer" .. self:EntIndex()) then - TimerCreate("ACF Overlay Buffer" .. self:EntIndex(), 1, 1, function() - if IsValid(self) then - Overlay(self) - end - end) - end + if TimerExists("ACF Overlay Buffer" .. self:EntIndex()) then return end + + TimerCreate("ACF Overlay Buffer" .. self:EntIndex(), 0.5, 1, function() + if not IsValid(self) then return end + + Overlay(self) + end) end end ----------------------------------------- From 8f60f6ceabd8a0399e9c3b9675dffb4509d9a251 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Tue, 7 Jul 2020 05:25:41 -0400 Subject: [PATCH 100/279] Moved clientside convars to acf_globals file - Moved the acf_drawboxes to the acf_globals file. - Changed acf_legalhints convar to be a clientside convar and moved it to the acf_globals file. --- lua/acf/base/acf_globals.lua | 2 ++ lua/acf/base/sv_validation.lua | 3 +-- lua/weapons/gmod_tool/stools/acf_menu2.lua | 2 +- lua/weapons/gmod_tool/stools/acfmenu.lua | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lua/acf/base/acf_globals.lua b/lua/acf/base/acf_globals.lua index def1f8814..b47201f72 100644 --- a/lua/acf/base/acf_globals.lua +++ b/lua/acf/base/acf_globals.lua @@ -141,6 +141,8 @@ elseif CLIENT then CreateClientConVar("acf_cl_particlemul", 1, true, true, "Multiplier for the density of ACF effects.", 0.1, 1) CreateClientConVar("ACF_MobilityRopeLinks", 1, true, true) CreateClientConVar("acf_unparent_disabled_ents", 0, true, true, "If enabled, all entities disabled for Bad Parenting will be unparented.", 0, 1) + CreateClientConVar("acf_drawboxes", 0, true, false, "Whether or not to draw hitboxes on ACF entities", 0, 1) + CreateClientConVar("acf_legalhints", 1, true, true, "If enabled, ACF will throw a warning hint whenever an entity gets disabled.", 0, 1) -- Display Info Bubble ---------------------- local ShowInfo = GetConVar("acf_show_entity_info") diff --git a/lua/acf/base/sv_validation.lua b/lua/acf/base/sv_validation.lua index d8caae7a0..fee76c2f5 100644 --- a/lua/acf/base/sv_validation.lua +++ b/lua/acf/base/sv_validation.lua @@ -1,5 +1,4 @@ -- Entity validation for ACF -local LegalHints = CreateConVar("acf_legalhints", 1, FCVAR_ARCHIVE) -- Local Vars ----------------------------------- local Gamemode = GetConVar("acf_gamemode") @@ -78,7 +77,7 @@ local function CheckLegal(Entity) Entity:Disable() -- Let the entity know it's disabled if Entity.UpdateOverlay then Entity:UpdateOverlay(true) end -- Update overlay if it has one (Passes true to update overlay instantly) - if LegalHints:GetBool() then -- Notify the owner + if tobool(Owner:GetInfo("acf_legalhints")) then -- Notify the owner local Name = Entity.WireDebugName .. " [" .. Entity:EntIndex() .. "]" if Reason == "Not drawn" then -- Thank you garry, very cool diff --git a/lua/weapons/gmod_tool/stools/acf_menu2.lua b/lua/weapons/gmod_tool/stools/acf_menu2.lua index 104a068c9..8dd72a46b 100644 --- a/lua/weapons/gmod_tool/stools/acf_menu2.lua +++ b/lua/weapons/gmod_tool/stools/acf_menu2.lua @@ -6,7 +6,7 @@ ACF.LoadToolFunctions(TOOL) cleanup.Register("acfmenu") if CLIENT then - local DrawBoxes = CreateConVar("acf_drawboxes", 0, FCVAR_ARCHIVE, "Whether or not to draw hitboxes on ACF entities", 0, 1) + local DrawBoxes = GetConVar("acf_drawboxes") language.Add("Tool.acf_menu2.name", "Armored Combat Framework") language.Add("Tool.acf_menu2.desc", "Testing the new menu tool") diff --git a/lua/weapons/gmod_tool/stools/acfmenu.lua b/lua/weapons/gmod_tool/stools/acfmenu.lua index 066ea96ef..e7092060e 100644 --- a/lua/weapons/gmod_tool/stools/acfmenu.lua +++ b/lua/weapons/gmod_tool/stools/acfmenu.lua @@ -36,7 +36,7 @@ if CLIENT then language.Add( "SBoxLimit_acf_ammo", "You've reached the ACF Explosives limit!" ) language.Add( "SBoxLimit_acf_sensor", "You've reached the ACF Sensors limit!" ) - local DrawBoxes = CreateConVar("acf_drawboxes", 0, FCVAR_ARCHIVE, "Whether or not to draw hitboxes on ACF entities", 0, 1) + local DrawBoxes = GetConVar("acf_drawboxes") function TOOL.BuildCPanel( CPanel ) From 586f0e036995d60572f42714844a0094260c4c24 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Tue, 7 Jul 2020 05:27:01 -0400 Subject: [PATCH 101/279] Added Collapsible and ModelPreview to ACF Panel - Added PANEL:AddCollapsible function to the ACF Panel. - Added PANEL:AddModelPreview function to the ACF Panel. - Reduced the horizontal dock margin on help labels. --- lua/vgui/acf_panel.lua | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/lua/vgui/acf_panel.lua b/lua/vgui/acf_panel.lua index 4ee5c1a7c..472e3f1b9 100644 --- a/lua/vgui/acf_panel.lua +++ b/lua/vgui/acf_panel.lua @@ -164,7 +164,7 @@ end function PANEL:AddHelp(Text) local TextColor = self:GetSkin().Colours.Tree.Hover local Panel = self:AddLabel(Text) - Panel:DockMargin(32, 0, 32, 10) + Panel:DockMargin(10, 0, 10, 10) Panel:SetTextColor(TextColor) Panel:InvalidateLayout() @@ -213,6 +213,33 @@ function PANEL:AddNumberWang(Label, Min, Max, Decimals) return Wang, Text end +function PANEL:AddCollapsible(Text, State) + if State == nil then State = true end + + local Base = vgui.Create("ACF_Panel") + Base:DockMargin(5, 5, 5, 10) + + local Category = self:AddPanel("DCollapsibleCategory") + Category:SetLabel(Text or "Title") + Category:DoExpansion(State) + Category:SetContents(Base) + + return Base, Category +end + +function PANEL:AddModelPreview(Model) + local Panel = self:AddPanel("DModelPanel") + Panel:SetModel(Model or "models/props_junk/PopCan01a.mdl") + Panel:SetLookAt(Vector()) + Panel:SetCamPos(Vector(45, 60, 45)) + Panel:SetHeight(80) + Panel:SetFOV(75) + + Panel.LayoutEntity = function() end + + return Panel +end + function PANEL:PerformLayout() self:SizeToChildren(true, true) end From 7975348e1a1c8d6e5ba5914102e8192a3b57806c Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Tue, 7 Jul 2020 05:39:39 -0400 Subject: [PATCH 102/279] Added Settings menu option - Added a new option to the menu that displays all the existing clientside convars the player can mess with. --- lua/acf/client/cl_menu.lua | 1 + lua/acf/client/menu_items/settings_menu.lua | 80 +++++++++++++++++++++ 2 files changed, 81 insertions(+) create mode 100644 lua/acf/client/menu_items/settings_menu.lua diff --git a/lua/acf/client/cl_menu.lua b/lua/acf/client/cl_menu.lua index 71b77af92..125ce92a3 100644 --- a/lua/acf/client/cl_menu.lua +++ b/lua/acf/client/cl_menu.lua @@ -70,6 +70,7 @@ do -- Menu population functions ACF.AddOption("About the Addon", "information") ACF.AddOptionItem("About the Addon", "Online Wiki", "book_open") ACF.AddOptionItem("About the Addon", "Updates", "newspaper") + ACF.AddOptionItem("About the Addon", "Settings", "wrench") ACF.AddOptionItem("About the Addon", "Contact Us", "feed") ACF.AddOption("Entities", "brick") diff --git a/lua/acf/client/menu_items/settings_menu.lua b/lua/acf/client/menu_items/settings_menu.lua new file mode 100644 index 000000000..26cb8cfa9 --- /dev/null +++ b/lua/acf/client/menu_items/settings_menu.lua @@ -0,0 +1,80 @@ +local Ent_Info = GetConVar("acf_show_entity_info") +local InfoHelp = { + [0] = "ACF entities will never display their information bubble when the player looks at them.", + [1] = "ACF entities will only display their information bubble when the player looks at them while they're not seated.", + [2] = "ACF entities will always display their information bubble when a player looks at them." +} + +local function CreateMenu(Menu) + do -- Entity Information Settings + local InfoValue = InfoHelp[Ent_Info:GetInt()] and Ent_Info:GetInt() or 1 + local Base = Menu:AddCollapsible("Entity Information") + + Base:AddLabel("Display ACF entity information:") + + local Info = Base:AddComboBox() + Info:AddChoice("Never", 0) + Info:AddChoice("When not seated", 1) + Info:AddChoice("Always", 2) + + local InfoDesc = Base:AddHelp() + InfoDesc:SetText(InfoHelp[InfoValue]) + + function Info:OnSelect(_, _, Data) + if not InfoHelp[Data] then + Data = 1 + end + + Ent_Info:SetInt(Data) + + InfoDesc:SetText(InfoHelp[Data]) + end + + Info:ChooseOptionID(InfoValue + 1) + + local HitBox = Base:AddCheckBox("Draw hitboxes on ACF entities.") + HitBox:SetConVar("acf_drawboxes") + + Base:AddHelp("Some entities might display more than just their hitbox.") + + local Rounds = Base:AddSlider("Max Rounds", 0, 64, 0) + Rounds:SetConVar("ACF_MaxRoundsDisplay") + + Base:AddHelp("Requires hitboxes to be enabled. Defines the maximum amount of rounds an ammo crate needs to have before using bulk display.") + end + + do -- Legal Check Settings + local Base = Menu:AddCollapsible("Legal Checks") + + local Hints = Base:AddCheckBox("Enable hints on entity disabling.") + Hints:SetConVar("acf_legalhints") + + local Parent = Base:AddCheckBox("Unparent disabled entities.") + Parent:SetConVar("acf_unparent_disabled_ents") + + Base:AddHelp("This option will only apply for entities that were disabled for 'Bad Parenting'.") + end + + do -- Aesthetic Settings + local Base = Menu:AddCollapsible("Aesthetic Settings") + + local Ropes = Base:AddCheckBox("Create mobility rope links.") + Ropes:SetConVar("ACF_MobilityRopeLinks") + + local Particles = Base:AddSlider("Particle Mult.", 0.1, 1, 2) + Particles:SetConVar("acf_cl_particlemul") + + Base:AddHelp("Defines the clientside particle multiplier, reduce it if you're experiencing lag when ACF effects are created.") + end + + do -- Tool Settings + local Base = Menu:AddCollapsible("Tool Settings") + + local Category = Base:AddCheckBox("Use custom category for ACF tools.") + Category:SetConVar("acf_tool_category") + + Base:AddHelp("You will need to rejoin the server for this option to apply.") + end +end + +ACF.AddOptionItem("About the Addon", "Settings", "wrench", CreateMenu) From f04226e74c167c3b38a791ee761728f535843b43 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Tue, 7 Jul 2020 05:41:05 -0400 Subject: [PATCH 103/279] Updated existing menus - Updated all existing menus so they can use the newly added collapsible sections and model preview panels. - Updated all the menus that spawn entities to state the entities they create can be fully parented. --- lua/acf/client/menu_items/components_menu.lua | 24 ++++-- lua/acf/client/menu_items/contact.lua | 54 ++++++++----- lua/acf/client/menu_items/engines_menu.lua | 45 ++++++++--- lua/acf/client/menu_items/gearboxes_menu.lua | 76 ++++++++++-------- lua/acf/client/menu_items/online_wiki.lua | 2 +- lua/acf/client/menu_items/sensors_menu.lua | 24 ++++-- lua/acf/client/menu_items/weapons_menu.lua | 78 ++++++++++++------- lua/acf/shared/fuel_types/electric.lua | 2 +- 8 files changed, 201 insertions(+), 104 deletions(-) diff --git a/lua/acf/client/menu_items/components_menu.lua b/lua/acf/client/menu_items/components_menu.lua index 2b662d03f..7351ab75f 100644 --- a/lua/acf/client/menu_items/components_menu.lua +++ b/lua/acf/client/menu_items/components_menu.lua @@ -41,10 +41,15 @@ local function CreateMenu(Menu) return end + Menu:AddTitle("Component Settings") + local ComponentClass = Menu:AddComboBox() local ComponentList = Menu:AddComboBox() - local ComponentName = Menu:AddTitle() - local ComponentDesc = Menu:AddLabel() + + local Base = Menu:AddCollapsible("Component Information") + local ComponentName = Base:AddTitle() + local ComponentDesc = Base:AddLabel() + local ComponentPreview = Base:AddModelPreview() function ComponentClass:OnSelect(Index, _, Data) if self.Selected == Data then return end @@ -64,6 +69,7 @@ local function CreateMenu(Menu) self.Selected = Data + local Preview = Data.Preview local ClassData = ComponentClass.Selected local Choices = Sorted[ClassData.Items] Selected[Choices] = Index @@ -73,16 +79,22 @@ local function CreateMenu(Menu) ComponentName:SetText(Data.Name) ComponentDesc:SetText(Data.Description or "No description provided.") - Menu:ClearTemporal(self) - Menu:StartTemporal(self) + ComponentPreview:SetModel(Data.Model) + ComponentPreview:SetCamPos(Preview and Preview.Offset or Vector(45, 60, 45)) + ComponentPreview:SetLookAt(Preview and Preview.Position or Vector()) + ComponentPreview:SetHeight(Preview and Preview.Height or 80) + ComponentPreview:SetFOV(Preview and Preview.FOV or 75) + + Menu:ClearTemporal(Base) + Menu:StartTemporal(Base) local CustomMenu = Data.CreateMenu or ClassData.CreateMenu if CustomMenu then - CustomMenu(Data, Menu) + CustomMenu(Data, Base) end - Menu:EndTemporal(self) + Menu:EndTemporal(Base) end LoadSortedList(ComponentClass, Components, "ID") diff --git a/lua/acf/client/menu_items/contact.lua b/lua/acf/client/menu_items/contact.lua index 7abfa367a..47e6d3e39 100644 --- a/lua/acf/client/menu_items/contact.lua +++ b/lua/acf/client/menu_items/contact.lua @@ -2,41 +2,53 @@ local function CreateMenu(Menu) Menu:AddTitle("Your feedback is important.") Menu:AddLabel("For this reason, we've setup a variety of methods to generate discussion among the members of the ACF community.") - Menu:AddTitle("How to Contribute") - Menu:AddLabel("To make it easier for first time contributors, we've left a guide about how to contribute to the addon.") + do -- Official Discord Server + local Base = Menu:AddCollapsible("Official Discord Server", false) - local Contribute = Menu:AddButton("Contributing to ACF") + Base:AddLabel("We have a Discord server! You can discuss the addon's development or just hang around on one of the off-topic channels.") - function Contribute:DoClickInternal() - gui.OpenURL("https://github.com/Stooberton/ACF-3/blob/master/CONTRIBUTING.md") + local Link = Base:AddButton("Join the Discord Server") + + function Link:DoClickInternal() + gui.OpenURL("https://discordapp.com/invite/shk5sc5") + end end - Menu:AddTitle("Official Discord Server") - Menu:AddLabel("We have a Discord server! You can discuss the addon's development or just hang around on one of the off-topic channels.") + do -- Official Steam Group + local Base = Menu:AddCollapsible("Official Steam Group", false) + + Base:AddLabel("There's also a Steam group, you'll find all important announcements about the addon's development there.") - local Discord = Menu:AddButton("Join the Discord Server") + local Link = Base:AddButton("Join the Steam Group") - function Discord:DoClickInternal() - gui.OpenURL("https://discordapp.com/invite/shk5sc5") + function Link:DoClickInternal() + gui.OpenURL("https://steamcommunity.com/groups/officialacf") + end end - Menu:AddTitle("Official Steam Group") - Menu:AddLabel("There's also a Steam group, you'll find all important announcements about the addon's development there.") + do -- "Github Issues & Suggestions" + local Base = Menu:AddCollapsible("Github Issues & Suggestions", false) - local Steam = Menu:AddButton("Join the Steam Group") + Base:AddLabel("The recommended method for bug reporting and suggestion posting is the Issues tab on the Github repository.") + Base:AddLabel("By using this method, you'll be able to easily track your issue and the discussion related to it.") - function Steam:DoClickInternal() - gui.OpenURL("https://steamcommunity.com/groups/officialacf") + local Link = Base:AddButton("Report an Issue") + + function Link:DoClickInternal() + gui.OpenURL("https://github.com/Stooberton/ACF-3/issues/new/choose") + end end - Menu:AddTitle("Github Issues & Suggestions") - Menu:AddLabel("The recommended method for bug reporting and suggestion posting is the Issues tab on the Github repository.") - Menu:AddLabel("By using this method, you'll be able to easily track your issue and the discussion related to it.") + do -- How to Contribute + local Base = Menu:AddCollapsible("How to Contribute", false) + + Base:AddLabel("To make it easier for first time contributors, we've left a guide about how to contribute to the addon.") - local Issue = Menu:AddButton("Report an Issue") + local Link = Base:AddButton("Contributing to ACF") - function Issue:DoClickInternal() - gui.OpenURL("https://github.com/Stooberton/ACF-3/issues/new/choose") + function Link:DoClickInternal() + gui.OpenURL("https://github.com/Stooberton/ACF-3/blob/master/CONTRIBUTING.md") + end end end diff --git a/lua/acf/client/menu_items/engines_menu.lua b/lua/acf/client/menu_items/engines_menu.lua index bdc2eae5c..5b05f9efa 100644 --- a/lua/acf/client/menu_items/engines_menu.lua +++ b/lua/acf/client/menu_items/engines_menu.lua @@ -39,7 +39,7 @@ local function UpdateEngineStats(Label, Data) local MinPower = RPM.PeakMin local MaxPower = RPM.PeakMax - local RPMText = "Idle RPM : %s RPM\nPowerband : %s-%s RPM\nRedline : %s RPM\nMass : %s" + local RPMText = "Idle RPM : %s RPM\nPowerband : %s-%s RPM\nRedline : %s RPM\nMass : %s\n\nThis entity can be fully parented." local LabelText = "" -- Electric motors and turbines get peak power in middle of rpm range @@ -72,9 +72,9 @@ local function UpdateEngineStats(Label, Data) AddText = Text:format(Fuel.Name, math.Round(Rate, 2), math.Round(Rate * 0.264, 2), PeakkWRPM) end - Consumption = Consumption .. AddText .. "\n\nThis engine requires fuel." + Consumption = Consumption .. AddText - Data.Fuel[K] = Fuel -- Replace once engines use the proper class functions + Data.Fuel[K] = Fuel -- TODO: Replace once engines use the proper class functions end Power = Power .. "\n" .. PowerText:format(math.floor(PeakkW), math.floor(PeakkW * 1.34), PeakkWRPM) @@ -86,18 +86,26 @@ local function UpdateEngineStats(Label, Data) end local function CreateMenu(Menu) + Menu:AddTitle("Engine Settings") + local EngineClass = Menu:AddComboBox() local EngineList = Menu:AddComboBox() - local EngineName = Menu:AddTitle() - local EngineDesc = Menu:AddLabel() - local EngineStats = Menu:AddLabel() - Menu:AddTitle("Fuel Settings") + local EngineBase = Menu:AddCollapsible("Engine Information") + local EngineName = EngineBase:AddTitle() + local EngineDesc = EngineBase:AddLabel() + local EnginePreview = EngineBase:AddModelPreview() + local EngineStats = EngineBase:AddLabel() + + Menu:AddTitle("Fuel Tank Settings") local FuelClass = Menu:AddComboBox() local FuelList = Menu:AddComboBox() local FuelType = Menu:AddComboBox() - local FuelDesc = Menu:AddLabel() + local FuelBase = Menu:AddCollapsible("Fuel Tank Information") + local FuelDesc = FuelBase:AddLabel() + local FuelPreview = FuelBase:AddModelPreview() + local FuelInfo = FuelBase:AddLabel() ACF.WriteValue("PrimaryClass", "acf_engine") ACF.WriteValue("SecondaryClass", "acf_fueltank") @@ -122,6 +130,7 @@ local function CreateMenu(Menu) self.Selected = Data + local Preview = Data.Preview local ClassData = EngineClass.Selected local ClassDesc = ClassData.Description local Choices = Sorted[ClassData.Items] @@ -132,6 +141,12 @@ local function CreateMenu(Menu) EngineName:SetText(Data.Name) EngineDesc:SetText((ClassDesc and (ClassDesc .. "\n\n") or "") .. Data.Description) + EnginePreview:SetModel(Data.Model) + EnginePreview:SetCamPos(Preview and Preview.Offset or Vector(45, 60, 45)) + EnginePreview:SetLookAt(Preview and Preview.Position or Vector()) + EnginePreview:SetHeight(Preview and Preview.Height or 80) + EnginePreview:SetFOV(Preview and Preview.FOV or 75) + UpdateEngineStats(EngineStats, Data) LoadSortedList(FuelType, Data.Fuel, "ID") @@ -153,6 +168,7 @@ local function CreateMenu(Menu) self.Selected = Data + local Preview = Data.Preview local ClassData = FuelClass.Selected local ClassDesc = ClassData.Description local Choices = Sorted[ClassData.Items] @@ -162,6 +178,12 @@ local function CreateMenu(Menu) ACF.WriteValue("FuelTank", Data.ID) + FuelPreview:SetModel(Data.Model) + FuelPreview:SetCamPos(Preview and Preview.Offset or Vector(45, 60, 45)) + FuelPreview:SetLookAt(Preview and Preview.Position or Vector()) + FuelPreview:SetHeight(Preview and Preview.Height or 80) + FuelPreview:SetFOV(Preview and Preview.FOV or 75) + FuelType:UpdateFuelText() end @@ -184,8 +206,8 @@ local function CreateMenu(Menu) if not FuelList.Selected then return end local FuelTank = FuelList.Selected - local FuelText = FuelList.Description local TextFunc = self.Selected.FuelTankText + local FuelText = "" local Wall = 0.03937 --wall thickness in inches (1mm) local Volume = FuelTank.Volume - (FuelTank.SurfaceArea * Wall) -- total volume of tank (cu in), reduced by wall thickness @@ -196,7 +218,7 @@ local function CreateMenu(Menu) if TextFunc then FuelText = FuelText .. TextFunc(Capacity, Mass, EmptyMass) else - local Text = "\n\nCapacity : %s L - %s gal\nFull Mass : %s\nEmpty Mass : %s" + local Text = "Capacity : %s L - %s gal\nFull Mass : %s\nEmpty Mass : %s\n\nThis entity can be fully parented." local Liters = math.Round(Capacity, 2) local Gallons = math.Round(Capacity * 0.264172, 2) @@ -211,7 +233,8 @@ local function CreateMenu(Menu) FuelText = FuelText .. "\n\nThis fuel tank cannot be linked to other ACF entities." end - FuelDesc:SetText(FuelText) + FuelDesc:SetText(FuelList.Description) + FuelInfo:SetText(FuelText) end LoadSortedList(EngineClass, Engines, "ID") diff --git a/lua/acf/client/menu_items/gearboxes_menu.lua b/lua/acf/client/menu_items/gearboxes_menu.lua index a2a20b053..8fe50d1e0 100644 --- a/lua/acf/client/menu_items/gearboxes_menu.lua +++ b/lua/acf/client/menu_items/gearboxes_menu.lua @@ -30,10 +30,15 @@ local function LoadSortedList(Panel, List, Member) end local function CreateMenu(Menu) + Menu:AddTitle("Gearbox Settings") + local GearboxClass = Menu:AddComboBox() local GearboxList = Menu:AddComboBox() - local GearboxName = Menu:AddTitle() - local GearboxDesc = Menu:AddLabel() + + local Base = Menu:AddCollapsible("Gearbox Information") + local GearboxName = Base:AddTitle() + local GearboxDesc = Base:AddLabel() + local GearboxPreview = Base:AddModelPreview() ACF.WriteValue("PrimaryClass", "acf_gearbox") ACF.WriteValue("SecondaryClass", "N/A") @@ -59,6 +64,7 @@ local function CreateMenu(Menu) self.Selected = Data + local Preview = Data.Preview local ClassData = GearboxClass.Selected local Choices = Sorted[ClassData.Items] Selected[Choices] = Index @@ -68,14 +74,20 @@ local function CreateMenu(Menu) GearboxName:SetText(Data.Name) GearboxDesc:SetText(Data.Description) - Menu:ClearTemporal(self) - Menu:StartTemporal(self) + GearboxPreview:SetModel(Data.Model) + GearboxPreview:SetCamPos(Preview and Preview.Offset or Vector(45, 60, 45)) + GearboxPreview:SetLookAt(Preview and Preview.Position or Vector()) + GearboxPreview:SetHeight(Preview and Preview.Height or 80) + GearboxPreview:SetFOV(Preview and Preview.FOV or 75) + + Menu:ClearTemporal(Base) + Menu:StartTemporal(Base) if ClassData.CreateMenu then - ClassData:CreateMenu(Data, Menu) + ClassData:CreateMenu(Data, Menu, Base) end - Menu:EndTemporal(self) + Menu:EndTemporal(Base) end LoadSortedList(GearboxClass, Gearboxes, "ID") @@ -87,21 +99,21 @@ do -- Default Menus local Values = {} do -- Manual Gearbox Menu - function ACF.ManualGearboxMenu(Class, Data, Menu) - local Text = "Mass : %s\nTorque Rating : %s n/m - %s fl-lb" + function ACF.ManualGearboxMenu(Class, Data, Menu, Base) + local Text = "Mass : %s\nTorque Rating : %s n/m - %s fl-lb\n\nThis entity can be fully parented." local Mass = ACF.GetProperMass(Data.Mass) local Gears = Class.Gears local Torque = math.floor(Data.MaxTorque * 0.73) - Menu:AddLabel(Text:format(Mass, Data.MaxTorque, Torque)) + Base:AddLabel(Text:format(Mass, Data.MaxTorque, Torque)) if Data.DualClutch then - Menu:AddLabel("The dual clutch allows you to apply power and brake each side independently.") + Base:AddLabel("The dual clutch allows you to apply power and brake each side independently.") end ----------------------------------- - Menu:AddTitle("Gear Settings") + local GearBase = Menu:AddCollapsible("Gear Settings") Values[Class.ID] = Values[Class.ID] or {} @@ -119,7 +131,7 @@ do -- Default Menus ACF.WriteValue(Variable, Default) - local Control = Menu:AddSlider("Gear " .. I, -1, 1, 2) + local Control = GearBase:AddSlider("Gear " .. I, -1, 1, 2) Control:SetDataVar(Variable, "OnValueChanged") Control:SetValueFunction(function(Panel) local Value = math.Round(ACF.ReadNumber(Variable), 2) @@ -138,7 +150,7 @@ do -- Default Menus ACF.WriteValue("FinalDrive", ValuesData.FinalDrive) - local FinalDrive = Menu:AddSlider("Final Drive", -1, 1, 2) + local FinalDrive = GearBase:AddSlider("Final Drive", -1, 1, 2) FinalDrive:SetDataVar("FinalDrive", "OnValueChanged") FinalDrive:SetValueFunction(function(Panel) local Value = math.Round(ACF.ReadNumber("FinalDrive"), 2) @@ -188,20 +200,20 @@ do -- Default Menus }, } - function ACF.CVTGearboxMenu(Class, Data, Menu) - local Text = "Mass : %s\nTorque Rating : %s n/m - %s fl-lb" + function ACF.CVTGearboxMenu(Class, Data, Menu, Base) + local Text = "Mass : %s\nTorque Rating : %s n/m - %s fl-lb\n\nThis entity can be fully parented." local Mass = ACF.GetProperMass(Data.Mass) local Torque = math.floor(Data.MaxTorque * 0.73) - Menu:AddLabel(Text:format(Mass, Data.MaxTorque, Torque)) + Base:AddLabel(Text:format(Mass, Data.MaxTorque, Torque)) if Data.DualClutch then - Menu:AddLabel("The dual clutch allows you to apply power and brake each side independently.") + Base:AddLabel("The dual clutch allows you to apply power and brake each side independently.") end ----------------------------------- - Menu:AddTitle("Gear Settings") + local GearBase = Menu:AddCollapsible("Gear Settings") Values[Class.ID] = Values[Class.ID] or {} @@ -221,7 +233,7 @@ do -- Default Menus ACF.WriteValue(Variable, Default) - local Control = Menu:AddSlider(GearData.Name, GearData.Min, GearData.Max, GearData.Decimals) + local Control = GearBase:AddSlider(GearData.Name, GearData.Min, GearData.Max, GearData.Decimals) Control:SetDataVar(Variable, "OnValueChanged") Control:SetValueFunction(function(Panel) local Value = math.Round(ACF.ReadNumber(Variable), GearData.Decimals) @@ -287,31 +299,31 @@ do -- Default Menus }, } - function ACF.AutomaticGearboxMenu(Class, Data, Menu) - local Text = "Mass : %s\nTorque Rating : %s n/m - %s fl-lb" + function ACF.AutomaticGearboxMenu(Class, Data, Menu, Base) + local Text = "Mass : %s\nTorque Rating : %s n/m - %s fl-lb\n\nThis entity can be fully parented." local Mass = ACF.GetProperMass(Data.Mass) local Gears = Class.Gears local Torque = math.floor(Data.MaxTorque * 0.73) - Menu:AddLabel(Text:format(Mass, Data.MaxTorque, Torque)) + Base:AddLabel(Text:format(Mass, Data.MaxTorque, Torque)) if Data.DualClutch then - Menu:AddLabel("The dual clutch allows you to apply power and brake each side independently.") + Base:AddLabel("The dual clutch allows you to apply power and brake each side independently.") end ----------------------------------- - Menu:AddTitle("Gear Settings") + local GearBase = Menu:AddCollapsible("Gear Settings") Values[Class.ID] = Values[Class.ID] or {} local ValuesData = Values[Class.ID] - Menu:AddLabel("Upshift Speed Unit :") + GearBase:AddLabel("Upshift Speed Unit :") ACF.WriteValue("ShiftUnit", UnitMult) - local Unit = Menu:AddComboBox() + local Unit = GearBase:AddComboBox() Unit:AddChoice("KPH", 10.936) Unit:AddChoice("MPH", 17.6) Unit:AddChoice("GMU", 1) @@ -345,7 +357,7 @@ do -- Default Menus ACF.WriteValue(GearVar, DefGear) - local Gear = Menu:AddSlider("Gear " .. I, -1, 1, 2) + local Gear = GearBase:AddSlider("Gear " .. I, -1, 1, 2) Gear:SetDataVar(GearVar, "OnValueChanged") Gear:SetValueFunction(function(Panel) local Value = math.Round(ACF.ReadNumber(GearVar), 2) @@ -368,7 +380,7 @@ do -- Default Menus ACF.WriteValue(ShiftVar, DefShift) - local Shift = Menu:AddNumberWang("Gear " .. I .. " Upshift Speed", 0, 9999, 2) + local Shift = GearBase:AddNumberWang("Gear " .. I .. " Upshift Speed", 0, 9999, 2) Shift:HideWang() Shift:SetDataVar(ShiftVar, "OnValueChanged") Shift:SetValueFunction(function(Panel) @@ -394,7 +406,7 @@ do -- Default Menus ACF.WriteValue(Variable, Default) - local Control = Menu:AddSlider(GearData.Name, GearData.Min, GearData.Max, GearData.Decimals) + local Control = GearBase:AddSlider(GearData.Name, GearData.Min, GearData.Max, GearData.Decimals) Control:SetDataVar(Variable, "OnValueChanged") Control:SetValueFunction(function(Panel) local Value = math.Round(ACF.ReadNumber(Variable), GearData.Decimals) @@ -411,7 +423,7 @@ do -- Default Menus ----------------------------------- - Menu:AddTitle("Shift Point Generator") + local GenBase = Menu:AddCollapsible("Shift Point Generator") for _, PanelData in ipairs(GenData) do local Variable = PanelData.Variable @@ -425,7 +437,7 @@ do -- Default Menus ACF.WriteValue(Variable, Default) - local Panel = Menu:AddNumberWang(PanelData.Name, PanelData.Min, PanelData.Max, PanelData.Decimals) + local Panel = GenBase:AddNumberWang(PanelData.Name, PanelData.Min, PanelData.Max, PanelData.Decimals) Panel:HideWang() Panel:SetDataVar(Variable, "OnValueChanged") Panel:SetValueFunction(function() @@ -443,7 +455,7 @@ do -- Default Menus end end - local Button = Menu:AddButton("Calculate") + local Button = GenBase:AddButton("Calculate") function Button:DoClickInternal() local UpshiftRPM = ValuesData.UpshiftRPM diff --git a/lua/acf/client/menu_items/online_wiki.lua b/lua/acf/client/menu_items/online_wiki.lua index b686c6935..bf0a7b32a 100644 --- a/lua/acf/client/menu_items/online_wiki.lua +++ b/lua/acf/client/menu_items/online_wiki.lua @@ -9,7 +9,7 @@ local function CreateMenu(Menu) gui.OpenURL("https://github.com/Stooberton/ACF-3/wiki") end - Menu:AddLabel("Note: The wiki is still a work in progress, it'll get populated as time passes.") + Menu:AddHelp("The wiki is still a work in progress, it'll get populated as time passes.") end ACF.AddOptionItem("About the Addon", "Online Wiki", "book_open", CreateMenu) diff --git a/lua/acf/client/menu_items/sensors_menu.lua b/lua/acf/client/menu_items/sensors_menu.lua index 8b258abca..45737dcef 100644 --- a/lua/acf/client/menu_items/sensors_menu.lua +++ b/lua/acf/client/menu_items/sensors_menu.lua @@ -41,10 +41,15 @@ local function CreateMenu(Menu) return end + Menu:AddTitle("Sensor Settings") + local SensorClass = Menu:AddComboBox() local SensorList = Menu:AddComboBox() - local SensorName = Menu:AddTitle() - local SensorDesc = Menu:AddLabel() + + local Base = Menu:AddCollapsible("Sensor Information") + local SensorName = Base:AddTitle() + local SensorDesc = Base:AddLabel() + local SensorPreview = Base:AddModelPreview() function SensorClass:OnSelect(Index, _, Data) if self.Selected == Data then return end @@ -64,6 +69,7 @@ local function CreateMenu(Menu) self.Selected = Data + local Preview = Data.Preview local ClassData = SensorClass.Selected local Choices = Sorted[ClassData.Items] Selected[Choices] = Index @@ -73,16 +79,22 @@ local function CreateMenu(Menu) SensorName:SetText(Data.Name) SensorDesc:SetText(Data.Description or "No description provided.") - Menu:ClearTemporal(self) - Menu:StartTemporal(self) + SensorPreview:SetModel(Data.Model) + SensorPreview:SetCamPos(Preview and Preview.Offset or Vector(45, 60, 45)) + SensorPreview:SetLookAt(Preview and Preview.Position or Vector()) + SensorPreview:SetHeight(Preview and Preview.Height or 80) + SensorPreview:SetFOV(Preview and Preview.FOV or 75) + + Menu:ClearTemporal(Base) + Menu:StartTemporal(Base) local CustomMenu = Data.CreateMenu or ClassData.CreateMenu if CustomMenu then - CustomMenu(Data, Menu) + CustomMenu(Data, Base) end - Menu:EndTemporal(self) + Menu:EndTemporal(Base) end LoadSortedList(SensorClass, Sensors, "ID") diff --git a/lua/acf/client/menu_items/weapons_menu.lua b/lua/acf/client/menu_items/weapons_menu.lua index 04094c73e..beabf63fb 100644 --- a/lua/acf/client/menu_items/weapons_menu.lua +++ b/lua/acf/client/menu_items/weapons_menu.lua @@ -51,26 +51,49 @@ local function LoadSortedList(Panel, List, Member) end local function CreateMenu(Menu) - local EntText = "Mass : %s kg\nFirerate : %s rpm\nSpread : %s degrees%s" + local EntText = "Mass : %s kg\nFirerate : %s rpm\nSpread : %s degrees%s\n\nThis entity can be fully parented." local MagText = "\nRounds : %s rounds\nReload : %s seconds" local AmmoData + Menu:AddTitle("Weapon Settings") + local ClassList = Menu:AddComboBox() local EntList = Menu:AddComboBox() - local EntName = Menu:AddTitle() - local ClassDesc = Menu:AddLabel() - local EntData = Menu:AddLabel() + + local WeaponBase = Menu:AddCollapsible("Weapon Information") + local EntName = WeaponBase:AddTitle() + local ClassDesc = WeaponBase:AddLabel() + local EntPreview = WeaponBase:AddModelPreview() + local EntData = WeaponBase:AddLabel() Menu:AddTitle("Ammo Settings") local CrateList = Menu:AddComboBox() local AmmoList = Menu:AddComboBox() + local AmmoBase = Menu:AddCollapsible("Ammo Information") + local AmmoDesc = AmmoBase:AddLabel() + local AmmoPreview = AmmoBase:AddModelPreview() + ACF.WriteValue("PrimaryClass", "acf_gun") ACF.WriteValue("SecondaryClass", "acf_ammo") ACF.SetToolMode("acf_menu2", "Main", "Spawner") + local function UpdateEntityData() + local Class = ClassList.Selected + local Data = EntList.Selected + + if not Class then return "" end + if not Data then return "" end + + local ReloadTime = AmmoData and (ACF.BaseReload + (AmmoData.ProjMass + AmmoData.PropMass) * ACF.MassToTime) or 60 + local Firerate = Data.Cyclic or 60 / ReloadTime + local Magazine = Data.MagSize and MagText:format(Data.MagSize, Data.MagReload) or "" + + return EntText:format(Data.Mass, math.Round(Firerate, 2), Class.Spread * 100, Magazine) + end + function ClassList:OnSelect(Index, _, Data) if self.Selected == Data then return end @@ -92,6 +115,7 @@ local function CreateMenu(Menu) self.Selected = Data + local Preview = Data.Preview local ClassData = ClassList.Selected local Choices = Sorted[ClassData.Items] Selected[Choices] = Index @@ -99,6 +123,13 @@ local function CreateMenu(Menu) ACF.WriteValue("Weapon", Data.ID) EntName:SetText(Data.Name) + EntData:SetText(UpdateEntityData()) + + EntPreview:SetModel(Data.Model) + EntPreview:SetCamPos(Preview and Preview.Offset or Vector(45, 60, 45)) + EntPreview:SetLookAt(Preview and Preview.Position or Vector()) + EntPreview:SetHeight(Preview and Preview.Height or 80) + EntPreview:SetFOV(Preview and Preview.FOV or 75) AmmoList:UpdateMenu() end @@ -106,29 +137,24 @@ local function CreateMenu(Menu) EntData:TrackDataVar("Projectile", "SetText") EntData:TrackDataVar("Propellant") EntData:TrackDataVar("Tracer") - EntData:SetValueFunction(function() - local Class = ClassList.Selected - local Data = EntList.Selected - - if not Class then return "" end - if not Data then return "" end - - local ReloadTime = AmmoData and (ACF.BaseReload + (AmmoData.ProjMass + AmmoData.PropMass) * ACF.MassToTime) or 60 - local Firerate = Data.Cyclic or 60 / ReloadTime - local Magazine = Data.MagSize and MagText:format(Data.MagSize, Data.MagReload) or "" - - return EntText:format(Data.Mass, math.Round(Firerate, 2), Class.Spread * 100, Magazine) - end) + EntData:SetValueFunction(UpdateEntityData) function CrateList:OnSelect(Index, _, Data) if self.Selected == Data then return end self.Selected = Data + local Preview = Data.Preview local Choices = Sorted[Crates] Selected[Choices] = Index ACF.WriteValue("Crate", Data.ID) + + AmmoPreview:SetModel(Data.Model) + AmmoPreview:SetCamPos(Preview and Preview.Offset or Vector(45, 60, 45)) + AmmoPreview:SetLookAt(Preview and Preview.Position or Vector()) + AmmoPreview:SetHeight(Preview and Preview.Height or 80) + AmmoPreview:SetFOV(Preview and Preview.FOV or 75) end function AmmoList:OnSelect(Index, _, Data) @@ -141,6 +167,8 @@ local function CreateMenu(Menu) ACF.WriteValue("Ammo", Data.ID) + AmmoDesc:SetText(Data.Description .. "\n\nThis entity can be fully parented.") + self:UpdateMenu() end @@ -152,13 +180,11 @@ local function CreateMenu(Menu) AmmoData = Ammo:ClientConvert(Menu, ToolData) - Menu:ClearTemporal(self) - Menu:StartTemporal(self) - - Menu:AddLabel(Ammo.Description) + Menu:ClearTemporal(AmmoBase) + Menu:StartTemporal(AmmoBase) if not Ammo.SupressDefaultMenu then - local RoundLength = Menu:AddLabel() + local RoundLength = AmmoBase:AddLabel() RoundLength:TrackDataVar("Projectile", "SetText") RoundLength:TrackDataVar("Propellant") RoundLength:TrackDataVar("Tracer") @@ -170,7 +196,7 @@ local function CreateMenu(Menu) return Text:format(CurLength, MaxLength) end) - local Projectile = Menu:AddSlider("Projectile Length", 0, AmmoData.MaxRoundLength, 2) + local Projectile = AmmoBase:AddSlider("Projectile Length", 0, AmmoData.MaxRoundLength, 2) Projectile:SetDataVar("Projectile", "OnValueChanged") Projectile:SetValueFunction(function(Panel, IsTracked) ToolData.Projectile = ACF.ReadNumber("Projectile") @@ -188,7 +214,7 @@ local function CreateMenu(Menu) return AmmoData.ProjLength end) - local Propellant = Menu:AddSlider("Propellant Length", 0, AmmoData.MaxRoundLength, 2) + local Propellant = AmmoBase:AddSlider("Propellant Length", 0, AmmoData.MaxRoundLength, 2) Propellant:SetDataVar("Propellant", "OnValueChanged") Propellant:SetValueFunction(function(Panel, IsTracked) ToolData.Propellant = ACF.ReadNumber("Propellant") @@ -208,10 +234,10 @@ local function CreateMenu(Menu) end if Ammo.MenuAction then - Ammo:MenuAction(Menu, ToolData, AmmoData) + Ammo:MenuAction(AmmoBase, ToolData, AmmoData) end - Menu:EndTemporal(self) + Menu:EndTemporal(AmmoBase) end LoadSortedList(ClassList, Weapons, "Name") diff --git a/lua/acf/shared/fuel_types/electric.lua b/lua/acf/shared/fuel_types/electric.lua index 02f2ccf15..4e32a1dd8 100644 --- a/lua/acf/shared/fuel_types/electric.lua +++ b/lua/acf/shared/fuel_types/electric.lua @@ -8,7 +8,7 @@ ACF.RegisterFuelType("Electric", { return Text:format(math.Round(Rate, 2), math.Round(Rate * 0.06, 2)) end, FuelTankText = function(Capacity, Mass) - local Text = "\n\nCharge : %s kW per hour - %s MJ\nMass : %s" + local Text = "Charge : %s kW per hour - %s MJ\nMass : %s" local kWh = math.Round(Capacity * ACF.LiIonED, 2) local MJ = math.Round(Capacity * ACF.LiIonED * 3.6, 2) From 96781781255602c3a516835eadd7771fe215baf8 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Mon, 13 Jul 2020 07:10:20 -0400 Subject: [PATCH 104/279] Added OnClassLoaded hook - Added OnClassLoaded hook, will provide the class ID and the class table itself. --- lua/acf/base/sh_classes.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lua/acf/base/sh_classes.lua b/lua/acf/base/sh_classes.lua index bf1c15530..4bcafee61 100644 --- a/lua/acf/base/sh_classes.lua +++ b/lua/acf/base/sh_classes.lua @@ -164,6 +164,8 @@ do -- Class registration function if Class.OnLoaded then Class:OnLoaded() end + + hook.Run("OnClassLoaded", Class.ID, Class) end) end From fc51d4bf1fedfd7efe0a3b8ba2156b3b1f7de6ed Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Mon, 13 Jul 2020 07:13:08 -0400 Subject: [PATCH 105/279] Improved ACF.RoundBaseGunpowder function - Improved ACF.RoundBaseGunpowder function to be able to use the destiny defined on the tooldata table. - The new weapons menu will now update the Destiny tool data value to Weapons. - Replaced used of AMMO:GetToolData() with ACF.GetToolData() --- lua/acf/base/sh_classes.lua | 2 ++ lua/acf/base/sh_round_functions.lua | 5 +++-- lua/acf/client/menu_items/weapons_menu.lua | 3 ++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/lua/acf/base/sh_classes.lua b/lua/acf/base/sh_classes.lua index 4bcafee61..f8ad2260d 100644 --- a/lua/acf/base/sh_classes.lua +++ b/lua/acf/base/sh_classes.lua @@ -223,6 +223,8 @@ do -- Weapon registration functions function ACF.RegisterWeapon(ID, ClassID, Data) local Class = AddGroupedClass(ID, ClassID, Weapons, Data) + Class.Destiny = "Weapons" + if not Class.EntClass then Class.EntClass = "acf_gun" end diff --git a/lua/acf/base/sh_round_functions.lua b/lua/acf/base/sh_round_functions.lua index 764bdb621..ff09c9294 100644 --- a/lua/acf/base/sh_round_functions.lua +++ b/lua/acf/base/sh_round_functions.lua @@ -1,5 +1,6 @@ function ACF.RoundBaseGunpowder(ToolData, Data) - local ClassData = ACF.Classes.Weapons[ToolData.WeaponClass] + local Class = ACF.Classes[ToolData.Destiny] + local ClassData = Class and Class[ToolData.WeaponClass] local WeaponData = ClassData and ClassData.Lookup[ToolData.Weapon] local GUIData = {} @@ -17,7 +18,7 @@ function ACF.RoundBaseGunpowder(ToolData, Data) local DesiredProp = math.Round(RoundData.PropMass * 1000 / ACF.PDensity / Data.FrArea, 2) local AllowedProp = GUIData.MaxRoundLength - GUIData.MinProjLength - GUIData.MaxPropLength = math.min(DesiredProp, AllowedProp) -- GUIData.MaxRoundLength - GUIData.MinProjLength + GUIData.MaxPropLength = math.min(DesiredProp, AllowedProp) GUIData.MaxProjLength = GUIData.MaxRoundLength - GUIData.MinPropLength ACF.UpdateRoundSpecs(ToolData, Data, GUIData) diff --git a/lua/acf/client/menu_items/weapons_menu.lua b/lua/acf/client/menu_items/weapons_menu.lua index beabf63fb..87941f2b4 100644 --- a/lua/acf/client/menu_items/weapons_menu.lua +++ b/lua/acf/client/menu_items/weapons_menu.lua @@ -121,6 +121,7 @@ local function CreateMenu(Menu) Selected[Choices] = Index ACF.WriteValue("Weapon", Data.ID) + ACF.WriteValue("Destiny", Data.Destiny) EntName:SetText(Data.Name) EntData:SetText(UpdateEntityData()) @@ -176,7 +177,7 @@ local function CreateMenu(Menu) if not self.Selected then return end local Ammo = self.Selected - local ToolData = Ammo:GetToolData() + local ToolData = ACF.GetToolData() AmmoData = Ammo:ClientConvert(Menu, ToolData) From 50bd3628c94c4397b510317397499a092ae44337 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Mon, 13 Jul 2020 07:13:44 -0400 Subject: [PATCH 106/279] Removed unused Ammo:GetToolData function - Removed the now unused Ammo:GetToolData function --- lua/acf/shared/ammo_types/ap.lua | 11 ----------- lua/acf/shared/ammo_types/aphe.lua | 7 ------- lua/acf/shared/ammo_types/fl.lua | 8 -------- lua/acf/shared/ammo_types/heat.lua | 8 -------- lua/acf/shared/ammo_types/hp.lua | 7 ------- lua/acf/shared/ammo_types/refill.lua | 8 -------- lua/acf/shared/ammo_types/smoke.lua | 9 --------- 7 files changed, 58 deletions(-) diff --git a/lua/acf/shared/ammo_types/ap.lua b/lua/acf/shared/ammo_types/ap.lua index eb308f9e8..fae3c479d 100644 --- a/lua/acf/shared/ammo_types/ap.lua +++ b/lua/acf/shared/ammo_types/ap.lua @@ -95,17 +95,6 @@ function Ammo:GetCrateText(BulletData) return Text:format(math.Round(BulletData.MuzzleVel, 2), math.Round(Data.MaxPen, 2)) end -function Ammo:GetToolData() - return { - Ammo = ACF.ReadString("Ammo"), - Weapon = ACF.ReadString("Weapon"), - WeaponClass = ACF.ReadString("WeaponClass"), - Projectile = ACF.ReadNumber("Projectile"), - Propellant = ACF.ReadNumber("Propellant"), - Tracer = ACF.ReadBool("Tracer"), - } -end - function Ammo:PropImpact(_, Bullet, Target, HitNormal, HitPos, Bone) if ACF_Check(Target) then local Speed = Bullet.Flight:Length() / ACF.Scale diff --git a/lua/acf/shared/ammo_types/aphe.lua b/lua/acf/shared/ammo_types/aphe.lua index 3b29fc571..5a0b1a2c7 100644 --- a/lua/acf/shared/ammo_types/aphe.lua +++ b/lua/acf/shared/ammo_types/aphe.lua @@ -89,13 +89,6 @@ function Ammo:GetCrateText(BulletData) return Text:format(math.Round(Data.BlastRadius, 2), math.Round(BulletData.FillerMass * ACF.HEPower, 2)) end -function Ammo:GetToolData() - local Data = Ammo.BaseClass.GetToolData(self) - Data.FillerMass = ACF.ReadNumber("FillerMass") - - return Data -end - function Ammo:OnFlightEnd(Index, Bullet, HitPos) ACF_HE(HitPos - Bullet.Flight:GetNormalized() * 3, Bullet.FillerMass, Bullet.ProjMass - Bullet.FillerMass, Bullet.Owner, nil, Bullet.Gun) diff --git a/lua/acf/shared/ammo_types/fl.lua b/lua/acf/shared/ammo_types/fl.lua index 4194b9b69..5dc9be981 100644 --- a/lua/acf/shared/ammo_types/fl.lua +++ b/lua/acf/shared/ammo_types/fl.lua @@ -161,14 +161,6 @@ function Ammo:GetCrateText(BulletData) return Text:format(math.Round(BulletData.MuzzleVel, 2), math.Round(Data.MaxPen, 2), math.Round(BulletData.FlechetteSpread + Spread, 2)) end -function Ammo:GetToolData() - local Data = Ammo.BaseClass.GetToolData(self) - Data.Flechettes = ACF.ReadNumber("Flechettes") - Data.Spread = ACF.ReadNumber("Spread") - - return Data -end - function Ammo:MenuAction(Menu, ToolData, Data) local Flechettes = Menu:AddSlider("Flechette Amount", Data.MinFlechettes, Data.MaxFlechettes) Flechettes:SetDataVar("Flechettes", "OnValueChanged") diff --git a/lua/acf/shared/ammo_types/heat.lua b/lua/acf/shared/ammo_types/heat.lua index eeb86e580..9c029036b 100644 --- a/lua/acf/shared/ammo_types/heat.lua +++ b/lua/acf/shared/ammo_types/heat.lua @@ -156,14 +156,6 @@ function Ammo:GetCrateText(BulletData) return Text:format(math.Round(BulletData.MuzzleVel, 2), math.Round(Data.MaxPen, 2), math.Round(Data.BlastRadius, 2), math.Round(Data.BoomFillerMass * ACF.HEPower, 2)) end -function Ammo:GetToolData() - local Data = Ammo.BaseClass.GetToolData(self) - Data.FillerMass = ACF.ReadNumber("FillerMass") - Data.LinerAngle = ACF.ReadNumber("LinerAngle") - - return Data -end - function Ammo:Detonate(Bullet, HitPos) local Crushed, HEATFillerMass, BoomFillerMass = self:CrushCalc(Bullet.Flight:Length() * 0.0254, Bullet.FillerMass) diff --git a/lua/acf/shared/ammo_types/hp.lua b/lua/acf/shared/ammo_types/hp.lua index ea55506cf..11e6fd8c3 100644 --- a/lua/acf/shared/ammo_types/hp.lua +++ b/lua/acf/shared/ammo_types/hp.lua @@ -82,13 +82,6 @@ function Ammo:GetCrateText(BulletData) return Text:format(math.Round(BulletData.ExpCaliber * 10, 2), math.Round(Data.MaxKETransfert, 2)) end -function Ammo:GetToolData() - local Data = Ammo.BaseClass.GetToolData(self) - Data.HollowCavity = ACF.ReadNumber("HollowCavity") - - return Data -end - function Ammo:MenuAction(Menu, ToolData, Data) local HollowCavity = Menu:AddSlider("Cavity Volume", Data.MinCavVol, Data.MaxCavVol, 2) HollowCavity:SetDataVar("HollowCavity", "OnValueChanged") diff --git a/lua/acf/shared/ammo_types/refill.lua b/lua/acf/shared/ammo_types/refill.lua index 9ee7f8f2a..e925053d1 100644 --- a/lua/acf/shared/ammo_types/refill.lua +++ b/lua/acf/shared/ammo_types/refill.lua @@ -45,13 +45,5 @@ function Ammo:GetCrateText() return "" end -function Ammo:GetToolData() - return { - Ammo = ACF.ReadString("Ammo"), - Weapon = ACF.ReadString("Weapon"), - WeaponClass = ACF.ReadString("WeaponClass"), - } -end - function Ammo:MenuAction() end diff --git a/lua/acf/shared/ammo_types/smoke.lua b/lua/acf/shared/ammo_types/smoke.lua index 3a4a911bb..1169fb701 100644 --- a/lua/acf/shared/ammo_types/smoke.lua +++ b/lua/acf/shared/ammo_types/smoke.lua @@ -130,15 +130,6 @@ function Ammo:GetCrateText(BulletData) return Text:format(math.Round(BulletData.MuzzleVel, 2), WPText, SMText) end -function Ammo:GetToolData() - local Data = Ammo.BaseClass.GetToolData(self) - Data.SmokeFiller = ACF.ReadNumber("SmokeFiller") - Data.WPFiller = ACF.ReadNumber("WPFiller") - Data.FuzeLength = ACF.ReadNumber("FuzeLength") - - return Data -end - function Ammo:PropImpact(_, Bullet, Target, HitNormal, HitPos, Bone) if ACF_Check(Target) then local Speed = Bullet.Flight:Length() / ACF.Scale From b286e02c5097b24d93a41383b8be009922badd77 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sat, 8 Aug 2020 14:31:29 -0400 Subject: [PATCH 107/279] Added ENT:ACF_OnRepaired function - When the torch repairs something, it'll attempt to call ENT:ACF_OnRepaired on the entity. --- lua/weapons/torch/shared.lua | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/lua/weapons/torch/shared.lua b/lua/weapons/torch/shared.lua index c7dac8b9f..1ae977611 100644 --- a/lua/weapons/torch/shared.lua +++ b/lua/weapons/torch/shared.lua @@ -143,20 +143,24 @@ function SWEP:PrimaryAttack() else if CPPI and not Entity:CPPICanTool(Owner, "torch") then return end - local Health = Entity.ACF.Health + local OldHealth = Entity.ACF.Health local MaxHealth = Entity.ACF.MaxHealth - if Health >= MaxHealth then return end + if OldHealth >= MaxHealth then return end - local Armor = Entity.ACF.Armour + local OldArmor = Entity.ACF.Armour local MaxArmor = Entity.ACF.MaxArmour - Health = math.min(Health + (30 / MaxArmor), MaxHealth) - Armor = MaxArmor * (0.5 + Health / MaxHealth * 0.5) + local Health = math.min(OldHealth + (30 / MaxArmor), MaxHealth) + local Armor = MaxArmor * (0.5 + Health / MaxHealth * 0.5) Entity.ACF.Health = Health Entity.ACF.Armour = Armor + if Entity.ACF_OnRepaired then + Entity:ACF_OnRepaired(OldArmor, OldHealth, Armor, Health) + end + Entity:EmitSound("ambient/energy/NewSpark0" .. math.random(3, 5) .. ".wav", true, true) TeslaSpark(Trace.HitPos, 1) end From 9a0a95bc7c95f0a534a0dde71d615bdc8a6866e7 Mon Sep 17 00:00:00 2001 From: shadow7483147 Date: Fri, 21 Aug 2020 03:49:30 -0500 Subject: [PATCH 108/279] Add files via upload --- lua/entities/acf_debris/cl_init.lua | 10 ++++++++++ lua/entities/acf_debris/init.lua | 16 ++-------------- lua/entities/acf_debris/shared.lua | 3 ++- 3 files changed, 14 insertions(+), 15 deletions(-) create mode 100644 lua/entities/acf_debris/cl_init.lua diff --git a/lua/entities/acf_debris/cl_init.lua b/lua/entities/acf_debris/cl_init.lua new file mode 100644 index 000000000..ad483b0bf --- /dev/null +++ b/lua/entities/acf_debris/cl_init.lua @@ -0,0 +1,10 @@ +include("shared.lua") + +function ENT:Initialize() + self:SetNoDraw(true) + CreateParticleSystem(self, "burning_gib_01", PATTACH_ABSORIGIN_FOLLOW) +end + +function ENT:OnRemove() + self:StopAndDestroyParticles() +end \ No newline at end of file diff --git a/lua/entities/acf_debris/init.lua b/lua/entities/acf_debris/init.lua index 333c4a1c0..f8b3e22b1 100644 --- a/lua/entities/acf_debris/init.lua +++ b/lua/entities/acf_debris/init.lua @@ -3,19 +3,7 @@ AddCSLuaFile("shared.lua") include("shared.lua") function ENT:Initialize() + self:SetModel("models/hunter/plates/plate.mdl") self:PhysicsInit(SOLID_VPHYSICS) - self:SetMoveType(MOVETYPE_VPHYSICS) - self:SetCollisionGroup(COLLISION_GROUP_WORLD) - - local PhysObj = self:GetPhysicsObject() - - if IsValid(PhysObj) then - PhysObj:Wake() - end - - timer.Simple(30, function() - if IsValid(self) then - self:Remove() - end - end) + self:SetCollisionGroup(COLLISION_GROUP_DEBRIS) end diff --git a/lua/entities/acf_debris/shared.lua b/lua/entities/acf_debris/shared.lua index 41e8551c7..765929fdf 100644 --- a/lua/entities/acf_debris/shared.lua +++ b/lua/entities/acf_debris/shared.lua @@ -1,3 +1,4 @@ DEFINE_BASECLASS("base_anim") -ENT.PrintName = "Debris" \ No newline at end of file +ENT.PrintName = "Fireball" +ENT.RenderGroup = RENDERGROUP_OTHER \ No newline at end of file From e8d3ded68293d6e2ad79fe606ec01104092b6767 Mon Sep 17 00:00:00 2001 From: shadow7483147 Date: Fri, 21 Aug 2020 03:51:04 -0500 Subject: [PATCH 109/279] Add files via upload --- lua/acf/server/damage.lua | 149 +++++++++++++++++++++++++------------- 1 file changed, 97 insertions(+), 52 deletions(-) diff --git a/lua/acf/server/damage.lua b/lua/acf/server/damage.lua index 572aecc12..21b9e5022 100644 --- a/lua/acf/server/damage.lua +++ b/lua/acf/server/damage.lua @@ -11,6 +11,8 @@ local ValidDebris = ACF.ValidDebris local ChildDebris = ACF.ChildDebris local DragDiv = ACF.DragDiv local GlobalFilter = ACF.GlobalFilter +-- Net Messages --------------------------------- +util.AddNetworkString("ACF_Debris") -- Local Funcs ---------------------------------- local function CalcDamage(Entity, Energy, FrArea, Angle) @@ -72,6 +74,7 @@ local function Shove(Target, Pos, Vec, KE) end ACF.KEShove = Shove + ------------------------------------------------- do @@ -290,8 +293,8 @@ do local Debris = ACF_HEKill(Ent, Table.Vec, PowerFraction, Origin) -- Make some debris - if IsValid(Debris) then - Filter[#Filter + 1] = Debris -- Filter that out too + for k,v in ipairs(Debris) do + if IsValid(v) then Filter[#Filter + 1] = v end -- Filter that out too end Loop = true -- Check for new targets since something died, maybe we'll find something new @@ -596,77 +599,119 @@ do end end end + ACF_KillChildProps = KillChildProps + -- Debris -- + + local function DebrisNetter(Entity, HitVector, Power, Gib, Ignite) + + local Mdl = Entity:GetModel() + local Mat = Entity:GetMaterial() + local Col = Entity:GetColor() + local ColR, ColG, ColB, ColA = Col.r, Col.g, Col.b, Col.a -- https://github.com/Facepunch/garrysmod-issues/issues/2407 + local Col = Color(ColR*0.5, ColG*0.5, ColB*0.5, ColA) -- how bout i do anyway + local Pos = Entity:GetPos() + local Ang = Entity:GetAngles() + local Mass = Entity:GetPhysicsObject():GetMass() or 1 + + net.Start("ACF_Debris") + net.WriteVector(HitVector) + net.WriteFloat(Power) + net.WriteFloat(Mass) + net.WriteString(Mdl) + net.WriteString(Mat) + net.WriteColor(Col) + net.WriteVector(Pos) + net.WriteAngle(Ang) + net.WriteBool(Gib) + net.WriteBool(Ignite) + net.SendPVS(Pos) + end + + local CreateFireballs = CreateConVar( + "acf_fireballs", 0, 0, -- Default 0, No flags + "Create serverside fireballs. Allows compatibility with mods like vFire, but is more taxing on server resources." + ) + + local FireballMultiplier = CreateConVar( + "acf_fireballmult", 1, 0, -- Default 0, No flags + "When fireballs are enabled, multiplies the amount created from a prop." + ) + + local function RandomPos( vecMin, vecMax ) + randomX = math.Rand(vecMin.x, vecMax.x) + randomY = math.Rand(vecMin.y, vecMax.y) + randomZ = math.Rand(vecMin.z, vecMax.z) + return Vector(randomX, randomY, randomZ) + end + function ACF_HEKill(Entity, HitVector, Energy, BlastPos) -- blast pos is an optional world-pos input for flinging away children props more realistically -- if it hasn't been processed yet, check for children if not Entity.ACF_Killed then KillChildProps(Entity, BlastPos or Entity:GetPos(), Energy) end - local Obj = Entity:GetPhysicsObject() - local Mass = IsValid(Obj) and Obj:GetMass() or 50 + local DebrisTable = {} + local Radius = Entity:BoundingRadius() - constraint.RemoveAll(Entity) - Entity:Remove() + --if Radius < ACF.DebrisScale then constraint.RemoveAll(Entity) Entity:Remove() else -- undersize? just delete it and move on. - if Entity:BoundingRadius() < ACF.DebrisScale then return nil end + local Power = Energy + DebrisNetter(Entity, HitVector, Power, false, true) - local Debris = ents.Create("acf_debris") - Debris:SetModel(Entity:GetModel()) - Debris:SetAngles(Entity:GetAngles()) - Debris:SetPos(Entity:GetPos()) - Debris:SetMaterial("models/props_wasteland/metal_tram001a") - Debris:Spawn() - Debris:Activate() + if CreateFireballs:GetInt() > 0 then - local Phys = Debris:GetPhysicsObject() - if IsValid(Phys) then - Phys:SetMass(math.Clamp(Mass,5,50000)) - Phys:ApplyForceOffset(HitVector:GetNormalized() * Energy * 15, Debris:GetPos() + VectorRand() * 10) -- previously energy*350 - end + local Pos = Entity:GetPos() + local Ang = Entity:GetAngles() + local Min, Max = Entity:OBBMins(), Entity:OBBMaxs() - if math.random() < ACF.DebrisIgniteChance then - Debris:Ignite(math.Rand(5, 45), 0) - end + local FireballCount = math.Clamp(Radius*0.1, 1, math.max(FireballMultiplier:GetFloat(), 1)) + print(FireballCount) + for i = 1, FireballCount do -- should we base this on prop volume? + + local Fireball = ents.Create("acf_debris") + if IsValid(Fireball) then -- we probably hit edict limit, stop looping + local RandomBox = RandomPos(Min, Max) + RandomBox:Rotate(Ang) + Fireball:SetPos(Pos + RandomBox) + Fireball:Spawn() + + local FireLifetime = math.Rand(5,15) -- fireball lifetime + Fireball:Ignite(FireLifetime) + timer.Simple(FireLifetime, function() if IsValid(Fireball) then Fireball:Remove() end end) -- check validity on last + + local Phys = Fireball:GetPhysicsObject() + if IsValid(Phys) then Phys:ApplyForceOffset(HitVector:GetNormalized() * Power * 15, Fireball:GetPos() + VectorRand() * 10) end + + table.insert(DebrisTable,Fireball) + end + + end + + end + + constraint.RemoveAll(Entity) + Entity:Remove() + + --end + return DebrisTable - return Debris end function ACF_APKill(Entity, HitVector, Power) - KillChildProps(Entity, Entity:GetPos(), Power) -- kill the children of this ent, instead of disappearing them from removing parent - local Obj = Entity:GetPhysicsObject() - local Mass = 25 + local Radius = Entity:BoundingRadius() - if IsValid(Obj) then Mass = Obj:GetMass() end + --if Radius > ACF.DebrisScale then DebrisNetter(Entity, HitVector, Power, true, false) end + -- Entity, HitNormal, Number, ShouldGib, ShouldIgnite + DebrisNetter(Entity, HitVector, Power, true, false) + -- Entity, HitNormal, Number, ShouldGib, ShouldIgnite constraint.RemoveAll(Entity) Entity:Remove() - if Entity:BoundingRadius() < ACF.DebrisScale then return end - - local Debris = ents.Create("acf_debris") - Debris:SetModel(Entity:GetModel()) - Debris:SetAngles(Entity:GetAngles()) - Debris:SetPos(Entity:GetPos()) - Debris:SetMaterial(Entity:GetMaterial()) - Debris:SetColor(Color(120, 120, 120, 255)) - Debris:Spawn() - Debris:Activate() - - local Phys = Debris:GetPhysicsObject() - if IsValid(Phys) then - Phys:SetMass(math.Clamp(Mass,5,50000)) - Phys:ApplyForceOffset(HitVector:GetNormalized() * Power * 350, Debris:GetPos() + VectorRand() * 20) - end - - local BreakEffect = EffectData() - BreakEffect:SetOrigin(Entity:GetPos()) - BreakEffect:SetScale(20) - util.Effect("WheelDust", BreakEffect) - - return Debris end + end do -- Round Impact -------------------------- @@ -717,8 +762,8 @@ do end if HitRes.Kill then - local Debris = ACF_APKill( Target , (Bullet.Flight):GetNormalized() , Energy.Kinetic ) - table.insert( Bullet.Filter , Debris ) + ACF_APKill( Target , (Bullet.Flight):GetNormalized() , Energy.Kinetic ) + --table.insert( Bullet.Filter , Debris ) end HitRes.Ricochet = false From 5eeae4ae8be107724a14650a14422e744c382eae Mon Sep 17 00:00:00 2001 From: shadow7483147 Date: Fri, 21 Aug 2020 03:51:21 -0500 Subject: [PATCH 110/279] Add files via upload --- lua/acf/client/cl_damage.lua | 160 +++++++++++++++++++++++++++++++++++ 1 file changed, 160 insertions(+) diff --git a/lua/acf/client/cl_damage.lua b/lua/acf/client/cl_damage.lua index 81bb69f01..b86dc72ac 100644 --- a/lua/acf/client/cl_damage.lua +++ b/lua/acf/client/cl_damage.lua @@ -1,3 +1,8 @@ +local RandFloat = math.Rand +local RandInt = math.random +local Clamp = math.Clamp +local MathMax = math.max + local Damaged = { CreateMaterial("ACF_Damaged1", "VertexLitGeneric", { ["$basetexture"] = "damaged/damaged1" @@ -68,3 +73,158 @@ net.Receive("ACF_RenderDamage", function() end end) +-- Debris & Burning Debris Effects -- + +local CreateFireballs = GetConVar("acf_fireballs") +game.AddParticles("particles/fire_01.pcf") +PrecacheParticleSystem("burning_gib_01") +PrecacheParticleSystem("env_fire_small_smoke") +PrecacheParticleSystem("smoke_gib_01") +PrecacheParticleSystem("smoke_exhaust_01a") +PrecacheParticleSystem("smoke_small_01b") +PrecacheParticleSystem("embers_medium_01") + +local function Particle(Entity, pEffect) + return CreateParticleSystem(Entity, pEffect, PATTACH_ABSORIGIN_FOLLOW) +end + +local CollisionTable = { -- No longer used! Doesn't seem to have an effect on anything. + COLLISION_GROUP_WORLD, -- in case 0 + COLLISION_GROUP_WORLD, + COLLISION_GROUP_DEBRIS, + COLLISION_GROUP_PUSHAWAY +} +local DebrisMasterCVar = CreateClientConVar("acf_debris", "1", true, false, + "Toggles ACF Debris." +) +local CollisionCVar = CreateClientConVar("acf_debris_collision", "0", true, false, + "Toggles whether debris created by ACF collides with objects. Disabling can prevent certain types of spam-induced lag & crashes." +) +local GibCVar = CreateClientConVar("acf_debris_gibmultiplier", "1", true, false, + "The amount of gibs spawned when created by ACF debris." +) +local GibSizeCVar = CreateClientConVar("acf_debris_gibsize", "1", true, false, + "The size of the gibs created by ACF debris." +) +local CVarGibLife = CreateClientConVar("acf_debris_giblifetime", "60", true, false, + "How long a gib will live in the world before fading. Default 30 to 60 seconds." +) +local CVarDebrisLife = CreateClientConVar("acf_debris_lifetime", "60", true, false, + "How long solid debris will live in the world before fading. Default 30 to 60 seconds." +) + +local function RandomPos( vecMin, vecMax ) + randomX = RandFloat(vecMin.x, vecMax.x) + randomY = RandFloat(vecMin.y, vecMax.y) + randomZ = RandFloat(vecMin.z, vecMax.z) + return Vector(randomX, randomY, randomZ) +end + +local function FadeAway( Ent ) -- local function Entity:FadeAway() is incorrect syntax????????? Am I referencing a hook somehow? + if not IsValid(Ent) then return end + Ent:SetRenderMode(RENDERMODE_TRANSCOLOR) + Ent:SetRenderFX(kRenderFxFadeSlow) -- interestingly, not synced to CurTime(). + local Smk, Emb = Ent.ACFSmokeParticle, Ent.ACFEmberParticle + if Smk then Smk:StopEmission() end + if Emb then Emb:StopEmission() end + timer.Simple(5, function() Ent:StopAndDestroyParticles() Ent:Remove() end) +end + +local function IgniteCL( Ent, Lifetime, Gib ) -- Lifetime describes fire life, smoke lasts until the entity is removed. + if Gib then + Particle(Ent, "burning_gib_01") + timer.Simple(Lifetime * 0.2, function() + if IsValid(Ent) then + Ent:StopParticlesNamed("burning_gib_01") + end + end) + else + Particle(Ent, "env_fire_small_smoke") + Ent.ACFSmokeParticle = Particle(Ent, "smoke_small_01b") + timer.Simple(Lifetime * 0.4, function() + if IsValid(Ent) then + Ent:StopParticlesNamed("env_fire_small_smoke") + end + end) + end +end + +net.Receive("ACF_Debris", function() + + if DebrisMasterCVar:GetInt() < 1 then return end + + local HitVec = net.ReadVector() + local Power = net.ReadFloat() + local Mass = net.ReadFloat() + local Mdl = net.ReadString() + local Mat = net.ReadString() + local Col = net.ReadColor() + local Pos = net.ReadVector() + local Ang = net.ReadAngle() + local Radius = net.ReadUInt(8) + local WillGib = net.ReadBool() + local WillIgnite = net.ReadBool() + + local Min, Max = Vector(), Vector() + + local Debris = ents.CreateClientProp(Mdl) + Debris:SetPos(Pos) + Debris:SetAngles(Ang) + Debris:SetColor(Col) + if Mat then Debris:SetMaterial(Mat) end + if CollisionCVar:GetInt() < 1 then Debris:SetCollisionGroup(COLLISION_GROUP_WORLD) end + Debris:Spawn() + local DebrisLifetime = RandFloat(0.5, 1) * MathMax(CVarDebrisLife:GetFloat(), 1) + timer.Simple(DebrisLifetime, function() FadeAway(Debris) end) + + if IsValid(Debris) then + + Min, Max = Debris:OBBMins(), Debris:OBBMaxs() --for gibs + + Debris.ACFEmberParticle = Particle(Debris, "embers_medium_01") + if WillIgnite and RandFloat(0, 1) * 0.2 < ACF.DebrisIgniteChance then + IgniteCL(Debris, DebrisLifetime, false) + else + Debris.ACFSmokeParticle = Particle(Debris, "smoke_exhaust_01a") + end + -- Debris (not gibs) has a 5 times higher chance of igniting since we're already saying that the debris will ignite. + + local Phys = Debris:GetPhysicsObject() + if IsValid(Phys) then + Phys:SetMass(Mass*0.1) + Phys:ApplyForceOffset(HitVec:GetNormalized() * Power * 70, Debris:GetPos() + VectorRand() * 20) + end + + end + + if WillGib and GibCVar:GetFloat() > 0 then + local GibCount = Clamp(Radius * 0.05, 1, MathMax(20 * GibCVar:GetFloat(), 1)) + for _ = 1, GibCount do -- should we base this on prop volume? + + local Gib = ents.CreateClientProp("models/gibs/metal_gib" .. RandInt(1,5) .. ".mdl") + if not IsValid(Gib) then break end -- we probably hit edict limit, stop looping + local RandomBox = RandomPos(Min, Max) + RandomBox:Rotate(Ang) + Gib:SetPos(Pos + RandomBox) + Gib:SetAngles(AngleRand(-180,180)) + Gib:SetModelScale(Clamp(Radius * 0.01 * GibSizeCVar:GetFloat(), 1, 20)) + Gib.ACFSmokeParticle = Particle(Gib, "smoke_gib_01") + Gib:Spawn() + Gib:Activate() + + local GibLifetime = RandFloat(0.5, 1) * MathMax(CVarGibLife:GetFloat(), 1) + timer.Simple(GibLifetime, function() FadeAway(Gib) end) + if RandFloat(0,1) < ACF.DebrisIgniteChance then IgniteCL(Gib, GibLifetime, true) end -- Gibs always ignite but still follow IgniteChance + + local GibPhys = Gib:GetPhysicsObject() + GibPhys:ApplyForceOffset(HitVec:GetNormalized() * Power, GibPhys:GetPos() + VectorRand() * 20) + + end + end + + local BreakEffect = EffectData() + BreakEffect:SetOrigin(Pos) -- TODO: Change this to the hit vector, but we need to redefine HitVec as HitNorm + BreakEffect:SetScale(20) + util.Effect("cball_explode", BreakEffect) + +end) \ No newline at end of file From da3a75426796c7f4995b2ef586e56628cb5f7fb0 Mon Sep 17 00:00:00 2001 From: shadow7483147 Date: Fri, 21 Aug 2020 04:44:54 -0500 Subject: [PATCH 111/279] remove fire particle on acf_debris fireball its already being ignited --- lua/entities/acf_debris/cl_init.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/lua/entities/acf_debris/cl_init.lua b/lua/entities/acf_debris/cl_init.lua index ad483b0bf..ec044d1f8 100644 --- a/lua/entities/acf_debris/cl_init.lua +++ b/lua/entities/acf_debris/cl_init.lua @@ -2,7 +2,6 @@ include("shared.lua") function ENT:Initialize() self:SetNoDraw(true) - CreateParticleSystem(self, "burning_gib_01", PATTACH_ABSORIGIN_FOLLOW) end function ENT:OnRemove() From 33fb3446a1f6c218fd269801fd33fe4193331870 Mon Sep 17 00:00:00 2001 From: shadow7483147 Date: Fri, 21 Aug 2020 04:48:13 -0500 Subject: [PATCH 112/279] add cvar to disable debris on serverside also make the linter happy --- lua/acf/server/damage.lua | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/lua/acf/server/damage.lua b/lua/acf/server/damage.lua index 21b9e5022..f74425ba4 100644 --- a/lua/acf/server/damage.lua +++ b/lua/acf/server/damage.lua @@ -293,7 +293,7 @@ do local Debris = ACF_HEKill(Ent, Table.Vec, PowerFraction, Origin) -- Make some debris - for k,v in ipairs(Debris) do + for _,v in ipairs(Debris) do if IsValid(v) then Filter[#Filter + 1] = v end -- Filter that out too end @@ -603,14 +603,21 @@ do ACF_KillChildProps = KillChildProps -- Debris -- + + local CVarDisableDebris = CreateConVar( + "acf_debris_sv", 1, 0, -- Default 1, No flags + "Setting this to 0 disables debris from being sent to clients. Reduces server network overhead." + ) local function DebrisNetter(Entity, HitVector, Power, Gib, Ignite) + + if CVarDisableDebris:GetInt() < 1 then return end local Mdl = Entity:GetModel() local Mat = Entity:GetMaterial() local Col = Entity:GetColor() local ColR, ColG, ColB, ColA = Col.r, Col.g, Col.b, Col.a -- https://github.com/Facepunch/garrysmod-issues/issues/2407 - local Col = Color(ColR*0.5, ColG*0.5, ColB*0.5, ColA) -- how bout i do anyway + local ColN = Color(ColR *0.5, ColG *0.5, ColB *0.5, ColA) -- how bout i do anyway local Pos = Entity:GetPos() local Ang = Entity:GetAngles() local Mass = Entity:GetPhysicsObject():GetMass() or 1 @@ -621,11 +628,11 @@ do net.WriteFloat(Mass) net.WriteString(Mdl) net.WriteString(Mat) - net.WriteColor(Col) + net.WriteColor(ColN) net.WriteVector(Pos) net.WriteAngle(Ang) - net.WriteBool(Gib) - net.WriteBool(Ignite) + net.WriteFloat(Gib) + net.WriteFloat(Ignite) net.SendPVS(Pos) end @@ -635,7 +642,7 @@ do ) local FireballMultiplier = CreateConVar( - "acf_fireballmult", 1, 0, -- Default 0, No flags + "acf_fireballmult", 1, 0, -- Default 1, No flags "When fireballs are enabled, multiplies the amount created from a prop." ) @@ -656,7 +663,7 @@ do --if Radius < ACF.DebrisScale then constraint.RemoveAll(Entity) Entity:Remove() else -- undersize? just delete it and move on. local Power = Energy - DebrisNetter(Entity, HitVector, Power, false, true) + DebrisNetter(Entity, HitVector, Power, 0, 1) if CreateFireballs:GetInt() > 0 then @@ -664,9 +671,8 @@ do local Ang = Entity:GetAngles() local Min, Max = Entity:OBBMins(), Entity:OBBMaxs() - local FireballCount = math.Clamp(Radius*0.1, 1, math.max(FireballMultiplier:GetFloat(), 1)) - print(FireballCount) - for i = 1, FireballCount do -- should we base this on prop volume? + local FireballCount = math.Clamp(Radius*0.01, 1, math.max(10 * FireballMultiplier:GetFloat(), 1)) + for _ = 1, FireballCount do -- should we base this on prop volume? local Fireball = ents.Create("acf_debris") if IsValid(Fireball) then -- we probably hit edict limit, stop looping @@ -700,11 +706,9 @@ do function ACF_APKill(Entity, HitVector, Power) KillChildProps(Entity, Entity:GetPos(), Power) -- kill the children of this ent, instead of disappearing them from removing parent - local Radius = Entity:BoundingRadius() - --if Radius > ACF.DebrisScale then DebrisNetter(Entity, HitVector, Power, true, false) end -- Entity, HitNormal, Number, ShouldGib, ShouldIgnite - DebrisNetter(Entity, HitVector, Power, true, false) + DebrisNetter(Entity, HitVector, Power, 1, 0) -- Entity, HitNormal, Number, ShouldGib, ShouldIgnite constraint.RemoveAll(Entity) From 796f24fbfec3222fe9dbcc4a2918289551e67fda Mon Sep 17 00:00:00 2001 From: shadow7483147 Date: Fri, 21 Aug 2020 04:49:02 -0500 Subject: [PATCH 113/279] im gonna smack the fuccin linter jkjkjk --- lua/acf/client/cl_damage.lua | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/lua/acf/client/cl_damage.lua b/lua/acf/client/cl_damage.lua index b86dc72ac..94c34aa81 100644 --- a/lua/acf/client/cl_damage.lua +++ b/lua/acf/client/cl_damage.lua @@ -75,7 +75,6 @@ end) -- Debris & Burning Debris Effects -- -local CreateFireballs = GetConVar("acf_fireballs") game.AddParticles("particles/fire_01.pcf") PrecacheParticleSystem("burning_gib_01") PrecacheParticleSystem("env_fire_small_smoke") @@ -88,12 +87,6 @@ local function Particle(Entity, pEffect) return CreateParticleSystem(Entity, pEffect, PATTACH_ABSORIGIN_FOLLOW) end -local CollisionTable = { -- No longer used! Doesn't seem to have an effect on anything. - COLLISION_GROUP_WORLD, -- in case 0 - COLLISION_GROUP_WORLD, - COLLISION_GROUP_DEBRIS, - COLLISION_GROUP_PUSHAWAY -} local DebrisMasterCVar = CreateClientConVar("acf_debris", "1", true, false, "Toggles ACF Debris." ) @@ -149,7 +142,9 @@ local function IgniteCL( Ent, Lifetime, Gib ) -- Lifetime describes fire life, s end end -net.Receive("ACF_Debris", function() +net.Receive("ACF_Debris", function(len) + + print(len) if DebrisMasterCVar:GetInt() < 1 then return end @@ -162,8 +157,8 @@ net.Receive("ACF_Debris", function() local Pos = net.ReadVector() local Ang = net.ReadAngle() local Radius = net.ReadUInt(8) - local WillGib = net.ReadBool() - local WillIgnite = net.ReadBool() + local WillGib = net.ReadFloat() + local WillIgnite = net.ReadFloat() local Min, Max = Vector(), Vector() @@ -182,7 +177,7 @@ net.Receive("ACF_Debris", function() Min, Max = Debris:OBBMins(), Debris:OBBMaxs() --for gibs Debris.ACFEmberParticle = Particle(Debris, "embers_medium_01") - if WillIgnite and RandFloat(0, 1) * 0.2 < ACF.DebrisIgniteChance then + if WillIgnite > 0 and RandFloat(0, 1) * 0.2 < ACF.DebrisIgniteChance then IgniteCL(Debris, DebrisLifetime, false) else Debris.ACFSmokeParticle = Particle(Debris, "smoke_exhaust_01a") @@ -191,13 +186,13 @@ net.Receive("ACF_Debris", function() local Phys = Debris:GetPhysicsObject() if IsValid(Phys) then - Phys:SetMass(Mass*0.1) + Phys:SetMass(Mass * 0.1) Phys:ApplyForceOffset(HitVec:GetNormalized() * Power * 70, Debris:GetPos() + VectorRand() * 20) end end - if WillGib and GibCVar:GetFloat() > 0 then + if WillGib > 0 and GibCVar:GetFloat() > 0 then local GibCount = Clamp(Radius * 0.05, 1, MathMax(20 * GibCVar:GetFloat(), 1)) for _ = 1, GibCount do -- should we base this on prop volume? From 4f99716d6a96d7a84fdeb314d4efae6f02c979b0 Mon Sep 17 00:00:00 2001 From: shadow7483147 Date: Fri, 21 Aug 2020 04:51:30 -0500 Subject: [PATCH 114/279] ok dad --- lua/acf/server/damage.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lua/acf/server/damage.lua b/lua/acf/server/damage.lua index f74425ba4..2450caaa7 100644 --- a/lua/acf/server/damage.lua +++ b/lua/acf/server/damage.lua @@ -603,21 +603,21 @@ do ACF_KillChildProps = KillChildProps -- Debris -- - + local CVarDisableDebris = CreateConVar( "acf_debris_sv", 1, 0, -- Default 1, No flags "Setting this to 0 disables debris from being sent to clients. Reduces server network overhead." ) local function DebrisNetter(Entity, HitVector, Power, Gib, Ignite) - + if CVarDisableDebris:GetInt() < 1 then return end local Mdl = Entity:GetModel() local Mat = Entity:GetMaterial() local Col = Entity:GetColor() local ColR, ColG, ColB, ColA = Col.r, Col.g, Col.b, Col.a -- https://github.com/Facepunch/garrysmod-issues/issues/2407 - local ColN = Color(ColR *0.5, ColG *0.5, ColB *0.5, ColA) -- how bout i do anyway + local ColN = Color(ColR * 0.5, ColG * 0.5, ColB * 0.5, ColA) -- how bout i do anyway local Pos = Entity:GetPos() local Ang = Entity:GetAngles() local Mass = Entity:GetPhysicsObject():GetMass() or 1 @@ -671,7 +671,7 @@ do local Ang = Entity:GetAngles() local Min, Max = Entity:OBBMins(), Entity:OBBMaxs() - local FireballCount = math.Clamp(Radius*0.01, 1, math.max(10 * FireballMultiplier:GetFloat(), 1)) + local FireballCount = math.Clamp(Radius * 0.01, 1, math.max(10 * FireballMultiplier:GetFloat(), 1)) for _ = 1, FireballCount do -- should we base this on prop volume? local Fireball = ents.Create("acf_debris") From c48ff75062f5d152505fd5964351ed381819c9e5 Mon Sep 17 00:00:00 2001 From: shadow7483147 Date: Fri, 21 Aug 2020 04:53:35 -0500 Subject: [PATCH 115/279] whoops left in the nessage length print its gone now --- lua/acf/client/cl_damage.lua | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lua/acf/client/cl_damage.lua b/lua/acf/client/cl_damage.lua index 94c34aa81..badb049bf 100644 --- a/lua/acf/client/cl_damage.lua +++ b/lua/acf/client/cl_damage.lua @@ -142,9 +142,7 @@ local function IgniteCL( Ent, Lifetime, Gib ) -- Lifetime describes fire life, s end end -net.Receive("ACF_Debris", function(len) - - print(len) +net.Receive("ACF_Debris", function() if DebrisMasterCVar:GetInt() < 1 then return end From 4052e9e7ae781488fb19b600abcb713127186b58 Mon Sep 17 00:00:00 2001 From: shadow7483147 Date: Fri, 21 Aug 2020 05:58:51 -0500 Subject: [PATCH 116/279] rename "acf_debris_sv" to "acf_debris" for server --- lua/acf/server/damage.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lua/acf/server/damage.lua b/lua/acf/server/damage.lua index 2450caaa7..ccde9b4cd 100644 --- a/lua/acf/server/damage.lua +++ b/lua/acf/server/damage.lua @@ -617,7 +617,7 @@ do local Mat = Entity:GetMaterial() local Col = Entity:GetColor() local ColR, ColG, ColB, ColA = Col.r, Col.g, Col.b, Col.a -- https://github.com/Facepunch/garrysmod-issues/issues/2407 - local ColN = Color(ColR * 0.5, ColG * 0.5, ColB * 0.5, ColA) -- how bout i do anyway + Col = Color(ColR * 0.5, ColG * 0.5, ColB * 0.5, ColA) -- how bout i do anyway local Pos = Entity:GetPos() local Ang = Entity:GetAngles() local Mass = Entity:GetPhysicsObject():GetMass() or 1 @@ -628,7 +628,7 @@ do net.WriteFloat(Mass) net.WriteString(Mdl) net.WriteString(Mat) - net.WriteColor(ColN) + net.WriteColor(Col) net.WriteVector(Pos) net.WriteAngle(Ang) net.WriteFloat(Gib) @@ -822,4 +822,4 @@ do return HitRes end end -end +end \ No newline at end of file From ae85277ee34c5abfee0a01459ae9337349fa3224 Mon Sep 17 00:00:00 2001 From: shadow7483147 Date: Fri, 21 Aug 2020 06:00:03 -0500 Subject: [PATCH 117/279] remove stale Radius variable --- lua/acf/client/cl_damage.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lua/acf/client/cl_damage.lua b/lua/acf/client/cl_damage.lua index badb049bf..ec4cedab7 100644 --- a/lua/acf/client/cl_damage.lua +++ b/lua/acf/client/cl_damage.lua @@ -154,11 +154,11 @@ net.Receive("ACF_Debris", function() local Col = net.ReadColor() local Pos = net.ReadVector() local Ang = net.ReadAngle() - local Radius = net.ReadUInt(8) local WillGib = net.ReadFloat() local WillIgnite = net.ReadFloat() local Min, Max = Vector(), Vector() + local Radius = 1 local Debris = ents.CreateClientProp(Mdl) Debris:SetPos(Pos) @@ -173,6 +173,7 @@ net.Receive("ACF_Debris", function() if IsValid(Debris) then Min, Max = Debris:OBBMins(), Debris:OBBMaxs() --for gibs + Radius = Debris:BoundingRadius() Debris.ACFEmberParticle = Particle(Debris, "embers_medium_01") if WillIgnite > 0 and RandFloat(0, 1) * 0.2 < ACF.DebrisIgniteChance then From 8ca1754219f3fd3f796012dd68f4d1ccaf9968ec Mon Sep 17 00:00:00 2001 From: shadow7483147 Date: Fri, 21 Aug 2020 06:00:44 -0500 Subject: [PATCH 118/279] Add files via upload acf_debris but actually saved on notepad this time --- lua/acf/server/damage.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/acf/server/damage.lua b/lua/acf/server/damage.lua index ccde9b4cd..7e580db32 100644 --- a/lua/acf/server/damage.lua +++ b/lua/acf/server/damage.lua @@ -605,7 +605,7 @@ do -- Debris -- local CVarDisableDebris = CreateConVar( - "acf_debris_sv", 1, 0, -- Default 1, No flags + "acf_debris", 1, 0, -- Default 1, No flags "Setting this to 0 disables debris from being sent to clients. Reduces server network overhead." ) From f5a491fba7db6f06400638e3c71b852c96370487 Mon Sep 17 00:00:00 2001 From: shadow7483147 Date: Fri, 21 Aug 2020 17:42:16 -0500 Subject: [PATCH 119/279] match current Dev branch, 8-21-20 17:41 (#1) --- lua/entities/acf_gun/init.lua | 6 ++--- .../core/custom/acffunctions.lua | 15 +++++++++++ .../core/custom/cl_acfdescriptions.lua | 1 + lua/starfall/libs_sv/acffunctions.lua | 25 +++++++++++++++++++ 4 files changed, 44 insertions(+), 3 deletions(-) diff --git a/lua/entities/acf_gun/init.lua b/lua/entities/acf_gun/init.lua index 4fdb8ab48..790f23543 100644 --- a/lua/entities/acf_gun/init.lua +++ b/lua/entities/acf_gun/init.lua @@ -245,7 +245,7 @@ do -- Metamethods -------------------------------- gmod_wire_expression2 = true, gmod_wire_joystick_multi = true, gmod_wire_pod = function(_, Input) - if Input.Pod then + if IsValid(Input.Pod) then return Input.Pod:GetDriver() end end, @@ -267,7 +267,7 @@ do -- Metamethods -------------------------------- WireTable.gmod_wire_joystick_multi = WireTable.gmod_wire_pod WireTable.gmod_wire_expression2 = function(This, Input, Checked) for _, V in pairs(Input.Inputs) do - if V.Src and not Checked[V.Src] and WireTable[V.Src:GetClass()] then + if IsValid(V.Src) and not Checked[V.Src] and WireTable[V.Src:GetClass()] then Checked[V.Src] = true -- We don't want to start an infinite loop return FindUser(This, V.Src, Checked) @@ -276,7 +276,7 @@ do -- Metamethods -------------------------------- end function ENT:GetUser(Input) - if not Input then return self.Owner end + if not IsValid(Input) then return self.Owner end local User = FindUser(self, Input) diff --git a/lua/entities/gmod_wire_expression2/core/custom/acffunctions.lua b/lua/entities/gmod_wire_expression2/core/custom/acffunctions.lua index 4b46efaf2..a89d6cc23 100644 --- a/lua/entities/gmod_wire_expression2/core/custom/acffunctions.lua +++ b/lua/entities/gmod_wire_expression2/core/custom/acffunctions.lua @@ -1001,6 +1001,21 @@ e2function number entity:acfDragCoef() return this.BulletData.DragCoef / ACF.DragDiv end +-- Returns the fin multiplier of the missile/bomb +e2function number entity:acfFinMul() + if not IsACFEntity(this) then return 0 end + if RestrictInfo(self, this) then return 0 end + if not this.BulletData then return 0 end + if not this.BulletData.Id then return 0 end + + local GunData = ACF.Weapons.Guns[this.BulletData.Id] + + if not GunData then return 0 end + if not GunData.round then return 0 end + + return GunData.round.finmul or 0 +end + -- Returns the number of projectiles in a flechette round e2function number entity:acfFLSpikes() if not IsACFEntity(this) then return 0 end diff --git a/lua/entities/gmod_wire_expression2/core/custom/cl_acfdescriptions.lua b/lua/entities/gmod_wire_expression2/core/custom/cl_acfdescriptions.lua index f42b5f7e3..d211bb41b 100644 --- a/lua/entities/gmod_wire_expression2/core/custom/cl_acfdescriptions.lua +++ b/lua/entities/gmod_wire_expression2/core/custom/cl_acfdescriptions.lua @@ -102,6 +102,7 @@ E2Desc["acfCaliber(e:)"] = "Returns the caliber of an ACF entity." E2Desc["acfMuzzleVel(e:)"] = "Returns the muzzle velocity of the ammo in an ACF entity." E2Desc["acfProjectileMass(e:)"] = "Returns the mass of the projectile in an ACF entity." E2Desc["acfDragCoef(e:)"] = "Returns the drag coefficient of the projectile in an ACF entity." +E2Desc["acfFinMul(e:)"] = "Returns the fin multiplier of the projectile in an ACF entity" E2Desc["acfFLSpikes(e:)"] = "Returns the number of projectiles in a flechette round." E2Desc["acfFLSpikeRadius(e:)"] = "Returns the radius (in mm) of the spikes in a flechette round." E2Desc["acfFLSpikeMass(e:)"] = "Returns the mass of a single spike in a FL round in a crate or gun." diff --git a/lua/starfall/libs_sv/acffunctions.lua b/lua/starfall/libs_sv/acffunctions.lua index fa74402b4..6b3e278f0 100644 --- a/lua/starfall/libs_sv/acffunctions.lua +++ b/lua/starfall/libs_sv/acffunctions.lua @@ -48,6 +48,11 @@ local function isGun ( ent ) if ( ent:GetClass() == "acf_gun" ) then return true else return false end end +local function isRack ( ent ) + if not validPhysics( ent ) then return false end + if ( ent:GetClass() == "acf_rack" ) then return true else return false end +end + local function isAmmo ( ent ) if not validPhysics( ent ) then return false end if ( ent:GetClass() == "acf_ammo" ) then return true else return false end @@ -2101,6 +2106,26 @@ function ents_methods:acfDragCoef() return ( this.BulletData[ "DragCoef" ] or 0 ) / ACF.DragDiv end +--- Returns the fin multiplier of the ammo in a crate or launcher +-- @server +function ents_methods:acfFinMul() + checktype( self, ents_metatable ) + local this = unwrap( self ) + + if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + + if not ( isAmmo( this ) or isRack( this ) ) then return 0 end + if restrictInfo( this ) then return 0 end + if not this.BulletData.Id then return 0 end + + local GunData = ACF.Weapons.Guns[this.BulletData.Id] + + if not GunData then return 0 end + if not GunData.round then return 0 end + + return ( GunData.round.finmul or 0 ) +end + -- [ Armor Functions ] -- --- Returns the current health of an entity From de9422da519c9f714cf58309ae42b4b5d7b4a979 Mon Sep 17 00:00:00 2001 From: shadow7483147 Date: Sat, 22 Aug 2020 13:23:14 -0500 Subject: [PATCH 120/279] Match dev commit 38b503c (#2) * added E:acfFinMul functions for E2 and Starfall, and E:isRack() Starfall helper function * additional checks * Fixed error on NULL input entity - Fixed error related to a NULL input entity when attempting to get the user of an ACF weapon. * Fixed typo on armor mass limit - Fixed typo inside the mass entity modifier that was limiting armor mass to 5 tons instead of 50. Co-authored-by: Alexandre425 Co-authored-by: TwistedTail <8784231+TwistedTail@users.noreply.github.com> --- lua/weapons/gmod_tool/stools/acfarmorprop.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/weapons/gmod_tool/stools/acfarmorprop.lua b/lua/weapons/gmod_tool/stools/acfarmorprop.lua index dbf25d383..d1026e8e0 100644 --- a/lua/weapons/gmod_tool/stools/acfarmorprop.lua +++ b/lua/weapons/gmod_tool/stools/acfarmorprop.lua @@ -109,7 +109,7 @@ local function ApplySettings(_, Entity, Data) if Data.Mass then local PhysObj = Entity.ACF.PhysObj -- If it passed ACF_Check, then the PhysObj will always be valid - local Mass = math.Clamp(Data.Mass, 0.1, 5000) + local Mass = math.Clamp(Data.Mass, 0.1, 50000) PhysObj:SetMass(Mass) From f18c2ee32cedf73eaa4def2d133bbf0aaff46e25 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Tue, 1 Sep 2020 03:53:53 -0400 Subject: [PATCH 121/279] Fixed several conflicts - Fixed several conflict related problems due to missing bits of code. - Ported some changes to the new registration methods. --- lua/acf/base/sh_round_functions.lua | 4 +- lua/acf/shared/ammo_crates/crates.lua | 72 ++++++++++++++++++++++++ lua/acf/shared/ammo_types/ap.lua | 1 + lua/acf/shared/ammo_types/apcr.lua | 11 ++-- lua/acf/shared/ammo_types/apds.lua | 20 +++++-- lua/acf/shared/ammo_types/apfsds.lua | 18 ++++-- lua/acf/shared/ammo_types/aphe.lua | 1 + lua/acf/shared/ammo_types/fl.lua | 1 + lua/acf/shared/ammo_types/he.lua | 1 + lua/acf/shared/ammo_types/heat.lua | 1 + lua/acf/shared/ammo_types/heatfs.lua | 1 + lua/acf/shared/ammo_types/hp.lua | 1 + lua/acf/shared/ammo_types/refill.lua | 6 +- lua/acf/shared/ammo_types/smoke.lua | 1 + lua/acf/shared/engines/b4.lua | 8 +-- lua/acf/shared/engines/b6.lua | 8 +-- lua/acf/shared/engines/electric.lua | 6 +- lua/acf/shared/engines/i2.lua | 4 +- lua/acf/shared/engines/i3.lua | 12 ++-- lua/acf/shared/engines/i4.lua | 12 ++-- lua/acf/shared/engines/i5.lua | 8 +-- lua/acf/shared/engines/i6.lua | 12 ++-- lua/acf/shared/engines/radial.lua | 8 +-- lua/acf/shared/engines/rotary.lua | 6 +- lua/acf/shared/engines/single.lua | 6 +- lua/acf/shared/engines/special.lua | 22 ++++---- lua/acf/shared/engines/turbine.lua | 24 ++++---- lua/acf/shared/engines/v10.lua | 6 +- lua/acf/shared/engines/v12.lua | 14 ++--- lua/acf/shared/engines/v2.lua | 6 +- lua/acf/shared/engines/v4.lua | 4 +- lua/acf/shared/engines/v6.lua | 10 ++-- lua/acf/shared/engines/v8.lua | 12 ++-- lua/acf/shared/guns/autocannon.lua | 2 +- lua/acf/shared/guns/grenadelauncher.lua | 2 +- lua/acf/shared/guns/heavymachinegun.lua | 2 +- lua/acf/shared/guns/howitzer.lua | 2 +- lua/acf/shared/guns/machinegun.lua | 2 +- lua/acf/shared/guns/mortar.lua | 2 +- lua/acf/shared/guns/rotaryautocannon.lua | 2 +- lua/acf/shared/guns/semiauto.lua | 2 +- lua/acf/shared/guns/shortcannon.lua | 2 +- lua/entities/acf_ammo/init.lua | 4 +- lua/entities/acf_engine/init.lua | 26 ++++++--- lua/entities/acf_fueltank/init.lua | 61 ++++++++++++-------- lua/entities/acf_gearbox/init.lua | 20 ++++++- lua/entities/acf_gun/init.lua | 40 ++++++++++++- 47 files changed, 335 insertions(+), 161 deletions(-) diff --git a/lua/acf/base/sh_round_functions.lua b/lua/acf/base/sh_round_functions.lua index ff09c9294..054c7996a 100644 --- a/lua/acf/base/sh_round_functions.lua +++ b/lua/acf/base/sh_round_functions.lua @@ -43,8 +43,8 @@ function ACF.UpdateRoundSpecs(ToolData, Data, GUIData) Data.ProjLength = math.Round(Projectile, 2) - Data.Tracer Data.PropLength = math.Round(Propellant, 2) - Data.PropMass = Data.FrArea * (Data.PropLength * ACF.PDensity / 1000) --Volume of the case as a cylinder * Powder density converted from g to kg - Data.RoundVolume = Data.FrArea * (Data.ProjLength + Data.PropLength) + Data.PropMass = Data.FrArea * ACF.AmmoCaseScale ^ 2 * (Data.PropLength * ACF.PDensity * 0.001) --Volume of the case as a cylinder * Powder density converted from g to kg + Data.RoundVolume = Data.FrArea * ACF.AmmoCaseScale ^ 2 * (Data.ProjLength + Data.PropLength) GUIData.ProjVolume = Data.FrArea * Data.ProjLength end diff --git a/lua/acf/shared/ammo_crates/crates.lua b/lua/acf/shared/ammo_crates/crates.lua index c619fde22..337edbd26 100644 --- a/lua/acf/shared/ammo_crates/crates.lua +++ b/lua/acf/shared/ammo_crates/crates.lua @@ -3,6 +3,8 @@ ACF.RegisterCrate("AmmoSmall", { Model = "models/ammocrate_small.mdl", Mass = 10, Volume = 2198, + Size = Vector(20.44, 7.93, 13.77), + Offset = Vector(-0.36, -0.01, 7.01) }) ACF.RegisterCrate("AmmoMedCube", { @@ -10,6 +12,8 @@ ACF.RegisterCrate("AmmoMedCube", { Model = "models/ammocrate_medium_small.mdl", Mass = 80, Volume = 17769, + Size = Vector(26.27, 25.9, 26.3), + Offset = Vector(-0.03, 0.42, 13.1) }) ACF.RegisterCrate("AmmoMedium", { @@ -17,6 +21,8 @@ ACF.RegisterCrate("AmmoMedium", { Model = "models/ammocrate_medium.mdl", Mass = 150, Volume = 35105, + Size = Vector(51.9, 26.27, 25.9), + Offset = Vector(-0.12, 0.42, 13.1) }) ACF.RegisterCrate("AmmoLarge", { @@ -24,6 +30,8 @@ ACF.RegisterCrate("AmmoLarge", { Model = "models/ammocrate_large.mdl", Mass = 1000, Volume = 140503, + Size = Vector(52.17, 52.06, 51.92), + Offset = Vector(-0.05, -0.38, 26.06) }) ACF.RegisterCrate("Ammo1x1x8", { @@ -31,6 +39,8 @@ ACF.RegisterCrate("Ammo1x1x8", { Model = "models/ammocrates/ammo_1x1x8.mdl", Mass = 40, Volume = 10872, + Size = Vector(11.09, 89.15, 11.13), + Offset = Vector(0, -0.02, -0.12) }) ACF.RegisterCrate("Ammo1x1x6", { @@ -38,6 +48,8 @@ ACF.RegisterCrate("Ammo1x1x6", { Model = "models/ammocrates/ammo_1x1x6.mdl", Mass = 30, Volume = 8202, + Size = Vector(11.2, 66.51, 11.14), + Offset = Vector(0, 0.02, -0.14) }) ACF.RegisterCrate("Ammo1x1x4", { @@ -45,6 +57,8 @@ ACF.RegisterCrate("Ammo1x1x4", { Model = "models/ammocrates/ammo_1x1x4.mdl", Mass = 20, Volume = 5519, + Size = Vector(11.16, 45.06, 11.11), + Offset = Vector(0, 0.16, -0.17) }) ACF.RegisterCrate("Ammo1x1x2", { @@ -52,6 +66,8 @@ ACF.RegisterCrate("Ammo1x1x2", { Model = "models/ammocrates/ammo_1x1x2.mdl", Mass = 10, Volume = 2743, + Size = Vector(11.16, 22.43, 11.11), + Offset = Vector(0, 0.05, -0.17) }) ACF.RegisterCrate("Ammo2x2x1", { @@ -59,6 +75,8 @@ ACF.RegisterCrate("Ammo2x2x1", { Model = "models/ammocrates/ammocrate_2x2x1.mdl", Mass = 20, Volume = 3200, + Size = Vector(20.06, 8.06, 20.06), + Offset = Vector(-0.52, 0, 10.19) }) ACF.RegisterCrate("Ammo2x2x2", { @@ -66,6 +84,8 @@ ACF.RegisterCrate("Ammo2x2x2", { Model = "models/ammocrates/ammocrate_2x2x2.mdl", Mass = 40, Volume = 8000, + Size = Vector(20.06, 20.06, 20.06), + Offset = Vector(-0.09, 0.51, 10.51) }) ACF.RegisterCrate("Ammo2x2x4", { @@ -73,6 +93,8 @@ ACF.RegisterCrate("Ammo2x2x4", { Model = "models/ammocrates/ammocrate_2x2x4.mdl", Mass = 80, Volume = 18000, + Size = Vector(20.06, 45.06, 20.06), + Offset = Vector(-0.71, 0, 10.18) }) ACF.RegisterCrate("Ammo2x2x6", { @@ -80,6 +102,8 @@ ACF.RegisterCrate("Ammo2x2x6", { Model = "models/ammocrates/ammo_2x2x6.mdl", Mass = 120, Volume = 33179, + Size = Vector(22.45, 66.59, 22.33), + Offset = Vector(0, 0, -0.1) }) ACF.RegisterCrate("Ammo2x2x8", { @@ -87,6 +111,8 @@ ACF.RegisterCrate("Ammo2x2x8", { Model = "models/ammocrates/ammo_2x2x8.mdl", Mass = 160, Volume = 45902, + Size = Vector(22.46, 90.1, 22.82), + Offset = Vector(0, 0, -0.14) }) ACF.RegisterCrate("Ammo2x3x1", { @@ -94,6 +120,8 @@ ACF.RegisterCrate("Ammo2x3x1", { Model = "models/ammocrates/ammocrate_2x3x1.mdl", Mass = 30, Volume = 5119, + Size = Vector(32.06, 8.06, 20.06), + Offset = Vector(-0.64, 0, 10.19) }) ACF.RegisterCrate("Ammo2x3x2", { @@ -101,6 +129,8 @@ ACF.RegisterCrate("Ammo2x3x2", { Model = "models/ammocrates/ammocrate_2x3x2.mdl", Mass = 60, Volume = 12799, + Size = Vector(32.06, 20.06, 20.06), + Offset = Vector(-0.64, 0, 10.19) }) ACF.RegisterCrate("Ammo2x3x4", { @@ -108,6 +138,8 @@ ACF.RegisterCrate("Ammo2x3x4", { Model = "models/ammocrates/ammocrate_2x3x4.mdl", Mass = 120, Volume = 28800, + Size = Vector(32.06, 45.06, 20.06), + Offset = Vector(-0.79, 0, 10) }) ACF.RegisterCrate("Ammo2x3x6", { @@ -115,6 +147,8 @@ ACF.RegisterCrate("Ammo2x3x6", { Model = "models/ammocrates/ammocrate_2x3x6.mdl", Mass = 180, Volume = 43421, + Size = Vector(31.94, 68.04, 20.1), + Offset = Vector(-0.79, -0.04, 10.02) }) ACF.RegisterCrate("Ammo2x3x8", { @@ -122,6 +156,8 @@ ACF.RegisterCrate("Ammo2x3x8", { Model = "models/ammocrates/ammocrate_2x3x8.mdl", Mass = 240, Volume = 57509, + Size = Vector(31.94, 90.1, 20.1), + Offset = Vector(-0.79, 0, 10.02) }) ACF.RegisterCrate("Ammo2x4x1", { @@ -129,6 +165,8 @@ ACF.RegisterCrate("Ammo2x4x1", { Model = "models/ammocrates/ammocrate_2x4x1.mdl", Mass = 40, Volume = 7200, + Size = Vector(45.06, 8.06, 20.06), + Offset = Vector(-0.64, 0, 10.19) }) ACF.RegisterCrate("Ammo2x4x2", { @@ -136,6 +174,8 @@ ACF.RegisterCrate("Ammo2x4x2", { Model = "models/ammocrates/ammocrate_2x4x2.mdl", Mass = 80, Volume = 18000, + Size = Vector(45.06, 20.06, 20.06), + Offset = Vector(-0.2, 0.71, 10.18) }) ACF.RegisterCrate("Ammo2x4x4", { @@ -143,6 +183,8 @@ ACF.RegisterCrate("Ammo2x4x4", { Model = "models/ammocrates/ammocrate_2x4x4.mdl", Mass = 160, Volume = 40500, + Size = Vector(45.06, 45.06, 20.06), + Offset = Vector(-0.79, 0, 10) }) ACF.RegisterCrate("Ammo2x4x6", { @@ -150,6 +192,8 @@ ACF.RegisterCrate("Ammo2x4x6", { Model = "models/ammocrates/ammocrate_2x4x6.mdl", Mass = 240, Volume = 61200, + Size = Vector(45.06, 68.06, 20.06), + Offset = Vector(-0.79, 0, 10) }) ACF.RegisterCrate("Ammo2x4x8", { @@ -157,6 +201,8 @@ ACF.RegisterCrate("Ammo2x4x8", { Model = "models/ammocrates/ammocrate_2x4x8.mdl", Mass = 320, Volume = 80999, + Size = Vector(45.06, 90.06, 20.06), + Offset = Vector(-0.79, 0, 10) }) ACF.RegisterCrate("Ammo3x4x1", { @@ -164,6 +210,8 @@ ACF.RegisterCrate("Ammo3x4x1", { Model = "models/ammocrates/ammocrate_3x4x1.mdl", Mass = 60, Volume = 11520, + Size = Vector(45.06, 8.06, 32.06), + Offset = Vector(-0.64, 0, 16.25) }) ACF.RegisterCrate("Ammo3x4x2", { @@ -171,6 +219,8 @@ ACF.RegisterCrate("Ammo3x4x2", { Model = "models/ammocrates/ammocrate_3x4x2.mdl", Mass = 120, Volume = 28800, + Size = Vector(45.06, 20.06, 32.06), + Offset = Vector(-0.2, 0.71, 16.26) }) ACF.RegisterCrate("Ammo3x4x4", { @@ -178,6 +228,8 @@ ACF.RegisterCrate("Ammo3x4x4", { Model = "models/ammocrates/ammocrate_3x4x4.mdl", Mass = 240, Volume = 64800, + Size = Vector(45.06, 45.06, 32.06), + Offset = Vector(-0.79, 0, 16) }) ACF.RegisterCrate("Ammo3x4x6", { @@ -185,6 +237,8 @@ ACF.RegisterCrate("Ammo3x4x6", { Model = "models/ammocrates/ammocrate_3x4x6.mdl", Mass = 360, Volume = 97920, + Size = Vector(45.06, 68.06, 32.06), + Offset = Vector(-0.79, 0, 16) }) ACF.RegisterCrate("Ammo3x4x8", { @@ -192,6 +246,8 @@ ACF.RegisterCrate("Ammo3x4x8", { Model = "models/ammocrates/ammocrate_3x4x8.mdl", Mass = 480, Volume = 129599, + Size = Vector(45.06, 90.06, 32.06), + Offset = Vector(0.15, 0, 16) }) ACF.RegisterCrate("Ammo4x4x1", { @@ -199,6 +255,8 @@ ACF.RegisterCrate("Ammo4x4x1", { Model = "models/ammocrates/ammo_4x4x1.mdl", Mass = 80, Volume = 23186, + Size = Vector(45.06, 45.06, 11.51), + Offset = Vector(0, 0, -0.06) }) ACF.RegisterCrate("Ammo4x4x2", { @@ -206,6 +264,8 @@ ACF.RegisterCrate("Ammo4x4x2", { Model = "models/ammocrates/ammocrate_4x4x2.mdl", Mass = 160, Volume = 40500, + Size = Vector(45.06, 20.06, 45.06), + Offset = Vector(-0.14, 0.71, 22.5) }) ACF.RegisterCrate("Ammo4x4x4", { @@ -213,6 +273,8 @@ ACF.RegisterCrate("Ammo4x4x4", { Model = "models/ammocrates/ammocrate_4x4x4.mdl", Mass = 320, Volume = 91125, + Size = Vector(45.06, 45.06, 45.06), + Offset = Vector(0.15, 0, 22.5) }) ACF.RegisterCrate("Ammo4x4x6", { @@ -220,6 +282,8 @@ ACF.RegisterCrate("Ammo4x4x6", { Model = "models/ammocrates/ammocrate_4x4x6.mdl", Mass = 480, Volume = 137700, + Size = Vector(45.06, 68.06, 45.06), + Offset = Vector(0.15, 0.06, 22.5) }) ACF.RegisterCrate("Ammo4x4x8", { @@ -227,6 +291,8 @@ ACF.RegisterCrate("Ammo4x4x8", { Model = "models/ammocrates/ammocrate_4x4x8.mdl", Mass = 640, Volume = 182249, + Size = Vector(45.06, 90.06, 45.06), + Offset = Vector(0.15, -0.01, 22.5) }) ACF.RegisterCrate("Ammo4x6x6", { @@ -234,6 +300,8 @@ ACF.RegisterCrate("Ammo4x6x6", { Model = "models/ammocrates/ammo_4x6x6.mdl", Mass = 720, Volume = 204106, + Size = Vector(67.56, 89.98, 44.99), + Offset = Vector(0, 0, -0.07) }) ACF.RegisterCrate("Ammo4x6x8", { @@ -241,6 +309,8 @@ ACF.RegisterCrate("Ammo4x6x8", { Model = "models/ammocrates/ammo_4x6x8.mdl", Mass = 800, Volume = 272664, + Size = Vector(67.56, 67.35, 45), + Offset = Vector(0, 0, -0.02) }) ACF.RegisterCrate("Ammo4x8x8", { @@ -248,4 +318,6 @@ ACF.RegisterCrate("Ammo4x8x8", { Model = "models/ammocrates/ammo_4x8x8.mdl", Mass = 960, Volume = 366397, + Size = Vector(90.21, 90.13, 45.19), + Offset = Vector(0, 0, -0.15) }) diff --git a/lua/acf/shared/ammo_types/ap.lua b/lua/acf/shared/ammo_types/ap.lua index fae3c479d..b0a1102b1 100644 --- a/lua/acf/shared/ammo_types/ap.lua +++ b/lua/acf/shared/ammo_types/ap.lua @@ -25,6 +25,7 @@ function Ammo:UpdateRoundData(ToolData, Data, GUIData) Data.ProjMass = Data.FrArea * Data.ProjLength * 0.0079 --Volume of the projectile as a cylinder * density of steel Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass) Data.DragCoef = Data.FrArea * 0.0001 / Data.ProjMass + Data.CartMass = Data.PropMass + Data.ProjMass for K, V in pairs(self:GetDisplayData(Data)) do GUIData[K] = V diff --git a/lua/acf/shared/ammo_types/apcr.lua b/lua/acf/shared/ammo_types/apcr.lua index d13284fa7..6d76b9e2f 100644 --- a/lua/acf/shared/ammo_types/apcr.lua +++ b/lua/acf/shared/ammo_types/apcr.lua @@ -19,9 +19,10 @@ function Ammo:UpdateRoundData(ToolData, Data, GUIData) ACF.UpdateRoundSpecs(ToolData, Data, GUIData) - Data.ProjMass = Data.FrArea * Data.ProjLength * 0.0079 * 1.1111 --Volume of the projectile as a cylinder * density of steel - Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass) * 1.2 - Data.DragCoef = Data.FrArea * 0.0001 / Data.ProjMass + Data.ProjMass = (Data.FrArea * 1.1111) * (Data.ProjLength * 0.0079) * 0.75 --Volume of the projectile as a cylinder * density of steel + Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass) + Data.DragCoef = (Data.FrArea * 0.000125) / Data.ProjMass -- Worse drag (Manually fudged to make a meaningful difference) + Data.CartMass = Data.PropMass + Data.ProjMass for K, V in pairs(self:GetDisplayData(Data)) do GUIData[K] = V @@ -35,8 +36,8 @@ function Ammo:BaseConvert(_, ToolData) local Data, GUIData = ACF.RoundBaseGunpowder(ToolData, {}) Data.ShovePower = 0.2 - Data.PenArea = Data.FrArea ^ ACF.PenAreaMod - Data.LimitVel = 1000 --Most efficient penetration speed in m/s + Data.PenArea = (Data.FrArea * 0.7) ^ ACF.PenAreaMod -- APCR has a smaller penetrator + Data.LimitVel = 900 --Most efficient penetration speed in m/s Data.KETransfert = 0.1 --Kinetic energy transfert to the target for movement purposes Data.Ricochet = 55 --Base ricochet angle diff --git a/lua/acf/shared/ammo_types/apds.lua b/lua/acf/shared/ammo_types/apds.lua index 869d92d04..0d3758179 100644 --- a/lua/acf/shared/ammo_types/apds.lua +++ b/lua/acf/shared/ammo_types/apds.lua @@ -18,9 +18,14 @@ function Ammo:UpdateRoundData(ToolData, Data, GUIData) ACF.UpdateRoundSpecs(ToolData, Data, GUIData) - Data.ProjMass = Data.FrArea * Data.ProjLength * 0.0079 --Volume of the projectile as a cylinder * density of steel - Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass) * 1.2 - Data.DragCoef = Data.FrArea * 0.0001 / Data.ProjMass + local Cylinder = (3.1416 * (Data.Caliber * 0.05) ^ 2) * Data.ProjLength * 0.5 -- A cylinder 1/2 the length of the projectile + local Hole = Data.RoundArea * Data.ProjLength * 0.25 -- Volume removed by the hole the dart passes through + local SabotMass = (Cylinder - Hole) * 2.7 * 0.65 * 0.001 -- Aluminum sabot + + Data.ProjMass = (Data.RoundArea * 0.6666) * (Data.ProjLength * 0.0079) -- Volume of the projectile as a cylinder * density of steel + Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass + SabotMass) + Data.DragCoef = Data.RoundArea * 0.0001 / Data.ProjMass + Data.CartMass = Data.PropMass + Data.ProjMass + SabotMass for K, V in pairs(self:GetDisplayData(Data)) do GUIData[K] = V @@ -32,12 +37,15 @@ function Ammo:BaseConvert(_, ToolData) if not ToolData.Propellant then ToolData.Propellant = 0 end local Data, GUIData = ACF.RoundBaseGunpowder(ToolData, {}) + local SubCaliberRatio = 0.375 -- Ratio of projectile to gun caliber + local Area = 3.1416 * (Data.Caliber * 0.05 * SubCaliberRatio) ^ 2 + Data.RoundArea = Area Data.ShovePower = 0.2 - Data.PenArea = Data.FrArea ^ ACF.PenAreaMod - Data.LimitVel = 1000 --Most efficient penetration speed in m/s + Data.PenArea = Area ^ ACF.PenAreaMod + Data.LimitVel = 950 --Most efficient penetration speed in m/s Data.KETransfert = 0.1 --Kinetic energy transfert to the target for movement purposes - Data.Ricochet = 65 --Base ricochet angle + Data.Ricochet = 80 --Base ricochet angle self:UpdateRoundData(ToolData, Data, GUIData) diff --git a/lua/acf/shared/ammo_types/apfsds.lua b/lua/acf/shared/ammo_types/apfsds.lua index 456c25ffe..c95173b71 100644 --- a/lua/acf/shared/ammo_types/apfsds.lua +++ b/lua/acf/shared/ammo_types/apfsds.lua @@ -16,9 +16,14 @@ function Ammo:UpdateRoundData(ToolData, Data, GUIData) ACF.UpdateRoundSpecs(ToolData, Data, GUIData) - Data.ProjMass = Data.FrArea * Data.ProjLength * 0.0079 * 0.6666 --Volume of the projectile as a cylinder * density of steel - Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass) * 1.5 + local Cylinder = (3.1416 * (Data.Caliber * 0.05) ^ 2) * Data.ProjLength * 0.25 -- A cylinder 1/4 the length of the projectile + local Hole = Data.RoundArea * Data.ProjLength * 0.25 -- Volume removed by the hole the dart passes through + local SabotMass = (Cylinder - Hole) * 2.7 * 0.25 * 0.001 -- A cylinder with a hole the size of the dart in it and im no math wizard so we're just going to take off 3/4 of the mass for the cutout since sabots are shaped like this: ][ + + Data.ProjMass = (Data.RoundArea * 0.6666) * (Data.ProjLength * 0.0079) -- Volume of the projectile as a cylinder * density of steel + Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass + SabotMass) Data.DragCoef = Data.FrArea * 0.0001 / Data.ProjMass + Data.CartMass = Data.PropMass + Data.ProjMass + SabotMass for K, V in pairs(self:GetDisplayData(Data)) do GUIData[K] = V @@ -30,12 +35,15 @@ function Ammo:BaseConvert(_, ToolData) if not ToolData.Propellant then ToolData.Propellant = 0 end local Data, GUIData = ACF.RoundBaseGunpowder(ToolData, {}) + local SubCaliberRatio = 0.29 -- Ratio of projectile to gun caliber + local Area = 3.1416 * (Data.Caliber * 0.05 * SubCaliberRatio) ^ 2 + Data.RoundArea = Area Data.ShovePower = 0.2 - Data.PenArea = Data.FrArea ^ ACF.PenAreaMod - Data.LimitVel = 1200 --Most efficient penetration speed in m/s + Data.PenArea = Area ^ ACF.PenAreaMod + Data.LimitVel = 1000 --Most efficient penetration speed in m/s Data.KETransfert = 0.1 --Kinetic energy transfert to the target for movement purposes - Data.Ricochet = 75 --Base ricochet angle + Data.Ricochet = 80 --Base ricochet angle self:UpdateRoundData(ToolData, Data, GUIData) diff --git a/lua/acf/shared/ammo_types/aphe.lua b/lua/acf/shared/ammo_types/aphe.lua index 5a0b1a2c7..54986b0da 100644 --- a/lua/acf/shared/ammo_types/aphe.lua +++ b/lua/acf/shared/ammo_types/aphe.lua @@ -32,6 +32,7 @@ function Ammo:UpdateRoundData(ToolData, Data, GUIData) Data.ProjMass = math.max(GUIData.ProjVolume - GUIData.FillerVol, 0) * 0.0079 + Data.FillerMass Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass) Data.DragCoef = Data.FrArea * 0.0001 / Data.ProjMass + Data.CartMass = Data.PropMass + Data.ProjMass for K, V in pairs(self:GetDisplayData(Data)) do GUIData[K] = V diff --git a/lua/acf/shared/ammo_types/fl.lua b/lua/acf/shared/ammo_types/fl.lua index 5dc9be981..88574ed19 100644 --- a/lua/acf/shared/ammo_types/fl.lua +++ b/lua/acf/shared/ammo_types/fl.lua @@ -87,6 +87,7 @@ function Ammo:UpdateRoundData(ToolData, Data, GUIData) Data.ProjMass = Data.Flechettes * Data.FlechetteMass -- total mass of all flechettes Data.DragCoef = Data.FrArea * 0.0001 / Data.ProjMass Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass) + Data.CartMass = Data.PropMass + Data.ProjMass for K, V in pairs(self:GetDisplayData(Data)) do GUIData[K] = V diff --git a/lua/acf/shared/ammo_types/he.lua b/lua/acf/shared/ammo_types/he.lua index ec025c1a5..c8e6ed552 100644 --- a/lua/acf/shared/ammo_types/he.lua +++ b/lua/acf/shared/ammo_types/he.lua @@ -30,6 +30,7 @@ function Ammo:UpdateRoundData(ToolData, Data, GUIData) Data.ProjMass = math.max(GUIData.ProjVolume - GUIData.FillerVol, 0) * 0.0079 + Data.FillerMass Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass) Data.DragCoef = Data.FrArea * 0.0001 / Data.ProjMass + Data.CartMass = Data.PropMass + Data.ProjMass for K, V in pairs(self:GetDisplayData(Data)) do GUIData[K] = V diff --git a/lua/acf/shared/ammo_types/heat.lua b/lua/acf/shared/ammo_types/heat.lua index 9c029036b..ad586e6f3 100644 --- a/lua/acf/shared/ammo_types/heat.lua +++ b/lua/acf/shared/ammo_types/heat.lua @@ -78,6 +78,7 @@ function Ammo:UpdateRoundData(ToolData, Data, GUIData) Data.SlugMV = self:CalcSlugMV(Data, HEATFiller) Data.CasingMass = Data.ProjMass - Data.FillerMass - ConeVol * 0.0079 Data.DragCoef = Data.FrArea * 0.0001 / Data.ProjMass + Data.CartMass = Data.PropMass + Data.ProjMass for K, V in pairs(self:GetDisplayData(Data)) do GUIData[K] = V diff --git a/lua/acf/shared/ammo_types/heatfs.lua b/lua/acf/shared/ammo_types/heatfs.lua index 77fd7e393..67b3f6849 100644 --- a/lua/acf/shared/ammo_types/heatfs.lua +++ b/lua/acf/shared/ammo_types/heatfs.lua @@ -47,6 +47,7 @@ function Ammo:UpdateRoundData(ToolData, Data, GUIData) Data.SlugMV = self:CalcSlugMV(Data, HEATFiller) Data.CasingMass = Data.ProjMass - Data.FillerMass - ConeVol * 0.0079 Data.DragCoef = Data.FrArea * 0.0001 / Data.ProjMass + Data.CartMass = Data.PropMass + Data.ProjMass for K, V in pairs(self:GetDisplayData(Data)) do GUIData[K] = V diff --git a/lua/acf/shared/ammo_types/hp.lua b/lua/acf/shared/ammo_types/hp.lua index 11e6fd8c3..8ca6a1d25 100644 --- a/lua/acf/shared/ammo_types/hp.lua +++ b/lua/acf/shared/ammo_types/hp.lua @@ -29,6 +29,7 @@ function Ammo:UpdateRoundData(ToolData, Data, GUIData) Data.ExpCaliber = Data.Caliber * 0.1 + ExpRatio * Data.ProjLength Data.PenArea = (3.1416 * Data.ExpCaliber * 0.5) ^ 2 ^ ACF.PenAreaMod Data.DragCoef = Data.FrArea * 0.0001 / Data.ProjMass + Data.CartMass = Data.PropMass + Data.ProjMass for K, V in pairs(self:GetDisplayData(Data)) do GUIData[K] = V diff --git a/lua/acf/shared/ammo_types/refill.lua b/lua/acf/shared/ammo_types/refill.lua index e925053d1..94592a0a9 100644 --- a/lua/acf/shared/ammo_types/refill.lua +++ b/lua/acf/shared/ammo_types/refill.lua @@ -15,13 +15,13 @@ function Ammo:BaseConvert(_, ToolData) Id = ToolData.Weapon, Type = ToolData.Ammo, Caliber = Weapon and Weapon.Caliber or 12.7, - ProjMass = 6 * 0.079, --Volume of the projectile as a cylinder * streamline factor (Data5) * density of steel - PropMass = 6 * ACF.PDensity * 0.001, --Volume of the case as a cylinder * Powder density converted from g to kg + ProjMass = 5.5 * 0.079, --Volume of the projectile as a cylinder * streamline factor (Data5) * density of steel + PropMass = 5.5 * ACF.PDensity * 0.001, --Volume of the case as a cylinder * Powder density converted from g to kg FillerMass = 0, DragCoef = 0, Tracer = 0, MuzzleVel = 0, - RoundVolume = 36, + RoundVolume = 35, } end diff --git a/lua/acf/shared/ammo_types/smoke.lua b/lua/acf/shared/ammo_types/smoke.lua index 1169fb701..1216055f1 100644 --- a/lua/acf/shared/ammo_types/smoke.lua +++ b/lua/acf/shared/ammo_types/smoke.lua @@ -48,6 +48,7 @@ function Ammo:UpdateRoundData(ToolData, Data, GUIData) Data.ProjMass = math.max(GUIData.ProjVolume - (GUIData.FillerVol + GUIData.WPVol), 0) * 0.0079 + Data.FillerMass + Data.WPMass Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass) Data.DragCoef = Data.FrArea * 0.0001 / Data.ProjMass + Data.CartMass = Data.PropMass + Data.ProjMass for K, V in pairs(self:GetDisplayData(Data)) do GUIData[K] = V diff --git a/lua/acf/shared/engines/b4.lua b/lua/acf/shared/engines/b4.lua index 567aa6a58..edc11896e 100644 --- a/lua/acf/shared/engines/b4.lua +++ b/lua/acf/shared/engines/b4.lua @@ -82,7 +82,7 @@ do Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 60, - Torque = 105, + Torque = 131, FlywheelMass = 0.06, RPM = { Idle = 600, @@ -100,7 +100,7 @@ do Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 125, - Torque = 180, + Torque = 225, FlywheelMass = 0.15, RPM = { Idle = 700, @@ -118,7 +118,7 @@ do Fuel = { Petrol = true, Diesel = true }, Type = "GenericDiesel", Mass = 135, - Torque = 248, + Torque = 310, FlywheelMass = 0.4, RPM = { Idle = 550, @@ -136,7 +136,7 @@ do Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 210, - Torque = 252, + Torque = 315, FlywheelMass = 0.15, RPM = { Idle = 900, diff --git a/lua/acf/shared/engines/b6.lua b/lua/acf/shared/engines/b6.lua index f68726a3f..969fc47ef 100644 --- a/lua/acf/shared/engines/b6.lua +++ b/lua/acf/shared/engines/b6.lua @@ -83,7 +83,7 @@ do Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 100, - Torque = 136, + Torque = 170, FlywheelMass = 0.08, RPM = { Idle = 750, @@ -101,7 +101,7 @@ do Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 240, - Torque = 330, + Torque = 412, FlywheelMass = 0.11, RPM = { Idle = 900, @@ -119,7 +119,7 @@ do Fuel = { Petrol = true, Diesel = true }, Type = "GenericDiesel", Mass = 480, - Torque = 565, + Torque = 706, FlywheelMass = 0.65, RPM = { Idle = 500, @@ -137,7 +137,7 @@ do Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 725, - Torque = 1100, + Torque = 1375, FlywheelMass = 1, RPM = { Idle = 620, diff --git a/lua/acf/shared/engines/electric.lua b/lua/acf/shared/engines/electric.lua index ec96066bb..3168445d4 100644 --- a/lua/acf/shared/engines/electric.lua +++ b/lua/acf/shared/engines/electric.lua @@ -148,7 +148,7 @@ do -- Electric Motors Fuel = { Electric = true }, Type = "Electric", Mass = 250, - Torque = 384, + Torque = 480, FlywheelMass = 0.3, IsElectric = true, RPM = { @@ -168,7 +168,7 @@ do -- Electric Motors Fuel = { Electric = true }, Type = "Electric", Mass = 850, - Torque = 1152, + Torque = 1440, FlywheelMass = 1.5, IsElectric = true, RPM = { @@ -188,7 +188,7 @@ do -- Electric Motors Fuel = { Electric = true }, Type = "Electric", Mass = 1900, - Torque = 3360, + Torque = 4200, FlywheelMass = 11.2, IsElectric = true, RPM = { diff --git a/lua/acf/shared/engines/i2.lua b/lua/acf/shared/engines/i2.lua index 711d351a0..7f44cb103 100644 --- a/lua/acf/shared/engines/i2.lua +++ b/lua/acf/shared/engines/i2.lua @@ -50,7 +50,7 @@ do Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 45, - Torque = 105, + Torque = 131, FlywheelMass = 0.12, RPM = { Idle = 500, @@ -68,7 +68,7 @@ do Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 800, - Torque = 2000, + Torque = 2500, FlywheelMass = 7, RPM = { Idle = 350, diff --git a/lua/acf/shared/engines/i3.lua b/lua/acf/shared/engines/i3.lua index 1f2ccb82a..921a9c0c0 100644 --- a/lua/acf/shared/engines/i3.lua +++ b/lua/acf/shared/engines/i3.lua @@ -120,7 +120,7 @@ do -- Petrol Engines Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 40, - Torque = 95, + Torque = 118, FlywheelMass = 0.05, RPM = { Idle = 1100, @@ -138,7 +138,7 @@ do -- Petrol Engines Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 170, - Torque = 195, + Torque = 243, FlywheelMass = 0.2, RPM = { Idle = 900, @@ -156,7 +156,7 @@ do -- Petrol Engines Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 500, - Torque = 715, + Torque = 893, FlywheelMass = 3.7, RPM = { Idle = 500, @@ -176,7 +176,7 @@ do -- Diesel Engines Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 65, - Torque = 150, + Torque = 187, FlywheelMass = 0.2, RPM = { Idle = 550, @@ -194,7 +194,7 @@ do -- Diesel Engines Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 200, - Torque = 290, + Torque = 362, FlywheelMass = 1, RPM = { Idle = 600, @@ -212,7 +212,7 @@ do -- Diesel Engines Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 650, - Torque = 1200, + Torque = 1500, FlywheelMass = 5, RPM = { Idle = 550, diff --git a/lua/acf/shared/engines/i4.lua b/lua/acf/shared/engines/i4.lua index 8307ce033..88fe25b0b 100644 --- a/lua/acf/shared/engines/i4.lua +++ b/lua/acf/shared/engines/i4.lua @@ -120,7 +120,7 @@ do -- Petrol Engines Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 50, - Torque = 90, + Torque = 112, FlywheelMass = 0.06, RPM = { Idle = 900, @@ -138,7 +138,7 @@ do -- Petrol Engines Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 200, - Torque = 240, + Torque = 300, FlywheelMass = 0.2, RPM = { Idle = 900, @@ -156,7 +156,7 @@ do -- Petrol Engines Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 600, - Torque = 850, + Torque = 1062, FlywheelMass = 4, RPM = { Idle = 500, @@ -176,7 +176,7 @@ do -- Diesel Engines Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 90, - Torque = 150, + Torque = 187, FlywheelMass = 0.2, RPM = { Idle = 650, @@ -194,7 +194,7 @@ do -- Diesel Engines Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 250, - Torque = 320, + Torque = 400, FlywheelMass = 1, RPM = { Idle = 500, @@ -212,7 +212,7 @@ do -- Diesel Engines Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 800, - Torque = 1400, + Torque = 1750, FlywheelMass = 5, RPM = { Idle = 450, diff --git a/lua/acf/shared/engines/i5.lua b/lua/acf/shared/engines/i5.lua index 7ba6f5b5a..75158ba2d 100644 --- a/lua/acf/shared/engines/i5.lua +++ b/lua/acf/shared/engines/i5.lua @@ -86,7 +86,7 @@ do -- Petrol Engines Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 100, - Torque = 125, + Torque = 156, FlywheelMass = 0.12, RPM = { Idle = 900, @@ -104,7 +104,7 @@ do -- Petrol Engines Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 250, - Torque = 275, + Torque = 343, FlywheelMass = 0.25, RPM = { Idle = 700, @@ -124,7 +124,7 @@ do -- Diesel Engines Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 130, - Torque = 180, + Torque = 225, FlywheelMass = 0.5, RPM = { Idle = 500, @@ -142,7 +142,7 @@ do -- Diesel Engines Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 400, - Torque = 440, + Torque = 550, FlywheelMass = 1.5, RPM = { Idle = 650, diff --git a/lua/acf/shared/engines/i6.lua b/lua/acf/shared/engines/i6.lua index fc413afee..ce91e652c 100644 --- a/lua/acf/shared/engines/i6.lua +++ b/lua/acf/shared/engines/i6.lua @@ -120,7 +120,7 @@ do -- Petrol Engines Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 120, - Torque = 130, + Torque = 162, FlywheelMass = 0.1, RPM = { Idle = 800, @@ -138,7 +138,7 @@ do -- Petrol Engines Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 300, - Torque = 360, + Torque = 450, FlywheelMass = 0.2, RPM = { Idle = 900, @@ -156,7 +156,7 @@ do -- Petrol Engines Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 850, - Torque = 960, + Torque = 1200, FlywheelMass = 2.5, RPM = { Idle = 800, @@ -176,7 +176,7 @@ do -- Diesel Engines Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 150, - Torque = 200, + Torque = 250, FlywheelMass = 0.5, RPM = { Idle = 650, @@ -194,7 +194,7 @@ do -- Diesel Engines Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 450, - Torque = 520, + Torque = 650, FlywheelMass = 1.5, RPM = { Idle = 600, @@ -212,7 +212,7 @@ do -- Diesel Engines Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 1200, - Torque = 1700, + Torque = 2125, FlywheelMass = 8, RPM = { Idle = 400, diff --git a/lua/acf/shared/engines/radial.lua b/lua/acf/shared/engines/radial.lua index 381a57d82..30156a78d 100644 --- a/lua/acf/shared/engines/radial.lua +++ b/lua/acf/shared/engines/radial.lua @@ -83,7 +83,7 @@ do Fuel = { Petrol = true }, Type = "Radial", Mass = 210, - Torque = 310, + Torque = 387, FlywheelMass = 0.22, RPM = { Idle = 700, @@ -101,7 +101,7 @@ do Fuel = { Petrol = true }, Type = "Radial", Mass = 385, - Torque = 560, + Torque = 700, FlywheelMass = 0.45, RPM = { Idle = 600, @@ -119,7 +119,7 @@ do Fuel = { Petrol = true, Diesel = true }, Type = "GenericDiesel", Mass = 450, - Torque = 800, + Torque = 1000, FlywheelMass = 1, RPM = { Idle = 400, @@ -137,7 +137,7 @@ do Fuel = { Petrol = true }, Type = "Radial", Mass = 952, - Torque = 1615, + Torque = 2018, FlywheelMass = 3.4, RPM = { Idle = 750, diff --git a/lua/acf/shared/engines/rotary.lua b/lua/acf/shared/engines/rotary.lua index 824a73270..7dee466ec 100644 --- a/lua/acf/shared/engines/rotary.lua +++ b/lua/acf/shared/engines/rotary.lua @@ -66,7 +66,7 @@ do Fuel = { Petrol = true }, Type = "Wankel", Mass = 50, - Torque = 78, + Torque = 97, FlywheelMass = 0.06, RPM = { Idle = 950, @@ -84,7 +84,7 @@ do Fuel = { Petrol = true }, Type = "Wankel", Mass = 140, - Torque = 124, + Torque = 155, FlywheelMass = 0.06, RPM = { Idle = 950, @@ -102,7 +102,7 @@ do Fuel = { Petrol = true }, Type = "Wankel", Mass = 200, - Torque = 188, + Torque = 235, FlywheelMass = 0.1, RPM = { Idle = 950, diff --git a/lua/acf/shared/engines/single.lua b/lua/acf/shared/engines/single.lua index 03f8229d3..5b62aaeca 100644 --- a/lua/acf/shared/engines/single.lua +++ b/lua/acf/shared/engines/single.lua @@ -65,7 +65,7 @@ do Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 15, - Torque = 20, + Torque = 25, FlywheelMass = 0.005, RPM = { Idle = 1200, @@ -83,7 +83,7 @@ do Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 20, - Torque = 40, + Torque = 50, FlywheelMass = 0.005, RPM = { Idle = 900, @@ -101,7 +101,7 @@ do Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 50, - Torque = 90, + Torque = 112, FlywheelMass = 0.1, RPM = { Idle = 600, diff --git a/lua/acf/shared/engines/special.lua b/lua/acf/shared/engines/special.lua index c5ed7e8aa..40f11f282 100644 --- a/lua/acf/shared/engines/special.lua +++ b/lua/acf/shared/engines/special.lua @@ -203,7 +203,7 @@ do -- Special Rotary Engines Fuel = { Petrol = true }, Type = "Wankel", Mass = 260, - Torque = 250, + Torque = 312, FlywheelMass = 0.11, RPM = { Idle = 1200, @@ -223,7 +223,7 @@ do -- Special I2 Engines Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 60, - Torque = 116, + Torque = 145, FlywheelMass = 0.085, RPM = { Idle = 750, @@ -243,7 +243,7 @@ do -- Special I4 Engines Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 78, - Torque = 68, + Torque = 85, FlywheelMass = 0.031, Pitch = 0.75, RPM = { @@ -262,7 +262,7 @@ do -- Special I4 Engines Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 150, - Torque = 176, + Torque = 220, FlywheelMass = 0.06, RPM = { Idle = 950, @@ -282,7 +282,7 @@ do -- Special V4 Engines Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 92, - Torque = 124.8, + Torque = 156, FlywheelMass = 0.04, RPM = { Idle = 900, @@ -302,7 +302,7 @@ do -- Special I6 Engines Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 180, - Torque = 224, + Torque = 280, FlywheelMass = 0.1, RPM = { Idle = 1100, @@ -322,7 +322,7 @@ do -- Special V6 Engines Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 134, - Torque = 172, + Torque = 215, FlywheelMass = 0.075, RPM = { Idle = 950, @@ -342,7 +342,7 @@ do -- Special V8 Engines Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 180, - Torque = 200, + Torque = 250, FlywheelMass = 0.075, RPM = { Idle = 1000, @@ -360,7 +360,7 @@ do -- Special V8 Engines Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 400, - Torque = 340, + Torque = 425, FlywheelMass = 0.15, RPM = { Idle = 1000, @@ -380,7 +380,7 @@ do -- Special V10 Engines Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 300, - Torque = 320, + Torque = 400, FlywheelMass = 0.15, RPM = { Idle = 1100, @@ -400,7 +400,7 @@ do -- Special V12 Engines Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 175, - Torque = 248, + Torque = 310, FlywheelMass = 0.1, Pitch = 0.85, RPM = { diff --git a/lua/acf/shared/engines/turbine.lua b/lua/acf/shared/engines/turbine.lua index 07e5a9931..13df0367d 100644 --- a/lua/acf/shared/engines/turbine.lua +++ b/lua/acf/shared/engines/turbine.lua @@ -257,7 +257,7 @@ do -- Forward-facing Gas Turbines Fuel = { Petrol = true, Diesel = true }, Type = "Turbine", Mass = 200, - Torque = 550, + Torque = 687, FlywheelMass = 2.9, IsElectric = true, RPM = { @@ -277,7 +277,7 @@ do -- Forward-facing Gas Turbines Fuel = { Petrol = true, Diesel = true }, Type = "Turbine", Mass = 400, - Torque = 813, + Torque = 1016, FlywheelMass = 4.3, IsElectric = true, RPM = { @@ -297,7 +297,7 @@ do -- Forward-facing Gas Turbines Fuel = { Petrol = true, Diesel = true }, Type = "Turbine", Mass = 1100, - Torque = 1990, + Torque = 2487, FlywheelMass = 10.5, IsElectric = true, RPM = { @@ -319,7 +319,7 @@ do -- Transaxial Gas Turbines Fuel = { Petrol = true, Diesel = true }, Type = "Turbine", Mass = 160, - Torque = 440, + Torque = 550, FlywheelMass = 2.3, IsElectric = true, IsTrans = true, @@ -340,7 +340,7 @@ do -- Transaxial Gas Turbines Fuel = { Petrol = true, Diesel = true }, Type = "Turbine", Mass = 320, - Torque = 650, + Torque = 812, FlywheelMass = 3.4, IsElectric = true, IsTrans = true, @@ -361,7 +361,7 @@ do -- Transaxial Gas Turbines Fuel = { Petrol = true, Diesel = true }, Type = "Turbine", Mass = 880, - Torque = 1592, + Torque = 1990, FlywheelMass = 8.4, IsElectric = true, IsTrans = true, @@ -389,7 +389,7 @@ do -- Forward-facing Ground Gas Turbines Fuel = { Petrol = true, Diesel = true }, Type = "Radial", Mass = 350, - Torque = 800, + Torque = 1000, FlywheelMass = 14.3, IsElectric = true, RPM = { @@ -409,7 +409,7 @@ do -- Forward-facing Ground Gas Turbines Fuel = { Petrol = true, Diesel = true }, Type = "Radial", --This is done to give proper fuel consumption and make the turbines not instant-torque from idle Mass = 600, - Torque = 1200, + Torque = 1500, FlywheelMass = 29.6, IsElectric = true, Pitch = 1.15, @@ -430,7 +430,7 @@ do -- Forward-facing Ground Gas Turbines Fuel = { Petrol = true, Diesel = true }, Type = "Radial", Mass = 1650, - Torque = 4000, + Torque = 5000, FlywheelMass = 75, IsElectric = true, Pitch = 1.35, @@ -453,7 +453,7 @@ do -- Transaxial Ground Gas Turbines Fuel = { Petrol = true, Diesel = true }, Type = "Radial", Mass = 280, - Torque = 600, + Torque = 750, FlywheelMass = 11.4, IsElectric = true, IsTrans = true, @@ -474,7 +474,7 @@ do -- Transaxial Ground Gas Turbines Fuel = { Petrol = true, Diesel = true }, Type = "Radial", Mass = 480, - Torque = 900, + Torque = 1125, FlywheelMass = 23.7, IsElectric = true, IsTrans = true, @@ -496,7 +496,7 @@ do -- Transaxial Ground Gas Turbines Fuel = { Petrol = true, Diesel = true }, Type = "Radial", Mass = 1320, - Torque = 3000, + Torque = 3750, FlywheelMass = 60, IsElectric = true, IsTrans = true, diff --git a/lua/acf/shared/engines/v10.lua b/lua/acf/shared/engines/v10.lua index a7f11c2b9..71c7276cc 100644 --- a/lua/acf/shared/engines/v10.lua +++ b/lua/acf/shared/engines/v10.lua @@ -64,7 +64,7 @@ do Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 160, - Torque = 288, + Torque = 360, FlywheelMass = 0.2, RPM = { Idle = 900, @@ -82,7 +82,7 @@ do Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 300, - Torque = 490, + Torque = 612, FlywheelMass = 0.5, RPM = { Idle = 750, @@ -100,7 +100,7 @@ do Fuel = { Petrol = true, Diesel = true }, Type = "GenericDiesel", Mass = 1600, - Torque = 2605, + Torque = 3256, FlywheelMass = 5, RPM = { Idle = 525, diff --git a/lua/acf/shared/engines/v12.lua b/lua/acf/shared/engines/v12.lua index feb269eac..4a74a60d0 100644 --- a/lua/acf/shared/engines/v12.lua +++ b/lua/acf/shared/engines/v12.lua @@ -137,7 +137,7 @@ do -- Petrol Engines Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 188, - Torque = 235, + Torque = 293, FlywheelMass = 0.2, RPM = { Idle = 1000, @@ -155,7 +155,7 @@ do -- Petrol Engines Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 360, - Torque = 500, + Torque = 625, FlywheelMass = 0.45, RPM = { Idle = 800, @@ -173,7 +173,7 @@ do -- Petrol Engines Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 520, - Torque = 660, + Torque = 825, FlywheelMass = 1, RPM = { Idle = 700, @@ -191,7 +191,7 @@ do -- Petrol Engines Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 1350, - Torque = 1925, + Torque = 2406, FlywheelMass = 5, RPM = { Idle = 600, @@ -211,7 +211,7 @@ do -- Diesel Engines Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 305, - Torque = 375, + Torque = 468, FlywheelMass = 0.475, RPM = { Idle = 650, @@ -229,7 +229,7 @@ do -- Diesel Engines Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 600, - Torque = 750, + Torque = 937, FlywheelMass = 2.5, RPM = { Idle = 675, @@ -247,7 +247,7 @@ do -- Diesel Engines Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 1800, - Torque = 3560, + Torque = 4450, FlywheelMass = 7, RPM = { Idle = 400, diff --git a/lua/acf/shared/engines/v2.lua b/lua/acf/shared/engines/v2.lua index ac1fcaff9..48738061e 100644 --- a/lua/acf/shared/engines/v2.lua +++ b/lua/acf/shared/engines/v2.lua @@ -65,7 +65,7 @@ do -- Petrol Engines Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 30, - Torque = 50, + Torque = 62, FlywheelMass = 0.01, RPM = { Idle = 900, @@ -83,7 +83,7 @@ do -- Petrol Engines Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 50, - Torque = 85, + Torque = 106, FlywheelMass = 0.02, RPM = { Idle = 725, @@ -101,7 +101,7 @@ do -- Petrol Engines Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 100, - Torque = 160, + Torque = 200, FlywheelMass = 0.075, RPM = { Idle = 900, diff --git a/lua/acf/shared/engines/v4.lua b/lua/acf/shared/engines/v4.lua index b3855e202..d25bd7c0f 100644 --- a/lua/acf/shared/engines/v4.lua +++ b/lua/acf/shared/engines/v4.lua @@ -50,7 +50,7 @@ do -- Diesel Engines Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 110, - Torque = 165, + Torque = 206, FlywheelMass = 0.3, RPM = { Idle = 650, @@ -68,7 +68,7 @@ do -- Diesel Engines Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 275, - Torque = 480, + Torque = 600, FlywheelMass = 1.05, RPM = { Idle = 600, diff --git a/lua/acf/shared/engines/v6.lua b/lua/acf/shared/engines/v6.lua index d0036b3db..8db0dbc60 100644 --- a/lua/acf/shared/engines/v6.lua +++ b/lua/acf/shared/engines/v6.lua @@ -100,7 +100,7 @@ do -- Petrol Engines Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 190, - Torque = 253, + Torque = 316, FlywheelMass = 0.25, RPM = { Idle = 700, @@ -118,7 +118,7 @@ do -- Petrol Engines Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 360, - Torque = 472, + Torque = 590, FlywheelMass = 0.45, RPM = { Idle = 800, @@ -136,7 +136,7 @@ do -- Petrol Engines Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 675, - Torque = 1445, + Torque = 1806, FlywheelMass = 4, RPM = { Idle = 600, @@ -156,7 +156,7 @@ do -- Diesel Engines Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 520, - Torque = 485, + Torque = 606, FlywheelMass = 0.8, RPM = { Idle = 650, @@ -174,7 +174,7 @@ do -- Diesel Engines Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 900, - Torque = 1767, + Torque = 2208, FlywheelMass = 6.4, RPM = { Idle = 400, diff --git a/lua/acf/shared/engines/v8.lua b/lua/acf/shared/engines/v8.lua index d029d5ae8..ef1daee72 100644 --- a/lua/acf/shared/engines/v8.lua +++ b/lua/acf/shared/engines/v8.lua @@ -120,7 +120,7 @@ do -- Petrol Engines Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 260, - Torque = 320, + Torque = 400, FlywheelMass = 0.15, RPM = { Idle = 800, @@ -138,7 +138,7 @@ do -- Petrol Engines Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 400, - Torque = 460, + Torque = 575, FlywheelMass = 0.25, RPM = { Idle = 700, @@ -156,7 +156,7 @@ do -- Petrol Engines Fuel = { Petrol = true }, Type = "GenericPetrol", Mass = 850, - Torque = 1458, + Torque = 1822, FlywheelMass = 2.8, RPM = { Idle = 600, @@ -176,7 +176,7 @@ do -- Diesel Engines Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 320, - Torque = 415, + Torque = 518, FlywheelMass = 0.75, RPM = { Idle = 800, @@ -194,7 +194,7 @@ do -- Diesel Engines Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 520, - Torque = 700, + Torque = 875, FlywheelMass = 1.6, RPM = { Idle = 650, @@ -212,7 +212,7 @@ do -- Diesel Engines Fuel = { Diesel = true }, Type = "GenericDiesel", Mass = 1200, - Torque = 2300, + Torque = 2875, FlywheelMass = 4.5, RPM = { Idle = 500, diff --git a/lua/acf/shared/guns/autocannon.lua b/lua/acf/shared/guns/autocannon.lua index 425b6bc4b..cb6055153 100644 --- a/lua/acf/shared/guns/autocannon.lua +++ b/lua/acf/shared/guns/autocannon.lua @@ -88,7 +88,7 @@ ACF.RegisterWeaponClass("AC", { Name = "Autocannon", Description = "Autocannons have a rather high weight and bulk for the ammo they fire, but they can fire it extremely fast.", MuzzleFlash = "auto_muzzleflash_noscale", - Spread = 0.25, + Spread = 0.2, Sound = "acf_base/weapons/ac_fire4.mp3", Caliber = { Min = 20, diff --git a/lua/acf/shared/guns/grenadelauncher.lua b/lua/acf/shared/guns/grenadelauncher.lua index 3a914c47e..78102de28 100644 --- a/lua/acf/shared/guns/grenadelauncher.lua +++ b/lua/acf/shared/guns/grenadelauncher.lua @@ -32,7 +32,7 @@ ACF.RegisterWeaponClass("GL", { Name = "Grenade Launcher", Description = "Grenade Launchers can fire shells with relatively large payloads at a fast rate, but with very limited velocities and poor accuracy.", MuzzleFlash = "gl_muzzleflash_noscale", - Spread = 0.32, + Spread = 0.28, Sound = "acf_base/weapons/grenadelauncher.mp3", Caliber = { Min = 25, diff --git a/lua/acf/shared/guns/heavymachinegun.lua b/lua/acf/shared/guns/heavymachinegun.lua index 3777b2b8f..2fba203f6 100644 --- a/lua/acf/shared/guns/heavymachinegun.lua +++ b/lua/acf/shared/guns/heavymachinegun.lua @@ -92,7 +92,7 @@ ACF.RegisterWeaponClass("HMG", { Name = "Heavy Machinegun", Description = "Designed as autocannons for aircraft, HMGs are rapid firing, lightweight, and compact but sacrifice accuracy, magazine size, and reload times.", MuzzleFlash = "mg_muzzleflash_noscale", - Spread = 1.3, + Spread = 0.24, Sound = "acf_base/weapons/mg_fire3.mp3", Caliber = { Min = 13, diff --git a/lua/acf/shared/guns/howitzer.lua b/lua/acf/shared/guns/howitzer.lua index b08fb76a8..94e0fc52e 100644 --- a/lua/acf/shared/guns/howitzer.lua +++ b/lua/acf/shared/guns/howitzer.lua @@ -116,7 +116,7 @@ ACF.RegisterWeaponClass("HW", { Name = "Howitzer", Description = "Howitzers are limited to rather mediocre muzzle velocities, but can fire extremely heavy projectiles with large useful payload capacities.", MuzzleFlash = "howie_muzzleflash_noscale", - Spread = 0.12, + Spread = 0.1, Sound = "acf_base/weapons/howitzer_new2.mp3", Caliber = { Min = 75, diff --git a/lua/acf/shared/guns/machinegun.lua b/lua/acf/shared/guns/machinegun.lua index afe12f2d6..181862cb7 100644 --- a/lua/acf/shared/guns/machinegun.lua +++ b/lua/acf/shared/guns/machinegun.lua @@ -70,7 +70,7 @@ ACF.RegisterWeaponClass("MG", { Name = "Machinegun", Description = "Machineguns are light guns that fire equally light bullets at a fast rate.", MuzzleFlash = "mg_muzzleflash_noscale", - Spread = 0.24, + Spread = 0.16, Sound = "acf_base/weapons/mg_fire4.mp3", Caliber = { Min = 5.56, diff --git a/lua/acf/shared/guns/mortar.lua b/lua/acf/shared/guns/mortar.lua index 7dfce2dc4..bb4a689c0 100644 --- a/lua/acf/shared/guns/mortar.lua +++ b/lua/acf/shared/guns/mortar.lua @@ -103,7 +103,7 @@ ACF.RegisterWeaponClass("MO", { Name = "Mortar", Description = "Mortars are able to fire shells with usefull payloads from a light weight gun, at the price of limited velocities.", MuzzleFlash = "mortar_muzzleflash_noscale", - Spread = 0.64, + Spread = 0.72, Sound = "acf_base/weapons/mortar_new.mp3", Caliber = { Min = 37, diff --git a/lua/acf/shared/guns/rotaryautocannon.lua b/lua/acf/shared/guns/rotaryautocannon.lua index 2d1e929c2..3655428b9 100644 --- a/lua/acf/shared/guns/rotaryautocannon.lua +++ b/lua/acf/shared/guns/rotaryautocannon.lua @@ -69,7 +69,7 @@ ACF.RegisterWeaponClass("RAC", { Name = "Rotary Autocannon", Description = "Rotary Autocannons sacrifice weight, bulk and accuracy over classic autocannons to get the highest rate of fire possible.", MuzzleFlash = "mg_muzzleflash_noscale", - Spread = 0.4, + Spread = 0.48, Sound = "acf_base/weapons/mg_fire3.mp3", Caliber = { Min = 7.62, diff --git a/lua/acf/shared/guns/semiauto.lua b/lua/acf/shared/guns/semiauto.lua index c86bce590..8fceb0aca 100644 --- a/lua/acf/shared/guns/semiauto.lua +++ b/lua/acf/shared/guns/semiauto.lua @@ -106,7 +106,7 @@ ACF.RegisterWeaponClass("SA", { Name = "Semiautomatic Cannon", Description = "Semiautomatic cannons offer light weight, small size, and high rates of fire at the cost of often reloading and low accuracy.", MuzzleFlash = "semi_muzzleflash_noscale", - Spread = 1.1, + Spread = 0.12, Sound = "acf_base/weapons/sa_fire1.mp3", Caliber = { Min = 20, diff --git a/lua/acf/shared/guns/shortcannon.lua b/lua/acf/shared/guns/shortcannon.lua index 128e6828b..5a873a957 100644 --- a/lua/acf/shared/guns/shortcannon.lua +++ b/lua/acf/shared/guns/shortcannon.lua @@ -103,7 +103,7 @@ ACF.RegisterWeaponClass("SC", { Name = "Short-Barrelled Cannon", Description = "Short cannons trade muzzle velocity and accuracy for lighter weight and smaller size, with more penetration than howitzers and lighter than cannons.", MuzzleFlash = "cannon_muzzleflash_noscale", - Spread = 0.2, + Spread = 0.16, Sound = "acf_base/weapons/cannon_new.mp3", Caliber = { Min = 37, diff --git a/lua/entities/acf_ammo/init.lua b/lua/entities/acf_ammo/init.lua index 8b4052374..5bece054f 100644 --- a/lua/entities/acf_ammo/init.lua +++ b/lua/entities/acf_ammo/init.lua @@ -577,9 +577,9 @@ do -- Metamethods ------------------------------- WireLib.AddOutputAlias("Munitions", "Ammo") ACF.AddInputAction("acf_ammo", "Load", function(Entity, Value) - Entity.Load = Entity.Ammo ~= 0 and tobool(Value) + Entity.Load = tobool(Value) - WireLib.TriggerOutput(Entity, "Loading", Entity.Load and 1 or 0) + WireLib.TriggerOutput(Entity, "Loading", Entity:CanConsume() and 1 or 0) end) function ENT:TriggerInput(Name, Value) diff --git a/lua/entities/acf_engine/init.lua b/lua/entities/acf_engine/init.lua index 2bba34b30..cfb68f78d 100644 --- a/lua/entities/acf_engine/init.lua +++ b/lua/entities/acf_engine/init.lua @@ -24,6 +24,10 @@ do ACF.RegisterClassUnlink("acf_engine", "acf_fueltank", function(Engine, Target) if Engine.FuelTanks[Target] or Target.Engines[Engine] then + if Engine.FuelTank == Target then + Engine.FuelTank = next(Engine.FuelTanks, Target) + end + Engine.FuelTanks[Target] = nil Target.Engines[Engine] = nil @@ -112,10 +116,9 @@ local TimerSimple = timer.Simple local TimerRemove = timer.Remove local Gamemode = GetConVar("acf_gamemode") -local function GetEfficiency(Entity) - local CompetitiveMult = Gamemode:GetInt() == 2 and ACF.CompFuelRate or 1 - - return ACF.Efficiency[Entity.EngineType] * CompetitiveMult +-- Fuel consumption is increased on competitive servers +local function GetEfficiencyMult() + return Gamemode:GetInt() == 2 and ACF.CompFuelRate or 1 end local function GetPitchVolume(Engine) @@ -129,9 +132,7 @@ end local function GetNextFuelTank(Engine) if not next(Engine.FuelTanks) then return end - local Current = Engine.FuelTank - local NextKey = (IsValid(Current) and Engine.FuelTanks[Current]) and Current or nil - local Select = next(Engine.FuelTanks, NextKey) or next(Engine.FuelTanks) + local Select = next(Engine.FuelTanks, Engine.FuelTank) or next(Engine.FuelTanks) local Start = Select repeat @@ -272,9 +273,10 @@ do -- Spawn and Update functions Entity.FuelTypes = EngineData.Fuel or { Petrol = true } Entity.FuelType = next(EngineData.Fuel) Entity.EngineType = EngineType.ID - Entity.Efficiency = EngineType.Efficiency + Entity.Efficiency = EngineType.Efficiency * GetEfficiencyMult() Entity.TorqueScale = EngineType.TorqueScale Entity.HealthMult = EngineType.HealthMult + Entity.HitBoxes = ACF.HitBoxes[EngineData.Model] Entity.Out = Entity:WorldToLocal(Entity:GetAttachment(Entity:LookupAttachment("driveshaft")).Pos) Entity:SetNWString("WireName", "ACF " .. Entity.Name) @@ -351,6 +353,14 @@ do -- Spawn and Update functions Class.OnSpawn(Engine, Data, Class, EngineData) end + do -- Mass entity mod removal + local EntMods = Data and Data.EntityMods + + if EntMods and EntMods.mass then + EntMods.mass = nil + end + end + CheckLegal(Engine) return Engine diff --git a/lua/entities/acf_fueltank/init.lua b/lua/entities/acf_fueltank/init.lua index 966d19c7f..2ba4cbfaf 100644 --- a/lua/entities/acf_fueltank/init.lua +++ b/lua/entities/acf_fueltank/init.lua @@ -19,6 +19,15 @@ local TimerCreate = timer.Create local TimerExists = timer.Exists local Wall = 0.03937 --wall thickness in inches (1mm) +local function CanRefuel(Refill, Tank, Distance) + if Refill.FuelType ~= Tank.FuelType then return false end + if Tank.Disabled then return false end + if Tank.SupplyFuel then return false end + if Tank.Fuel >= Tank.Capacity then return false end + + return Distance <= RefillDist +end + --===============================================================================================-- do -- Spawn and Update functions @@ -70,7 +79,7 @@ do -- Spawn and Update functions Entity.Volume = PhysObj:GetVolume() - (Area * Wall) -- total volume of tank (cu in), reduced by wall thickness Entity.Capacity = Entity.Volume * ACF.CuIToLiter * ACF.TankVolumeMul * 0.4774 --internal volume available for fuel in liters, with magic realism number Entity.EmptyMass = (Area * Wall) * 16.387 * (7.9 / 1000) -- total wall volume * cu in to cc * density of steel (kg/cc) - Entity.IsExplosive = Entity.FuelType ~= "Electric" and FuelTank.IsExplosive + Entity.IsExplosive = FuelTank.IsExplosive Entity.NoLinks = FuelTank.Unlinkable Entity.HitBoxes = { Main = { @@ -94,6 +103,9 @@ do -- Spawn and Update functions Entity:UpdateMass(true) Entity:UpdateOverlay(true) + + WireLib.TriggerOutput(Entity, "Fuel", Entity.Fuel) + WireLib.TriggerOutput(Entity, "Capacity", Entity.Capacity) end function MakeACF_FuelTank(Player, Pos, Angle, Data) @@ -119,12 +131,11 @@ do -- Spawn and Update functions Tank.Owner = Player -- MUST be stored on ent for PP Tank.Engines = {} - Tank.Active = true Tank.Leaking = 0 Tank.CanUpdate = true Tank.LastThink = 0 Tank.Inputs = WireLib.CreateInputs(Tank, { "Active", "Refuel Duty" }) - Tank.Outputs = WireLib.CreateOutputs(Tank, { "Fuel", "Capacity", "Leaking", "Entity [ENTITY]" }) + Tank.Outputs = WireLib.CreateOutputs(Tank, { "Activated", "Fuel", "Capacity", "Leaking", "Entity [ENTITY]" }) Tank.DataStore = ACF.GetEntClassVars("acf_fueltank") WireLib.TriggerOutput(Tank, "Entity", Tank) @@ -137,6 +148,17 @@ do -- Spawn and Update functions Class.OnSpawn(Tank, Data, Class, FuelTank) end + do -- Mass entity mod removal + local EntMods = Data and Data.EntityMods + + if EntMods and EntMods.mass then + EntMods.mass = nil + end + end + + -- Fuel tanks should be active by default + Tank:TriggerInput("Active", 1) + CheckLegal(Tank) return Tank @@ -363,7 +385,7 @@ do -- Overlay Update if Ent.Leaking > 0 then Text = "Leaking" else - Text = Ent.Active and "Providing Fuel" or "Idle" + Text = Ent:CanConsume() and "Providing Fuel" or "Idle" end Text = Text .. "\n\nFuel Type: " .. Ent.FuelType @@ -393,34 +415,29 @@ do -- Overlay Update return Overlay(self) end - if TimerExists("ACF Overlay Buffer" .. self:EntIndex()) then -- This entity has been updated too recently - self.OverlayBuffer = true -- Mark it to update when buffer time has expired - else - TimerCreate("ACF Overlay Buffer" .. self:EntIndex(), 1, 1, function() - if IsValid(self) and self.OverlayBuffer then - self.OverlayBuffer = nil - self:UpdateOverlay() - end - end) + if TimerExists("ACF Overlay Buffer" .. self:EntIndex()) then -- This entity has been updated too recently + self.OverlayBuffer = true -- Mark it to update when buffer time has expired + else + TimerCreate("ACF Overlay Buffer" .. self:EntIndex(), 1, 1, function() + if IsValid(self) and self.OverlayBuffer then + self.OverlayBuffer = nil + self:UpdateOverlay() + end + end) - Overlay(self) + Overlay(self) + end end end ACF.AddInputAction("acf_fueltank", "Active", function(Entity, Value) - if not Entity.Inputs.Active.Path then - Value = true - end - Entity.Active = tobool(Value) - print(Entity, Entity.Active) + WireLib.TriggerOutput(Entity, "Activated", Entity:CanConsume() and 1 or 0) end) ACF.AddInputAction("acf_fueltank", "Refuel Duty", function(Entity, Value) - local N = math.Clamp(tonumber(Value), 0, 2) - - Entity.SupplyFuel = N ~= 0 and N + Entity.SupplyFuel = tobool(Value) or nil end) function ENT:TriggerInput(Name, Value) diff --git a/lua/entities/acf_gearbox/init.lua b/lua/entities/acf_gearbox/init.lua index cad4457b6..844127996 100644 --- a/lua/entities/acf_gearbox/init.lua +++ b/lua/entities/acf_gearbox/init.lua @@ -375,6 +375,7 @@ do -- Spawn and Update functions Entity.In = Entity:WorldToLocal(Entity:GetAttachment(Entity:LookupAttachment("input")).Pos) Entity.OutL = Entity:WorldToLocal(Entity:GetAttachment(Entity:LookupAttachment("driveshaftL")).Pos) Entity.OutR = Entity:WorldToLocal(Entity:GetAttachment(Entity:LookupAttachment("driveshaftR")).Pos) + Entity.HitBoxes = ACF.HitBoxes[Gearbox.Model] CreateInputs(Entity) CreateOutputs(Entity) @@ -425,7 +426,15 @@ do -- Spawn and Update functions local Phys = Entity:GetPhysicsObject() if IsValid(Phys) then Phys:SetMass(Gearbox.Mass) end - ChangeGear(Entity, 1) + -- Force gearbox to forget its gear and drive + Entity.Drive = nil + Entity.Gear = nil + + if Entity.Auto then + ChangeDrive(Entity, 1) + else + ChangeGear(Entity, 1) + end Entity:UpdateOverlay(true) end @@ -461,7 +470,6 @@ do -- Spawn and Update functions Gearbox.LBrake = 0 Gearbox.RBrake = 0 Gearbox.SteerRate = 0 - Gearbox.Gear = 0 Gearbox.ChangeFinished = 0 Gearbox.InGear = false Gearbox.LastActive = 0 @@ -473,6 +481,14 @@ do -- Spawn and Update functions Class.OnSpawn(Gearbox, Data, Class, GearboxData) end + do -- Mass entity mod removal + local EntMods = Data and Data.EntityMods + + if EntMods and EntMods.mass then + EntMods.mass = nil + end + end + CheckLegal(Gearbox) timer.Create("ACF Gearbox Clock " .. Gearbox:EntIndex(), 3, 0, function() diff --git a/lua/entities/acf_gun/init.lua b/lua/entities/acf_gun/init.lua index 2d31d3daa..e9f87a3a5 100644 --- a/lua/entities/acf_gun/init.lua +++ b/lua/entities/acf_gun/init.lua @@ -159,6 +159,14 @@ do -- Spawn and Update functions -------------------------------- Class.OnSpawn(Gun, Data, Class, Weapon) end + do -- Mass entity mod removal + local EntMods = Data and Data.EntityMods + + if EntMods and EntMods.mass then + EntMods.mass = nil + end + end + TimerCreate("ACF Ammo Left " .. Gun:EntIndex(), 1, 0, function() if not IsValid(Gun) then return end @@ -250,6 +258,10 @@ do -- Metamethods -------------------------------- ACF.RegisterClassUnlink("acf_gun", "acf_ammo", function(Weapon, Target) if Weapon.Crates[Target] or Target.Weapons[Weapon] then + if Weapon.CurrentCrate == Target then + Weapon.CurrentCrate = next(Weapon.Crates, Target) + end + Weapon.Crates[Target] = nil Target.Weapons[Weapon] = nil @@ -511,9 +523,7 @@ do -- Metamethods -------------------------------- if not next(Gun.Crates) then return end -- Find the next available crate to pull ammo from -- - local Current = Gun.CurrentCrate - local NextKey = (IsValid(Current) and Gun.Crates[Current]) and Current or nil - local Select = next(Gun.Crates, NextKey) or next(Gun.Crates) + local Select = next(Gun.Crates, Gun.CurrentCrate) or next(Gun.Crates) local Start = Select repeat @@ -726,6 +736,30 @@ do -- Metamethods -------------------------------- end ----------------------------------------- do -- Misc ---------------------------------- + function ENT:ACF_Activate(Recalc) + local PhysObj = self.ACF.PhysObj + + if not self.ACF.Area then + self.ACF.Area = PhysObj:GetSurfaceArea() * 6.45 + end + + local Volume = PhysObj:GetVolume() * 2 + + local Armour = self.Caliber * 10 + local Health = Volume / ACF.Threshold --Setting the threshold of the prop Area gone + local Percent = 1 + + if Recalc and self.ACF.Health and self.ACF.MaxHealth then + Percent = self.ACF.Health / self.ACF.MaxHealth + end + + self.ACF.Health = Health * Percent + self.ACF.MaxHealth = Health + self.ACF.Armour = Armour * (0.5 + Percent * 0.5) + self.ACF.MaxArmour = Armour + self.ACF.Type = "Prop" + end + function ENT:SetState(State) self.State = State From 1f06bfffca578895aaba204a2ed3b8c8ddba8c9a Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Mon, 7 Sep 2020 04:41:46 -0300 Subject: [PATCH 122/279] Added argument to ENT:OnResized - On the scalable_entity base, ENT:OnResized will now receive the new size as an argument. - Removed the now unused ENT.Volume propriety on ammo crates that was only used by racks. - Changed some cases where the values of a vector would be retrieved with the numerical index instead of the axis name. --- lua/entities/acf_ammo/cl_init.lua | 6 +++--- lua/entities/acf_ammo/init.lua | 22 +++++++--------------- lua/entities/base_scalable/cl_init.lua | 2 +- lua/entities/base_scalable/init.lua | 2 +- 4 files changed, 12 insertions(+), 20 deletions(-) diff --git a/lua/entities/acf_ammo/cl_init.lua b/lua/entities/acf_ammo/cl_init.lua index 3ec59c4ad..d9663eab3 100644 --- a/lua/entities/acf_ammo/cl_init.lua +++ b/lua/entities/acf_ammo/cl_init.lua @@ -74,12 +74,12 @@ function ENT:RequestAmmoData() net.SendToServer() end -function ENT:OnResized() +function ENT:OnResized(Size) self.HitBoxes = { Main = { Pos = self:OBBCenter(), - Scale = self:GetSize(), - Angle = Angle(0, 0, 0), + Scale = Size, + Angle = Angle(), Sensitive = false } } diff --git a/lua/entities/acf_ammo/init.lua b/lua/entities/acf_ammo/init.lua index 5bece054f..039c8df2f 100644 --- a/lua/entities/acf_ammo/init.lua +++ b/lua/entities/acf_ammo/init.lua @@ -382,6 +382,7 @@ local function UpdateAmmoData(Entity, Data1, Data2, Data3, Data4, Data5, Data6, if AmmoData and not (Data11 or Data12 or Data13) then local NewPos = Entity:LocalToWorld(AmmoData.Offset) + local Size = AmmoData.Size Entity:SetPos(NewPos) @@ -391,9 +392,9 @@ local function UpdateAmmoData(Entity, Data1, Data2, Data3, Data4, Data5, Data6, Data.BuildDupeInfo.PosReset = NewPos end - Data11 = AmmoData.Size[1] - Data12 = AmmoData.Size[2] - Data13 = AmmoData.Size[3] + Data11 = Size.x + Data12 = Size.y + Data13 = Size.z end end @@ -877,13 +878,11 @@ do -- Metamethods ------------------------------- return true, Message end - function ENT:OnResized() - local Size = self:GetSize() - + function ENT:OnResized(Size) do -- Calculate new empty mass local A = ACF.AmmoArmor * 0.039 -- Millimeters to inches - local ExteriorVolume = Size[1] * Size[2] * Size[3] - local InteriorVolume = (Size[1] - A) * (Size[2] - A) * (Size[3] - A) -- Math degree + local ExteriorVolume = Size.x * Size.y * Size.z + local InteriorVolume = (Size.x - A) * (Size.y - A) * (Size.z - A) -- Math degree local Volume = ExteriorVolume - InteriorVolume local Mass = Volume * 0.13 -- Kg of steel per inch @@ -898,13 +897,6 @@ do -- Metamethods ------------------------------- } } - -- TODO: Remove as soon as racks are improved, this is only being readded because of them - local PhysObj = self:GetPhysicsObject() - - if IsValid(PhysObj) then - self.Volume = PhysObj:GetVolume() * 0.1576 * ACF.AmmoMod - end - self:UpdateOverlay() end diff --git a/lua/entities/base_scalable/cl_init.lua b/lua/entities/base_scalable/cl_init.lua index c8dba0a65..a5349cb29 100644 --- a/lua/entities/base_scalable/cl_init.lua +++ b/lua/entities/base_scalable/cl_init.lua @@ -44,7 +44,7 @@ function ENT:SetSize(NewSize) local PhysObj = self:GetPhysicsObject() if IsValid(PhysObj) then - if self.OnResized then self:OnResized() end + if self.OnResized then self:OnResized(NewSize) end hook.Run("OnEntityResized", self, PhysObj, NewSize) end diff --git a/lua/entities/base_scalable/init.lua b/lua/entities/base_scalable/init.lua index 3a84e68fb..41189f949 100644 --- a/lua/entities/base_scalable/init.lua +++ b/lua/entities/base_scalable/init.lua @@ -105,7 +105,7 @@ function ENT:SetSize(NewSize) local PhysObj = self:GetPhysicsObject() if IsValid(PhysObj) then - if self.OnResized then self:OnResized() end + if self.OnResized then self:OnResized(NewSize) end hook.Run("OnEntityResized", self, PhysObj, NewSize) end From ddc4c1cbf8608d7d7b6e220f03777ff32cfd54ba Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Mon, 7 Sep 2020 04:58:26 -0300 Subject: [PATCH 123/279] Fixed electric engine and fuel types - Fixed electric engine and fuel types due to them still using the removed ACF.ElecRate global variable. --- lua/acf/shared/engine_types/electric.lua | 2 +- lua/acf/shared/fuel_types/electric.lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lua/acf/shared/engine_types/electric.lua b/lua/acf/shared/engine_types/electric.lua index 13bc17cdd..11d39fd65 100644 --- a/lua/acf/shared/engine_types/electric.lua +++ b/lua/acf/shared/engine_types/electric.lua @@ -12,6 +12,6 @@ ACF.RegisterEngineType("Electric", { end, CalculateFuelUsage = function(Entity) -- Electric engines use current power output, not max - return ACF.ElecRate / Entity.Efficiency * 3600 + return ACF.FuelRate / Entity.Efficiency * 3600 end }) diff --git a/lua/acf/shared/fuel_types/electric.lua b/lua/acf/shared/fuel_types/electric.lua index 4e32a1dd8..e875b9812 100644 --- a/lua/acf/shared/fuel_types/electric.lua +++ b/lua/acf/shared/fuel_types/electric.lua @@ -3,7 +3,7 @@ ACF.RegisterFuelType("Electric", { Density = 3.89, ConsumptionText = function(PeakkW, _, TypeData) local Text = "\n\nPeak Energy Consumption :\n%s kW - %s MJ/min" - local Rate = ACF.ElecRate * PeakkW / TypeData.Efficiency + local Rate = ACF.FuelRate * PeakkW / TypeData.Efficiency return Text:format(math.Round(Rate, 2), math.Round(Rate * 0.06, 2)) end, From 950c185f65a00d4d640ada28467c2140238fc300 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Mon, 7 Sep 2020 05:23:02 -0300 Subject: [PATCH 124/279] Vastly increased ammo refilling speed - Increased ammo refilling speed by a great margin as it now takes the ACF.RefillSpeed variable into account. --- lua/entities/acf_ammo/init.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/entities/acf_ammo/init.lua b/lua/entities/acf_ammo/init.lua index 039c8df2f..67993598d 100644 --- a/lua/entities/acf_ammo/init.lua +++ b/lua/entities/acf_ammo/init.lua @@ -59,7 +59,7 @@ local function RefillCrates(Refill) local Distance = Position:DistToSqr(Crate:GetPos()) if CanRefillCrate(Refill, Crate, Distance) then - local Supply = math.ceil((50000 / ((Crate.BulletData.ProjMass + Crate.BulletData.PropMass) * 1000)) / Distance ^ 0.5) + local Supply = math.ceil(ACF.RefillSpeed / Crate.BulletData.CartMass / Distance ^ 0.5) local Transfer = math.min(Supply, Refill.Ammo, Crate.Capacity - Crate.Ammo) if hook.Run("ACF_CanRefill", Refill, Crate, Transfer) == false then continue end From 44ffb23b6910768d9e31bc57354ac38fe97d1ac6 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Tue, 8 Sep 2020 05:58:21 -0300 Subject: [PATCH 125/279] Added ACF_DrawBoxes hook - Added ACF_DrawBoxes hook on the clientside, it's called whenever the new ACF Menu tool is out and the player is staring at an entity from a reasonable distance while the acf_drawboxes convar is enabled. This will make it easier to implement more HUD info with the new menu. - Updated box displays on the new menu tool. - Fixed clientside ammo updating using an old value when called from the networked var proxy. - Fixed acf_maxroundsdisplay callback for clientside not working at all due the function being case sensitive. - Ammo crates will now properly clean their clientside convar change callback when removed. - Removed some unused code from ammo crates. - Reduced ammo count networking cooldown to half a second. --- lua/entities/acf_ammo/cl_init.lua | 105 +++++++++++++++++---- lua/entities/acf_ammo/init.lua | 2 +- lua/weapons/gmod_tool/stools/acf_menu2.lua | 31 ++++-- 3 files changed, 108 insertions(+), 30 deletions(-) diff --git a/lua/entities/acf_ammo/cl_init.lua b/lua/entities/acf_ammo/cl_init.lua index d9663eab3..fcf20e259 100644 --- a/lua/entities/acf_ammo/cl_init.lua +++ b/lua/entities/acf_ammo/cl_init.lua @@ -1,12 +1,11 @@ include("shared.lua") -local RoundsDisplayCVar = GetConVar("ACF_MaxRoundsDisplay") +local MaxRounds = GetConVar("acf_maxroundsdisplay") local HideInfo = ACF.HideInfoBubble -local Distance = ACF.RefillDistance local Refills = {} local Queued = {} -local function UpdateClAmmo(Entity) +local function UpdateAmmoCount(Entity, Ammo) if not IsValid(Entity) then return end if not Entity.HasData then if Entity.HasData == nil then @@ -16,13 +15,11 @@ local function UpdateClAmmo(Entity) return end - local MaxDisplayRounds = RoundsDisplayCVar:GetInt() + local MaxDisplayRounds = MaxRounds:GetInt() - Entity.Ammo = math.Clamp(Entity:GetNWInt("Ammo", 0), 0, Entity.Capacity) - - local FinalAmmo = Entity.HasBoxedAmmo and math.floor(Entity.Ammo / Entity.MagSize) or Entity.Ammo - - Entity.BulkDisplay = FinalAmmo > MaxDisplayRounds + Entity.Ammo = Ammo or Entity:GetNWInt("Ammo", 0) + Entity.FinalAmmo = Entity.HasBoxedAmmo and math.floor(Entity.Ammo / Entity.MagSize) or Entity.Ammo + Entity.BulkDisplay = Entity.FinalAmmo > MaxDisplayRounds end net.Receive("ACF_RequestAmmoData", function() @@ -48,19 +45,18 @@ net.Receive("ACF_RequestAmmoData", function() Queued[Entity] = nil end - UpdateClAmmo(Entity) + UpdateAmmoCount(Entity) end) function ENT:Initialize() - self:SetNWVarProxy("Ammo", function() - UpdateClAmmo(self) + self:SetNWVarProxy("Ammo", function(_, _, _, Ammo) + UpdateAmmoCount(self, Ammo) end) - cvars.AddChangeCallback("ACF_MaxRoundsDisplay", function() - UpdateClAmmo(self) - end) + cvars.AddChangeCallback("acf_maxroundsdisplay", function() + UpdateAmmoCount(self) + end, "Ammo Crate " .. self:EntIndex()) - self.DrawAmmoHookIndex = "draw_ammo_" .. self:EntIndex() self.BaseClass.Initialize(self) end @@ -107,11 +103,14 @@ end function ENT:OnRemove() Refills[self] = nil - hook.Remove("PostDrawOpaqueRenderables",self.DrawAmmoHookIndex) + cvars.RemoveChangeCallback("acf_maxroundsdisplay", "Ammo Crate " .. self:EntIndex()) end -- TODO: Resupply effect library, should apply for both ammo and fuel do -- Resupply effect + local Yellow = Color(255, 255, 0, 10) + local Distance = ACF.RefillDistance + net.Receive("ACF_RefillEffect", function() local Refill = net.ReadEntity() @@ -132,8 +131,76 @@ do -- Resupply effect render.SetColorMaterial() for Refill in pairs(Refills) do - render.DrawSphere(Refill:GetPos(), Distance, 50, 50, Color(255, 255, 0, 10)) - render.DrawSphere(Refill:GetPos(), -Distance, 50, 50, Color(255, 255, 0, 10)) + local Pos = Refill:GetPos() + + render.DrawSphere(Pos, Distance, 50, 50, Yellow) + render.DrawSphere(Pos, -Distance, 50, 50, Yellow) + end + end) +end + +do -- Ammo overlay + -- Ammo overlay colors + local Blue = Color(0, 127, 255, 65) + local Orange = Color(255, 127, 0, 65) + local Green = Color(0, 255, 0, 65) + local Red = Color(255, 0, 0, 65) + + local function GetPosition(X, Y, Z, RoundSize, Spacing, RoundAngle, Direction) + local SizeX = (X - 1) * (RoundSize.x + Spacing) * RoundAngle:Forward() * Direction + local SizeY = (Y - 1) * (RoundSize.y + Spacing) * RoundAngle:Right() * Direction + local SizeZ = (Z - 1) * (RoundSize.z + Spacing) * RoundAngle:Up() * Direction + + return SizeX + SizeY + SizeZ + end + + local function DrawRounds(Entity, Center, Spacing, Fits, RoundSize, RoundAngle, Total) + local Count = 0 + + local StartPos = GetPosition(Fits.x, Fits.y, Fits.z, RoundSize, Spacing, RoundAngle, 1) * 0.5 + + for X = 1, Fits.x do + for Y = 1, Fits.y do + for Z = 1, Fits.z do + local LocalPos = GetPosition(X, Y, Z, RoundSize, Spacing, RoundAngle, -1) + local C = Entity.IsRound and Blue or Entity.HasBoxedAmmo and Green or Orange + + render.DrawWireframeBox(Center + StartPos + LocalPos, RoundAngle, -RoundSize * 0.5, RoundSize * 0.5, C) + + Count = Count + 1 + + if Count == Total then return end + end + end + end + end + + hook.Add("ACF_DrawBoxes", "ACF Draw Ammo", function(Entity) + if not Entity.IsScalable then return end + if not Entity.HasData then + if Entity.HasData == nil and Entity.RequestAmmoData then + Entity:RequestAmmoData() + end + + return + end + if Entity.FinalAmmo <= 0 then return end + + local RoundAngle = Entity:LocalToWorldAngles(Entity.LocalAng) + local Center = Entity:LocalToWorld(Entity:OBBCenter()) + local RoundSize = Entity.RoundSize + local Spacing = Entity.Spacing + local Fits = Entity.FitPerAxis + + if not Entity.BulkDisplay then + DrawRounds(Entity, Center, Spacing, Fits, RoundSize, RoundAngle, Entity.FinalAmmo) + else -- Basic bitch box that scales according to ammo, only for bulk display + local AmmoPerc = Entity.Ammo / Entity.Capacity + local SizeAdd = Vector(Spacing, Spacing, Spacing) * Fits + local BulkSize = ((Fits * RoundSize * Vector(1, AmmoPerc, 1)) + SizeAdd) * 0.5 + local Offset = RoundAngle:Right() * (Fits.y * RoundSize.y) * 0.5 * (1 - AmmoPerc) + + render.DrawWireframeBox(Center + Offset, RoundAngle, -BulkSize, BulkSize, Red) end end) end diff --git a/lua/entities/acf_ammo/init.lua b/lua/entities/acf_ammo/init.lua index 67993598d..4183be93e 100644 --- a/lua/entities/acf_ammo/init.lua +++ b/lua/entities/acf_ammo/init.lua @@ -719,7 +719,7 @@ do -- Metamethods ------------------------------- if TimerExists("ACF Network Ammo " .. self:EntIndex()) then return end - TimerCreate("ACF Network Ammo " .. self:EntIndex(), 1, 1, function() + TimerCreate("ACF Network Ammo " .. self:EntIndex(), 0.5, 1, function() if not IsValid(self) then return end self:SetNWInt("Ammo", self.Ammo) diff --git a/lua/weapons/gmod_tool/stools/acf_menu2.lua b/lua/weapons/gmod_tool/stools/acf_menu2.lua index 8dd72a46b..3b60960cf 100644 --- a/lua/weapons/gmod_tool/stools/acf_menu2.lua +++ b/lua/weapons/gmod_tool/stools/acf_menu2.lua @@ -8,24 +8,23 @@ cleanup.Register("acfmenu") if CLIENT then local DrawBoxes = GetConVar("acf_drawboxes") + -- "Hitbox" colors + local Sensitive = Color(255, 0, 0, 50) + local NotSoSensitive = Color(255, 255, 0, 50) + language.Add("Tool.acf_menu2.name", "Armored Combat Framework") language.Add("Tool.acf_menu2.desc", "Testing the new menu tool") function TOOL:DrawHUD() - if not DrawBoxes:GetBool() then return end - - local Ent = LocalPlayer():GetEyeTrace().Entity - - if not IsValid(Ent) then return end - if not Ent.HitBoxes then return end + local Trace = LocalPlayer():GetEyeTrace() + local Distance = Trace.StartPos:DistToSqr(Trace.HitPos) + local Entity = Trace.Entity cam.Start3D() render.SetColorMaterial() - for _, Tab in pairs(Ent.HitBoxes) do - local BoxColor = Tab.Sensitive and Color(214, 160, 190, 50) or Color(160, 190, 215, 50) - - render.DrawBox(Ent:LocalToWorld(Tab.Pos), Ent:LocalToWorldAngles(Tab.Angle), Tab.Scale * -0.5, Tab.Scale * 0.5, BoxColor) + if DrawBoxes:GetBool() and IsValid(Entity) and Distance <= 65536 then + hook.Run("ACF_DrawBoxes", Entity, Trace) end cam.End3D() @@ -38,4 +37,16 @@ if CLIENT then ACF.BuildContextPanel(ACF.Menu.Panel) end) + + hook.Add("ACF_DrawBoxes", "ACF Draw Hitboxes", function(Entity) + if not Entity.HitBoxes then return end + if not next(Entity.HitBoxes) then return end + + for _, Tab in pairs(Entity.HitBoxes) do + local Pos = Entity:LocalToWorld(Tab.Pos) + local Ang = Entity:LocalToWorldAngles(Tab.Angle) + + render.DrawWireframeBox(Pos, Ang, Tab.Scale * -0.5, Tab.Scale * 0.5, Tab.Sensitive and Sensitive or NotSoSensitive) + end + end) end From 4e8c096f5dad124b34d90dd20be5e5194534b67d Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Thu, 10 Sep 2020 01:12:51 -0300 Subject: [PATCH 126/279] Improved Tool Data functions - All Tool Data ACF.ReadX functions received a new argument for a default value in case the desired key value fails to be found. - Added ACF.ReadRaw and ACF.ReadData functions, they will return the real data stored on the desired key without converting it to a specific type. --- lua/acf/base/util/cl_util.lua | 32 +++++++++++++------------- lua/acf/base/util/sv_util.lua | 42 +++++++++++++++-------------------- 2 files changed, 35 insertions(+), 39 deletions(-) diff --git a/lua/acf/base/util/cl_util.lua b/lua/acf/base/util/cl_util.lua index 0debfda28..b087546f6 100644 --- a/lua/acf/base/util/cl_util.lua +++ b/lua/acf/base/util/cl_util.lua @@ -81,31 +81,32 @@ do -- Tool data functions return Result end - function ACF.ReadBool(Key) - if not Key then return false end + local function ReadData(Key, Default) + if Key == nil then return end - return tobool(ToolData[Key]) - end + local Value = ToolData[Key] - function ACF.ReadNumber(Key) - if not Key then return 0 end + return Value ~= nil and Value or Default + end - local Data = ToolData[Key] + function ACF.ReadBool(Key, Default) + return tobool(ReadData(Key, Default)) + end - if Data == nil then return 0 end + function ACF.ReadNumber(Key, Default) + local Value = ReadData(Key, Default) - return tonumber(Data) + return Value ~= nil and tonumber(Value) or 0 -- tonumber can't handle nil values end function ACF.ReadString(Key) - if not Key then return "" end + local Value = ReadData(Key, Default) - local Data = ToolData[Key] - - if Data == nil then return "" end - - return tostring(Data) + return Value ~= nil and tostring(Value) or "" -- tostring can't handle nil values end + + ACF.ReadData = ReadData + ACF.ReadRaw = ReadData end do -- Write function @@ -119,6 +120,7 @@ do -- Tool data functions hook.Run("OnToolDataUpdate", Key, Value) + -- TODO: Replace with a queue system similar to the one used by the scalable base -- Allowing one network message per key per tick if timer.Exists("ACF WriteValue " .. Key) then return end diff --git a/lua/acf/base/util/sv_util.lua b/lua/acf/base/util/sv_util.lua index df7ad8907..f9b768b95 100644 --- a/lua/acf/base/util/sv_util.lua +++ b/lua/acf/base/util/sv_util.lua @@ -99,40 +99,34 @@ do -- Tool data functions return Result end - function ACF.ReadBool(Player, Key) - if not IsValid(Player) then return false end - if not Key then return false end - - local Data = ToolData[Player] + local function ReadData(Player, Key, Default) + if not IsValid(Player) then return end + if not ToolData[Player] then return end + if Key == nil then return end - if not Data then return false end + local Value = ToolData[Key] - return tobool(Data[Key]) + return Value ~= nil and Value or Default end - function ACF.ReadNumber(Player, Key) - if not IsValid(Player) then return 0 end - if not Key then return 0 end - - local Data = ToolData[Player] - - if not Data then return 0 end - if not Data[Key] then return 0 end - - return tonumber(Data[Key]) + function ACF.ReadBool(Player, Key, Default) + return tobool(ReadData(Player, Key, Default)) end - function ACF.ReadString(Player, Key) - if not IsValid(Player) then return "" end - if not Key then return "" end + function ACF.ReadNumber(Player, Key, Default) + local Value = ReadData(Player, Key, Default) - local Data = ToolData[Player] + return Value ~= nil and tonumber(Value) or 0 -- tonumber can't handle nil values + end - if not Data then return "" end - if not Data[Key] then return "" end + function ACF.ReadString(Player, Key, Default) + local Value = ReadData(Player, Key, Default) - return tostring(Data[Key]) + return Value ~= nil and tostring(Value) or "" -- tostring can't handle nil values end + + ACF.ReadData = ReadData + ACF.ReadRaw = ReadData end end From 574e535d98a299a574b72f078845b47900aeed43 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Thu, 10 Sep 2020 05:02:48 -0300 Subject: [PATCH 127/279] Removed ACF.SysTime - Removed ACF.SysTime entirely due to its implementation having no actual difference with ACF.CurTime --- lua/acf/base/acf_globals.lua | 1 - lua/acf/server/ballistics.lua | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/lua/acf/base/acf_globals.lua b/lua/acf/base/acf_globals.lua index 7dec801e6..3bba9e9ff 100644 --- a/lua/acf/base/acf_globals.lua +++ b/lua/acf/base/acf_globals.lua @@ -339,7 +339,6 @@ end ------------------------------------------------ --Stupid workaround red added to precache timescaling. hook.Add("Think", "Update ACF Internal Clock", function() ACF.CurTime = CurTime() - ACF.SysTime = SysTime() end) do -- Smoke/Wind ----------------------------------- diff --git a/lua/acf/server/ballistics.lua b/lua/acf/server/ballistics.lua index 57b4cd55b..ebdffac33 100644 --- a/lua/acf/server/ballistics.lua +++ b/lua/acf/server/ballistics.lua @@ -115,7 +115,7 @@ function ACF_CreateBullet(BulletData) Bullet.Index = ACF.CurBulletIndex Bullet.Accel = Vector(0, 0, GetConVar("sv_gravity"):GetInt() * -1) - Bullet.LastThink = ACF.SysTime + Bullet.LastThink = ACF.CurTime Bullet.FlightTime = 0 Bullet.TraceBackComp = 0 Bullet.Fuze = Bullet.Fuze and Bullet.Fuze + ACF.CurTime or nil -- Convert Fuze from fuze length to time of detonation @@ -162,13 +162,13 @@ function ACF_CalcBulletFlight(Index, Bullet, BackTraceOverride) Bullet.FlightTime = 0 end - local DeltaTime = ACF.SysTime - Bullet.LastThink + local DeltaTime = ACF.CurTime - Bullet.LastThink local Drag = Bullet.Flight:GetNormalized() * (Bullet.DragCoef * Bullet.Flight:LengthSqr()) / ACF.DragDiv Bullet.NextPos = Bullet.Pos + (Bullet.Flight * ACF.Scale * DeltaTime) Bullet.Flight = Bullet.Flight + (Bullet.Accel - Drag) * DeltaTime Bullet.StartTrace = Bullet.Pos - Bullet.Flight:GetNormalized() * (math.min(ACF.PhysMaxVel * 0.025, Bullet.FlightTime * Bullet.Flight:Length() - Bullet.TraceBackComp * DeltaTime)) - Bullet.LastThink = ACF.SysTime + Bullet.LastThink = ACF.CurTime Bullet.FlightTime = Bullet.FlightTime + DeltaTime Bullet.DeltaTime = DeltaTime From 72419b7bf1c4f83d7f108163a60d866353e0fe00 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Thu, 10 Sep 2020 05:05:11 -0300 Subject: [PATCH 128/279] Changed unit of ACF.MinFuzeCaliber - The global variable ACF.MinFuzeCaliber will now be defined in millimeters instead of centimeters. - New ammo definitions will now use ACF.MinFuzeCaliber instead of a hard-coded value. --- lua/acf/base/acf_globals.lua | 2 +- lua/acf/shared/ammo_types/he.lua | 2 +- lua/acf/shared/ammo_types/heat.lua | 2 +- lua/acf/shared/ammo_types/smoke.lua | 2 +- lua/acf/shared/rounds/he.lua | 2 +- lua/acf/shared/rounds/heat.lua | 2 +- lua/acf/shared/rounds/heatfs.lua | 2 +- lua/acf/shared/rounds/smoke.lua | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lua/acf/base/acf_globals.lua b/lua/acf/base/acf_globals.lua index 3bba9e9ff..345b78184 100644 --- a/lua/acf/base/acf_globals.lua +++ b/lua/acf/base/acf_globals.lua @@ -14,7 +14,7 @@ do -- ACF global vars ACF.SmokeWind = 5 + math.random() * 35 --affects the ability of smoke to be used for screening effect ACF.EnableKillicons = true -- Enable killicons overwriting. -- Fuzes - ACF.MinFuzeCaliber = 2 -- Minimum caliber that can be fuzed (centimeters) + ACF.MinFuzeCaliber = 20 -- Minimum caliber in millimeters that can be fuzed -- Reload Mechanics ACF.BaseReload = 1 -- Minimum reload time. Time it takes to move around a weightless projectile ACF.MassToTime = 0.2 -- Conversion of projectile mass to time be moved around diff --git a/lua/acf/shared/ammo_types/he.lua b/lua/acf/shared/ammo_types/he.lua index c8e6ed552..f73bfc954 100644 --- a/lua/acf/shared/ammo_types/he.lua +++ b/lua/acf/shared/ammo_types/he.lua @@ -52,7 +52,7 @@ function Ammo:BaseConvert(_, ToolData) Data.KETransfert = 0.1 --Kinetic energy transfert to the target for movement purposes Data.Ricochet = 60 --Base ricochet angle Data.DetonatorAngle = 80 - Data.CanFuze = Data.Caliber > 20 -- Can fuze on calibers > 20mm + Data.CanFuze = Data.Caliber > ACF.MinFuzeCaliber -- Can fuze on calibers > 20mm self:UpdateRoundData(ToolData, Data, GUIData) diff --git a/lua/acf/shared/ammo_types/heat.lua b/lua/acf/shared/ammo_types/heat.lua index ad586e6f3..b0ebef0fb 100644 --- a/lua/acf/shared/ammo_types/heat.lua +++ b/lua/acf/shared/ammo_types/heat.lua @@ -105,7 +105,7 @@ function Ammo:BaseConvert(_, ToolData) Data.DetonatorAngle = 75 Data.Detonated = false Data.NotFirstPen = false - Data.CanFuze = Data.Caliber > 20 -- Can fuze on calibers > 20mm + Data.CanFuze = Data.Caliber > ACF.MinFuzeCaliber -- Can fuze on calibers > 20mm self:UpdateRoundData(ToolData, Data, GUIData) diff --git a/lua/acf/shared/ammo_types/smoke.lua b/lua/acf/shared/ammo_types/smoke.lua index 1216055f1..a7afa348b 100644 --- a/lua/acf/shared/ammo_types/smoke.lua +++ b/lua/acf/shared/ammo_types/smoke.lua @@ -74,7 +74,7 @@ function Ammo:BaseConvert(_, ToolData) Data.KETransfert = 0.1 --Kinetic energy transfert to the target for movement purposes Data.Ricochet = 60 --Base ricochet angle Data.DetonatorAngle = 80 - Data.CanFuze = Data.Caliber > 20 -- Can fuze on calibers > 20mm + Data.CanFuze = Data.Caliber > ACF.MinFuzeCaliber -- Can fuze on calibers > 20mm self:UpdateRoundData(ToolData, Data, GUIData) diff --git a/lua/acf/shared/rounds/he.lua b/lua/acf/shared/rounds/he.lua index fde0cc7cb..c4c4d522c 100644 --- a/lua/acf/shared/rounds/he.lua +++ b/lua/acf/shared/rounds/he.lua @@ -49,7 +49,7 @@ function Round.convert(_, PlayerData) Data.KETransfert = 0.1 --Kinetic energy transfert to the target for movement purposes Data.Ricochet = 60 --Base ricochet angle Data.DetonatorAngle = 80 - Data.CanFuze = Data.Caliber > ACF.MinFuzeCaliber -- Can fuze on calibers > 20mm + Data.CanFuze = Data.Caliber > ACF.MinFuzeCaliber * 0.1 -- Can fuze on calibers > 20mm Data.CartMass = Data.PropMass + Data.ProjMass --Only the crates need this part diff --git a/lua/acf/shared/rounds/heat.lua b/lua/acf/shared/rounds/heat.lua index 1969e75a3..c186e0464 100644 --- a/lua/acf/shared/rounds/heat.lua +++ b/lua/acf/shared/rounds/heat.lua @@ -113,7 +113,7 @@ function Round.convert(_, PlayerData) Data.DetonatorAngle = 75 Data.Detonated = false Data.NotFirstPen = false - Data.CanFuze = Data.Caliber > ACF.MinFuzeCaliber -- Can fuze on calibers > 20mm + Data.CanFuze = Data.Caliber > ACF.MinFuzeCaliber * 0.1 -- Can fuze on calibers > 20mm Data.CartMass = Data.PropMass + Data.ProjMass --Only the crates need this part diff --git a/lua/acf/shared/rounds/heatfs.lua b/lua/acf/shared/rounds/heatfs.lua index cd0183211..6293698d6 100644 --- a/lua/acf/shared/rounds/heatfs.lua +++ b/lua/acf/shared/rounds/heatfs.lua @@ -123,7 +123,7 @@ function Round.convert(_, PlayerData) Data.Detonated = false Data.NotFirstPen = false - Data.CanFuze = Data.Caliber > ACF.MinFuzeCaliber -- Can fuze on calibers > 20mm + Data.CanFuze = Data.Caliber > ACF.MinFuzeCaliber * 0.1 -- Can fuze on calibers > 20mm Data.CartMass = Data.PropMass + Data.ProjMass --Only the crates need this part diff --git a/lua/acf/shared/rounds/smoke.lua b/lua/acf/shared/rounds/smoke.lua index b26a1e1c5..57f5a4060 100644 --- a/lua/acf/shared/rounds/smoke.lua +++ b/lua/acf/shared/rounds/smoke.lua @@ -55,7 +55,7 @@ function Round.convert(_, PlayerData) Data.KETransfert = 0.1 --Kinetic energy transfert to the target for movement purposes Data.Ricochet = 60 --Base ricochet angle Data.DetonatorAngle = 80 - Data.CanFuze = Data.Caliber > ACF.MinFuzeCaliber -- Can fuze on calibers > 20mm + Data.CanFuze = Data.Caliber > ACF.MinFuzeCaliber * 0.1 -- Can fuze on calibers > 20mm Data.CartMass = Data.PropMass + Data.ProjMass --Only the crates need this part From a1a5b6e9e55aed015c0bf200a292ad397de9cac2 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Thu, 10 Sep 2020 05:12:49 -0300 Subject: [PATCH 129/279] Reorganized console variables - Small reorganization to a few server-side only console variables. - Added acf_enable_workshop_content server-side console variable. It's enabled by default and allows for more important server content to be forced on clients. - Edited acf_enable_workshop_extras console variable. It's now disabled by default as its content isn't as relevant as the content added by acf_enable_workshop_content. - Renamed sbox_acf_restrictinfo console variable to acf_restrict_info. - Edited acf_drawboxes console variable to be enabled by default. --- lua/acf/base/acf_globals.lua | 32 ++++++++++++++----- lua/acf/client/menu_items/settings_menu.lua | 2 +- lua/entities/acf_gun/init.lua | 2 +- .../core/custom/acffunctions.lua | 2 +- lua/starfall/libs_sv/acffunctions.lua | 6 ++-- 5 files changed, 30 insertions(+), 14 deletions(-) diff --git a/lua/acf/base/acf_globals.lua b/lua/acf/base/acf_globals.lua index 345b78184..a490facb8 100644 --- a/lua/acf/base/acf_globals.lua +++ b/lua/acf/base/acf_globals.lua @@ -13,12 +13,15 @@ do -- ACF global vars ACF.PhysMaxVel = 4000 ACF.SmokeWind = 5 + math.random() * 35 --affects the ability of smoke to be used for screening effect ACF.EnableKillicons = true -- Enable killicons overwriting. + -- Fuzes ACF.MinFuzeCaliber = 20 -- Minimum caliber in millimeters that can be fuzed + -- Reload Mechanics ACF.BaseReload = 1 -- Minimum reload time. Time it takes to move around a weightless projectile ACF.MassToTime = 0.2 -- Conversion of projectile mass to time be moved around ACF.LengthToTime = 0.1 -- Conversion of projectile length to time -- Emulating the added difficulty of manipulating a longer projectile + -- External and Terminal Ballistics ACF.DragDiv = 80 --Drag fudge factor ACF.Scale = 1 --Scale factor for ACF in the game world @@ -40,6 +43,7 @@ do -- ACF global vars npc_strider = true, npc_dog = true } + -- Ammo ACF.AmmoArmor = 5 -- How many millimeters of armor ammo crates have ACF.AmmoPadding = 2 -- Millimeters of wasted space between rounds @@ -49,6 +53,7 @@ do -- ACF global vars ACF.PScale = 1 --Gun Propellant power expotential ACF.MVScale = 0.5 --Propellant to MV convertion expotential ACF.PDensity = 0.95 -- Propellant loading density (Density of propellant + volume lost due to packing density) + -- HE ACF.HEPower = 8000 --HE Filler power per KG in KJ ACF.HEDensity = 1.65 --HE Filler density (That's TNT density) @@ -63,6 +68,7 @@ do -- ACF global vars ACF.HEATBoomConvert = 1 / 3 -- percentage of filler that creates HE damage at detonation ACF.HEATMinCrush = 800 -- vel where crush starts, progressively converting round to raw HE ACF.HEATMaxCrush = 1200 -- vel where fully crushed + -- Debris ACF.ChildDebris = 50 -- higher is more debris props; Chance = ACF.ChildDebris / num_children; Only applies to children of acf-killed parent props ACF.DebrisIgniteChance = 0.25 @@ -76,10 +82,12 @@ do -- ACF global vars prop_physics = true, prop_vehicle_prisoner_pod = true } + -- Weapon Accuracy ACF.SpreadScale = 4 -- The maximum amount that damage can decrease a gun"s accuracy. Default 4x ACF.GunInaccuracyScale = 1 -- A multiplier for gun accuracy. Must be between 0.5 and 4 ACF.GunInaccuracyBias = 2 -- Higher numbers make shots more likely to be inaccurate. Choose between 0.5 to 4. Default is 2 (unbiased). + -- Fuel ACF.FuelRate = 1 --multiplier for fuel usage, 1.0 is approx real world ACF.CompFuelRate = 27.8 --Extra multiplier for fuel consumption on servers with acf_gamemode set to 2 (Competitive) @@ -129,11 +137,6 @@ end do -- ACF Convars/Callbacks ------------------------ CreateConVar("sbox_max_acf_ammo", 32) - CreateConVar("acf_meshvalue", 1) - CreateConVar("sbox_acf_restrictinfo", 1) -- 0=any, 1=owned - -- Cvars for recoil/he push - CreateConVar("acf_hepush", 1) - CreateConVar("acf_recoilpush", 1) -- New healthmod/armormod/ammomod cvars CreateConVar("acf_healthmod", 1) CreateConVar("acf_armormod", 1) @@ -161,10 +164,22 @@ if SERVER then util.AddNetworkString("ACF_RenderDamage") util.AddNetworkString("ACF_Notify") - CreateConVar("acf_enable_workshop_extras", 1, FCVAR_ARCHIVE, "Enable extra workshop content download for clients. Requires server restart on change.", 0, 1) + CreateConVar("acf_enable_workshop_content", 1, FCVAR_ARCHIVE, "Enable workshop content download for clients. Requires server restart on change.", 0, 1) + CreateConVar("acf_enable_workshop_extras", 0, FCVAR_ARCHIVE, "Enable extra workshop content download for clients. Requires server restart on change.", 0, 1) CreateConVar("acf_gamemode", 1, FCVAR_ARCHIVE + FCVAR_NOTIFY, "Sets the ACF gamemode of the server. 0 = Sandbox, 1 = Classic, 2 = Competitive", 0, 2) + CreateConVar("acf_restrict_info", 1, FCVAR_ARCHIVE, "If enabled, players will be only allowed to get info from entities they're allowed to mess with.", 0, 1) + CreateConVar("acf_hepush", 1, FCVAR_ARCHIVE, "Whether or not HE pushes on entities", 0, 1) CreateConVar("acf_kepush", 1, FCVAR_ARCHIVE, "Whether or not kinetic force pushes on entities", 0, 1) + CreateConVar("acf_recoilpush", 1, FCVAR_ARCHIVE, "Whether or not ACF guns apply recoil", 0, 1) + + -- Addon content ---------------------------- + local Content = GetConVar("acf_enable_workshop_content") + + if Content:GetBool() then + resource.AddWorkshop("2183798463") -- Playermodel seats + end + --------------------------------------------- -- Extra content ---------------------------- local Extras = GetConVar("acf_enable_workshop_extras") @@ -180,11 +195,12 @@ elseif CLIENT then CreateClientConVar("acf_mobilityropelinks", 1, true, true) CreateClientConVar("acf_maxroundsdisplay", 16, true, false, "Maximum rounds to display before using bulk display (0 to only display bulk)", 0, 5000) CreateClientConVar("acf_unparent_disabled_ents", 0, true, true, "If enabled, all entities disabled for Bad Parenting will be unparented.", 0, 1) - CreateClientConVar("acf_drawboxes", 0, true, false, "Whether or not to draw hitboxes on ACF entities", 0, 1) + CreateClientConVar("acf_drawboxes", 1, true, false, "Whether or not to draw hitboxes on ACF entities", 0, 1) CreateClientConVar("acf_legalhints", 1, true, true, "If enabled, ACF will throw a warning hint whenever an entity gets disabled.", 0, 1) -- Display Info Bubble ---------------------- local ShowInfo = GetConVar("acf_show_entity_info") + local LocalPly = LocalPlayer() function ACF.HideInfoBubble() local Value = ShowInfo:GetInt() @@ -192,7 +208,7 @@ elseif CLIENT then if Value == 0 then return true end if Value == 2 then return false end - return LocalPlayer():InVehicle() + return LocalPly:InVehicle() end --------------------------------------------- diff --git a/lua/acf/client/menu_items/settings_menu.lua b/lua/acf/client/menu_items/settings_menu.lua index 26cb8cfa9..796450c15 100644 --- a/lua/acf/client/menu_items/settings_menu.lua +++ b/lua/acf/client/menu_items/settings_menu.lua @@ -59,7 +59,7 @@ local function CreateMenu(Menu) local Base = Menu:AddCollapsible("Aesthetic Settings") local Ropes = Base:AddCheckBox("Create mobility rope links.") - Ropes:SetConVar("ACF_MobilityRopeLinks") + Ropes:SetConVar("acf_mobilityropelinks") local Particles = Base:AddSlider("Particle Mult.", 0.1, 1, 2) Particles:SetConVar("acf_cl_particlemul") diff --git a/lua/entities/acf_gun/init.lua b/lua/entities/acf_gun/init.lua index e9f87a3a5..0dcbf0aef 100644 --- a/lua/entities/acf_gun/init.lua +++ b/lua/entities/acf_gun/init.lua @@ -5,7 +5,7 @@ include("shared.lua") -- Local Vars ----------------------------------- -local ACF_RECOIL = CreateConVar("acf_recoilpush", 1, FCVAR_ARCHIVE, "Whether or not ACF guns apply recoil", 0, 1) +local ACF_RECOIL = GetConVar("acf_recoilpush") local UnlinkSound = "physics/metal/metal_box_impact_bullet%s.wav" local CheckLegal = ACF_CheckLegal local Shove = ACF.KEShove diff --git a/lua/entities/gmod_wire_expression2/core/custom/acffunctions.lua b/lua/entities/gmod_wire_expression2/core/custom/acffunctions.lua index 7a160eff7..3ba3b35e2 100644 --- a/lua/entities/gmod_wire_expression2/core/custom/acffunctions.lua +++ b/lua/entities/gmod_wire_expression2/core/custom/acffunctions.lua @@ -11,7 +11,7 @@ E2Lib.RegisterExtension("acf", true) -- Local Variables and Helper Functions --===============================================================================================-- -local RestrictInfoConVar = GetConVar("sbox_acf_restrictinfo") +local RestrictInfoConVar = GetConVar("acf_restrict_info") local AllLinkSources = ACF.GetAllLinkSources local LinkSource = ACF.GetLinkSource local RoundTypes = ACF.RoundTypes diff --git a/lua/starfall/libs_sv/acffunctions.lua b/lua/starfall/libs_sv/acffunctions.lua index 930627993..75141070d 100644 --- a/lua/starfall/libs_sv/acffunctions.lua +++ b/lua/starfall/libs_sv/acffunctions.lua @@ -91,7 +91,7 @@ local vec_meta, vwrap, vunwrap = instance.Types.Vector, instance.Types.Vector.Wr local function restrictInfo ( ent ) if not propProtectionInstalled then return false end - if GetConVar("sbox_acf_restrictinfo"):GetInt() ~= 0 then + if GetConVar("acf_restrict_info"):GetInt() ~= 0 then if ent:CPPIGetOwner() ~= instance.player then return true else return false end end return false @@ -114,7 +114,7 @@ end -- @server -- @return True if restriced, False if not function acf_library.infoRestricted() - return GetConVar("sbox_acf_restrictinfo"):GetInt() ~= 0 + return GetConVar("acf_restrict_info"):GetInt() ~= 0 end --- Returns current ACF drag divisor @@ -828,7 +828,7 @@ end -- Moved to acf lib -- Returns true if functions returning sensitive info are restricted to owned props --[[function ents_methods:acfInfoRestricted () - return GetConVar( "sbox_acf_restrictinfo" ):GetInt() ~= 0 + return GetConVar( "acf_restrict_info" ):GetInt() ~= 0 end]] --- Returns true if this entity contains sensitive info and is not accessable to us From 80d24dbbf7dce2471aa877d2c4bd56a1e6044b52 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Thu, 10 Sep 2020 10:37:20 -0300 Subject: [PATCH 130/279] Reverted change to ACF.HideInfoBubble - Reverted optimization to ACF.HideInfoBubble since LocalPlayer() doesn't instantly return a valid entity on singleplayer. --- lua/acf/base/acf_globals.lua | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lua/acf/base/acf_globals.lua b/lua/acf/base/acf_globals.lua index a490facb8..0ac193bed 100644 --- a/lua/acf/base/acf_globals.lua +++ b/lua/acf/base/acf_globals.lua @@ -200,7 +200,6 @@ elseif CLIENT then -- Display Info Bubble ---------------------- local ShowInfo = GetConVar("acf_show_entity_info") - local LocalPly = LocalPlayer() function ACF.HideInfoBubble() local Value = ShowInfo:GetInt() @@ -208,7 +207,7 @@ elseif CLIENT then if Value == 0 then return true end if Value == 2 then return false end - return LocalPly:InVehicle() + return LocalPlayer():InVehicle() end --------------------------------------------- From e934fec933f609a3ae1fc857e54405b87fd4d6c2 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Mon, 14 Sep 2020 06:49:15 -0300 Subject: [PATCH 131/279] Improved menu options and items - Renamed ACF.AddOption to ACF.AddMenuOption - Renamed ACF.AddOptionItem to ACF.AddMenuItem - Both functions will now have a first argument to define their order. The higher the value the lower on the list it'll be. - Both options and items can now add a last argument to define function to tell when they can be enabled. If the function return false, then the option/item will not appear on the menu. - Improved stage and operation recovery on the tool functions. --- lua/acf/base/sh_tool_functions.lua | 16 ++- lua/acf/client/cl_menu.lua | 110 +++++++++++------- lua/acf/client/menu_items/components_menu.lua | 2 +- lua/acf/client/menu_items/contact.lua | 2 +- lua/acf/client/menu_items/engines_menu.lua | 2 +- lua/acf/client/menu_items/gearboxes_menu.lua | 2 +- lua/acf/client/menu_items/online_wiki.lua | 2 +- lua/acf/client/menu_items/sensors_menu.lua | 2 +- lua/acf/client/menu_items/settings_menu.lua | 7 +- lua/acf/client/menu_items/weapons_menu.lua | 2 +- 10 files changed, 90 insertions(+), 57 deletions(-) diff --git a/lua/acf/base/sh_tool_functions.lua b/lua/acf/base/sh_tool_functions.lua index 8ac5b1791..9d5493253 100644 --- a/lua/acf/base/sh_tool_functions.lua +++ b/lua/acf/base/sh_tool_functions.lua @@ -233,6 +233,7 @@ do -- Tool Functions Loader return not Trace.HitSky end else + -- Helper function, allows you to set both stage and op at the same time with their names function Tool:SetMode(StageName, OpName) if not StageName then return end if not OpName then return end @@ -282,8 +283,13 @@ do -- Tool Functions Loader function Tool:Deploy() local OnDeploy = self.OpData.OnDeploy - self:SetStage(self.LastStage) - self:SetOperation(self.LastOp) + if self.LastStage then + self:SetStage(self.LastStage) + self:SetOperation(self.LastOp) + + self.LastStage = nil + self.LastOp = nil + end if OnDeploy then OnDeploy(self) @@ -297,8 +303,10 @@ do -- Tool Functions Loader OnHolster(self) end - self.LastStage = self.Stage - self.LastOp = self.Operation + if not self.LastStage then + self.LastStage = self.Stage + self.LastOp = self.Operation + end end function Tool:Think() diff --git a/lua/acf/client/cl_menu.lua b/lua/acf/client/cl_menu.lua index 125ce92a3..43115b48b 100644 --- a/lua/acf/client/cl_menu.lua +++ b/lua/acf/client/cl_menu.lua @@ -1,6 +1,9 @@ -local Options = {} -local Lookup = {} -local Count = 0 +ACF.MenuOptions = ACF.MenuOptions or {} +ACF.MenuLookup = ACF.MenuLookup or {} +ACF.MenuCount = ACF.MenuCount or 0 + +local Options = ACF.MenuOptions +local Lookup = ACF.MenuLookup do -- Menu population functions local function DefaultAction(Menu) @@ -8,43 +11,42 @@ do -- Menu population functions Menu:AddLabel("This option is either a work in progress or something isn't working as intended.") end - local function MissilesMenu(Menu) - Menu:AddTitle("ACF-3 Missiles is not installed.") - Menu:AddLabel("This option requires ACF-3 Missiles to be installed. You can get it here:") - - local Link = Menu:AddButton("ACF-3 Missiles Repository") - - function Link:DoClickInternal() - gui.OpenURL("https://github.com/TwistedTail/ACF-3-Missiles") - end - end - - function ACF.AddOption(Name, Icon) + function ACF.AddMenuOption(Index, Name, Icon, Enabled) + if not Index then return end if not Name then return end + if not isfunction(Enabled) then Enabled = nil end if not Lookup[Name] then - Count = Count + 1 + local Count = ACF.MenuCount + 1 Options[Count] = { - Name = Name, Icon = "icon16/" .. (Icon or "plugin") .. ".png", + IsEnabled = Enabled, + Index = Index, + Name = Name, Lookup = {}, List = {}, Count = 0, } Lookup[Name] = Options[Count] + + ACF.MenuCount = Count else local Option = Lookup[Name] Option.Icon = "icon16/" .. (Icon or "plugin") .. ".png" + Option.IsEnabled = Enabled + Option.Index = Index end end - function ACF.AddOptionItem(Option, Name, Icon, Action) + function ACF.AddMenuItem(Index, Option, Name, Icon, Action, Enabled) + if not Index then return end if not Option then return end if not Name then return end if not Lookup[Option] then return end + if not isfunction(Enabled) then Enabled = nil end local Items = Lookup[Option] local Item = Items.Lookup[Name] @@ -55,6 +57,8 @@ do -- Menu population functions Items.List[Items.Count] = { Icon = "icon16/" .. (Icon or "plugin") .. ".png", Action = Action or DefaultAction, + IsEnabled = Enabled, + Index = Index, Name = Name, } @@ -62,39 +66,58 @@ do -- Menu population functions else Item.Icon = "icon16/" .. (Icon or "plugin") .. ".png" Item.Action = Action or DefaultAction + Item.IsEnabled = Enabled + Item.Index = Index Item.Name = Name end end - -- Small workaround to give the correct order to the items - ACF.AddOption("About the Addon", "information") - ACF.AddOptionItem("About the Addon", "Online Wiki", "book_open") - ACF.AddOptionItem("About the Addon", "Updates", "newspaper") - ACF.AddOptionItem("About the Addon", "Settings", "wrench") - ACF.AddOptionItem("About the Addon", "Contact Us", "feed") - - ACF.AddOption("Entities", "brick") - ACF.AddOptionItem("Entities", "Weapons", "gun") - ACF.AddOptionItem("Entities", "Missiles", "wand", MissilesMenu) - ACF.AddOptionItem("Entities", "Engines", "car") - ACF.AddOptionItem("Entities", "Gearboxes", "cog") - ACF.AddOptionItem("Entities", "Sensors", "transmit") - ACF.AddOptionItem("Entities", "Components", "drive") + ACF.AddMenuOption(1, "About the Addon", "information") + ACF.AddMenuItem(101, "About the Addon", "Updates", "newspaper") -- TODO: Add Updates item + + ACF.AddMenuOption(101, "Entities", "brick") end do -- ACF Menu context panel + local function GetSortedList(List) + local Result = {} + + for K, V in ipairs(List) do + Result[K] = V + end + + table.SortByMember(Result, "Index", true) + + return Result + end + + local function AllowOption(Option) + if Option.IsEnabled and not Option:IsEnabled() then return false end + + return hook.Run("ACF_AllowMenuOption", Option) ~= false + end + + local function AllowItem(Item) + if Item.IsEnabled and not Item:IsEnabled() then return false end + + return hook.Run("ACF_AllowMenuItem", Item) ~= false + end + local function PopulateTree(Tree) + local OptionList = GetSortedList(Options) local First - Tree.BaseHeight = Count + 0.5 + Tree.BaseHeight = 0.5 + + for _, Option in ipairs(OptionList) do + if not AllowOption(Option) then continue end - for _, Option in ipairs(Options) do local Parent = Tree:AddNode(Option.Name, Option.Icon) local SetExpanded = Parent.SetExpanded Parent.Action = Option.Action Parent.Master = true - Parent.Count = Option.Count + Parent.Count = 0 Parent.SetExpanded = function(Panel, Bool) if not Panel.AllowExpand then return end @@ -103,22 +126,29 @@ do -- ACF Menu context panel Panel.AllowExpand = nil end - for _, Data in ipairs(Option.List) do - local Child = Parent:AddNode(Data.Name, Data.Icon) + Tree.BaseHeight = Tree.BaseHeight + 1 - Child.Action = Data.Action + local ItemList = GetSortedList(Option.List) + for _, Item in ipairs(ItemList) do + if not AllowItem(Item) then continue end + + local Child = Parent:AddNode(Item.Name, Item.Icon) + Child.Action = Item.Action Child.Parent = Parent + Parent.Count = Parent.Count + 1 + if not Parent.Selected then Parent.Selected = Child if not First then - Tree:SetSelectedItem(Child) - First = true + First = Child end end end end + + Tree:SetSelectedItem(First) end local function UpdateTree(Tree, Old, New) diff --git a/lua/acf/client/menu_items/components_menu.lua b/lua/acf/client/menu_items/components_menu.lua index 7351ab75f..b8e8321dd 100644 --- a/lua/acf/client/menu_items/components_menu.lua +++ b/lua/acf/client/menu_items/components_menu.lua @@ -100,4 +100,4 @@ local function CreateMenu(Menu) LoadSortedList(ComponentClass, Components, "ID") end -ACF.AddOptionItem("Entities", "Components", "drive", CreateMenu) +ACF.AddMenuItem(501, "Entities", "Components", "drive", CreateMenu) diff --git a/lua/acf/client/menu_items/contact.lua b/lua/acf/client/menu_items/contact.lua index 47e6d3e39..de0072d42 100644 --- a/lua/acf/client/menu_items/contact.lua +++ b/lua/acf/client/menu_items/contact.lua @@ -52,4 +52,4 @@ local function CreateMenu(Menu) end end -ACF.AddOptionItem("About the Addon", "Contact Us", "feed", CreateMenu) +ACF.AddMenuItem(301, "About the Addon", "Contact Us", "feed", CreateMenu) diff --git a/lua/acf/client/menu_items/engines_menu.lua b/lua/acf/client/menu_items/engines_menu.lua index 5b05f9efa..615a5f2f1 100644 --- a/lua/acf/client/menu_items/engines_menu.lua +++ b/lua/acf/client/menu_items/engines_menu.lua @@ -241,4 +241,4 @@ local function CreateMenu(Menu) LoadSortedList(FuelClass, FuelTanks, "ID") end -ACF.AddOptionItem("Entities", "Engines", "car", CreateMenu) +ACF.AddMenuItem(201, "Entities", "Engines", "car", CreateMenu) diff --git a/lua/acf/client/menu_items/gearboxes_menu.lua b/lua/acf/client/menu_items/gearboxes_menu.lua index 8fe50d1e0..423e51e3a 100644 --- a/lua/acf/client/menu_items/gearboxes_menu.lua +++ b/lua/acf/client/menu_items/gearboxes_menu.lua @@ -93,7 +93,7 @@ local function CreateMenu(Menu) LoadSortedList(GearboxClass, Gearboxes, "ID") end -ACF.AddOptionItem("Entities", "Gearboxes", "cog", CreateMenu) +ACF.AddMenuItem(301, "Entities", "Gearboxes", "cog", CreateMenu) do -- Default Menus local Values = {} diff --git a/lua/acf/client/menu_items/online_wiki.lua b/lua/acf/client/menu_items/online_wiki.lua index bf0a7b32a..5bece3133 100644 --- a/lua/acf/client/menu_items/online_wiki.lua +++ b/lua/acf/client/menu_items/online_wiki.lua @@ -12,4 +12,4 @@ local function CreateMenu(Menu) Menu:AddHelp("The wiki is still a work in progress, it'll get populated as time passes.") end -ACF.AddOptionItem("About the Addon", "Online Wiki", "book_open", CreateMenu) +ACF.AddMenuItem(1, "About the Addon", "Online Wiki", "book_open", CreateMenu) diff --git a/lua/acf/client/menu_items/sensors_menu.lua b/lua/acf/client/menu_items/sensors_menu.lua index 45737dcef..c2b69d3e7 100644 --- a/lua/acf/client/menu_items/sensors_menu.lua +++ b/lua/acf/client/menu_items/sensors_menu.lua @@ -100,4 +100,4 @@ local function CreateMenu(Menu) LoadSortedList(SensorClass, Sensors, "ID") end -ACF.AddOptionItem("Entities", "Sensors", "transmit", CreateMenu) +ACF.AddMenuItem(401, "Entities", "Sensors", "transmit", CreateMenu) diff --git a/lua/acf/client/menu_items/settings_menu.lua b/lua/acf/client/menu_items/settings_menu.lua index 796450c15..8ca2a9ed4 100644 --- a/lua/acf/client/menu_items/settings_menu.lua +++ b/lua/acf/client/menu_items/settings_menu.lua @@ -48,11 +48,6 @@ local function CreateMenu(Menu) local Hints = Base:AddCheckBox("Enable hints on entity disabling.") Hints:SetConVar("acf_legalhints") - - local Parent = Base:AddCheckBox("Unparent disabled entities.") - Parent:SetConVar("acf_unparent_disabled_ents") - - Base:AddHelp("This option will only apply for entities that were disabled for 'Bad Parenting'.") end do -- Aesthetic Settings @@ -77,4 +72,4 @@ local function CreateMenu(Menu) end end -ACF.AddOptionItem("About the Addon", "Settings", "wrench", CreateMenu) +ACF.AddMenuItem(201, "About the Addon", "Settings", "wrench", CreateMenu) diff --git a/lua/acf/client/menu_items/weapons_menu.lua b/lua/acf/client/menu_items/weapons_menu.lua index 87941f2b4..bb1106c7e 100644 --- a/lua/acf/client/menu_items/weapons_menu.lua +++ b/lua/acf/client/menu_items/weapons_menu.lua @@ -245,4 +245,4 @@ local function CreateMenu(Menu) LoadSortedList(CrateList, Crates, "ID") end -ACF.AddOptionItem("Entities", "Weapons", "gun", CreateMenu) +ACF.AddMenuItem(1, "Entities", "Weapons", "gun", CreateMenu) From 32708f64040d1e1e8a34dbc359aaa33b7fcf1017 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Wed, 28 Oct 2020 17:16:55 -0300 Subject: [PATCH 132/279] Improved entity class functions - Entity class functions are no longer server-side only. - Renamed ACF.AddEntClassVars to ACF.AddEntityArguments. - Adding arguments with ACF.AddEntityArguments no longer requires the entity class to be previously registered with ACF.RegisterEntityClass. - Renamed ACF.GetEntClassVars to ACF.GetEntityArguments. --- lua/acf/base/sh_classes.lua | 81 ++++++++++++++++++++----------------- 1 file changed, 44 insertions(+), 37 deletions(-) diff --git a/lua/acf/base/sh_classes.lua b/lua/acf/base/sh_classes.lua index f8ad2260d..7f2eb05d8 100644 --- a/lua/acf/base/sh_classes.lua +++ b/lua/acf/base/sh_classes.lua @@ -440,51 +440,31 @@ do -- Sensor registration functions end end --- Serverside-only stuff -if CLIENT then return end - do -- Entity class registration function ACF.Classes.Entities = ACF.Classes.Entities or {} local Entities = ACF.Classes.Entities - local VarLookup = {} - local VarList = {} - function ACF.RegisterEntityClass(Class, Function, ...) - if not isstring(Class) then return end - if not isfunction(Function) then return end + local function GetEntityTable(Class) + if Entities[Class] then return Entities[Class] end - Entities[Class] = { - Spawn = Function, + local Table = { + Lookup = {}, + Count = 0, + List = {}, } - local Vars = istable(...) and ... or { ... } - local Lookup, List = {}, {} - local Count = 0 - - for _, V in pairs(Vars) do - Count = Count + 1 - - Lookup[V] = true - List[Count] = V - end - - VarLookup[Class] = Lookup - VarList[Class] = List + Entities[Class] = Table - duplicator.RegisterEntityClass(Class, Function, "Pos", "Angle", "Data", unpack(List)) + return Table end - function ACF.AddEntClassVars(Class, ...) - if not isstring(Class) then return end - if not Entities[Class] then return end - - local Vars = istable(...) and ... or { ... } - local Lookup = VarLookup[Class] - local List = VarList[Class] - local Count = #List + local function AddArguments(Entity, Arguments) + local Lookup = Entity.Lookup + local Count = Entity.Count + local List = Entity.List - for _, V in pairs(Vars) do + for _, V in ipairs(Arguments) do if not Lookup[V] then Count = Count + 1 @@ -493,22 +473,49 @@ do -- Entity class registration function end end + Entity.Count = Count + + return List + end + + function ACF.RegisterEntityClass(Class, Function, ...) + if not isstring(Class) then return end + if not isfunction(Function) then return end + + local Entity = GetEntityTable(Class) + local Arguments = istable(...) and ... or { ... } + local List = AddArguments(Entity, Arguments) + + Entity.Spawn = Function + duplicator.RegisterEntityClass(Class, Function, "Pos", "Angle", "Data", unpack(List)) end + function ACF.AddEntityArguments(Class, ...) + if not isstring(Class) then return end + + local Entity = GetEntityTable(Class) + local Arguments = istable(...) and ... or { ... } + local List = AddArguments(Entity, Arguments) + + if Entity.Spawn then + duplicator.RegisterEntityClass(Class, Entity.Spawn, "Pos", "Angle", "Data", unpack(List)) + end + end + function ACF.GetEntityClass(Class) if not Class then return end return Entities[Class] end - function ACF.GetEntClassVars(Class) - if not Class then return end - if not VarList[Class] then return end + function ACF.GetEntityArguments(Class) + if not isstring(Class) then return end + local Entity = GetEntityTable(Class) local List = {} - for K, V in ipairs(VarList[Class]) do + for K, V in ipairs(Entity.List) do List[K] = V end From b30e0660a3399c4fbad005fb8c3aa51ceed40d2a Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Wed, 28 Oct 2020 17:43:25 -0300 Subject: [PATCH 133/279] Improved tool functions - TOOL:SetMode no longer requires the user to be using the tool to manipulate it. - Added a 1 tick delay to ACF.SetToolMode --- lua/acf/base/sh_tool_functions.lua | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/lua/acf/base/sh_tool_functions.lua b/lua/acf/base/sh_tool_functions.lua index 9d5493253..de19ecea1 100644 --- a/lua/acf/base/sh_tool_functions.lua +++ b/lua/acf/base/sh_tool_functions.lua @@ -126,9 +126,10 @@ do -- Tool Information Registration function end for K, V in pairs(Info) do - New[K] = K == "name" and Name or V + New[K] = V end + New.name = Name New.stage = StageIdx New.op = OpIdx @@ -332,7 +333,6 @@ do -- Clientside Tool interaction if not Tool then return end if not Tool.SetMode then return end - if Player:GetTool() ~= Tool then return end Tool:SetMode(StageName, OpName) end) @@ -342,11 +342,13 @@ do -- Clientside Tool interaction if not isstring(Stage) then return end if not isstring(Op) then return end - net.Start("ACF_ToolMode") - net.WriteString(Tool) - net.WriteString(Stage) - net.WriteString(Op) - net.SendToServer() + timer.Simple(0, function() -- Yeah. + net.Start("ACF_ToolMode") + net.WriteString(Tool) + net.WriteString(Stage) + net.WriteString(Op) + net.SendToServer() + end) end end end From 33710ef1a8fc98d9a6ff8a1bb2adeca47ef8f714 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Wed, 28 Oct 2020 17:50:39 -0300 Subject: [PATCH 134/279] Added extra overlay text functions - Added ACF.RegisterOverlayText function to add extra bits of text to ACF entities' overlay. - Added ACF.RemoveOverlayText function to remove extra text overlay entries. - Added ACF.GetOverlayText function to get a string with the result of all the entries of a certain entity class. - PhysObj restoration functions will now save and restore the physics object material and contents. --- lua/acf/base/acf_globals.lua | 6 +++- lua/acf/base/util/sv_util.lua | 55 +++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/lua/acf/base/acf_globals.lua b/lua/acf/base/acf_globals.lua index 0ac193bed..51fdd02e2 100644 --- a/lua/acf/base/acf_globals.lua +++ b/lua/acf/base/acf_globals.lua @@ -244,7 +244,11 @@ timer.Simple(0, function() end end) -function switch(cases,arg) local Var = (cases[arg] or cases["default"]) return Var end +function switch(cases, arg) + local Var = cases[arg] + + return Var ~= nil and Var or cases.default +end -- changes here will be automatically reflected in the armor properties tool function ACF_CalcArmor(Area, Ductility, Mass) diff --git a/lua/acf/base/util/sv_util.lua b/lua/acf/base/util/sv_util.lua index f9b768b95..67b43c685 100644 --- a/lua/acf/base/util/sv_util.lua +++ b/lua/acf/base/util/sv_util.lua @@ -139,10 +139,14 @@ do -- Entity saving and restoring local PhysObj = Entity:GetPhysicsObject() + if not IsValid(PhysObj) then return end + Saved[Entity] = { Constraints = constraint.GetTable(Entity), Gravity = PhysObj:IsGravityEnabled(), Motion = PhysObj:IsMotionEnabled(), + Contents = PhysObj:GetContents(), + Material = PhysObj:GetMaterial(), } Entity:CallOnRemove("ACF_RestoreEntity", function() @@ -159,6 +163,8 @@ do -- Entity saving and restoring PhysObj:EnableGravity(EntData.Gravity) PhysObj:EnableMotion(EntData.Motion) + PhysObj:SetContents(EntData.Contents) + PhysObj:SetMaterial(EntData.Material) for _, Data in ipairs(EntData.Constraints) do local Constraint = Constraints[Data.Type] @@ -324,6 +330,55 @@ do -- Entity inputs end end +do -- Extra overlay text + local Classes = {} + + function ACF.RegisterOverlayText(ClassName, Identifier, Function) + if not isstring(ClassName) then return end + if Identifier == nil then return end + if not isfunction(Function) then return end + + local Class = Classes[ClassName] + + if not Class then + Classes[ClassName] = { + [Identifier] = Function + } + else + Class[Identifier] = Function + end + end + + function ACF.RemoveOverlayText(ClassName, Identifier) + if not isstring(ClassName) then return end + if Identifier == nil then return end + + local Class = Classes[ClassName] + + if not Class then return end + + Class[Identifier] = nil + end + + function ACF.GetOverlayText(Entity) + local Class = Classes[Entity:GetClass()] + + if not Class then return "" end + + local Result = "" + + for _, Function in pairs(Class) do + local Text = Function(Entity) + + if Text and Text ~= "" then + Result = Result .. "\n\n" .. Text + end + end + + return Result + end +end + function ACF_GetHitAngle(HitNormal, HitVector) local Ang = math.deg(math.acos(HitNormal:Dot(-HitVector:GetNormalized()))) -- Can output nan sometimes on extremely small angles From 33673855b3993aaf83884bc811a48d90437ef01c Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Wed, 28 Oct 2020 18:06:32 -0300 Subject: [PATCH 135/279] Added improved copy tool - Added improved ACF Copy tool, capable of copying and applying information from any ACF entity. - Added clientside console command `acf_reload_copy_menu`. - Renamed ACF.BuildContextPanel function to ACF.CreateSpawnMenu. - Renamed `acf_reload_menu` console command to `acf_reload_spawn_menu`. --- lua/acf/client/cl_copy_menu.lua | 147 ++++++++++++++++++ .../client/{cl_menu.lua => cl_spawn_menu.lua} | 10 +- lua/weapons/gmod_tool/stools/acf_menu2.lua | 8 +- lua/weapons/gmod_tool/stools/acfcopy.lua | 95 ++--------- lua/weapons/gmod_tool/stools/acfmenu.lua | 4 - 5 files changed, 166 insertions(+), 98 deletions(-) create mode 100644 lua/acf/client/cl_copy_menu.lua rename lua/acf/client/{cl_menu.lua => cl_spawn_menu.lua} (96%) diff --git a/lua/acf/client/cl_copy_menu.lua b/lua/acf/client/cl_copy_menu.lua new file mode 100644 index 000000000..7296a4a00 --- /dev/null +++ b/lua/acf/client/cl_copy_menu.lua @@ -0,0 +1,147 @@ +local CopiedData = {} +local Disabled = {} +local Selected + +net.Receive("ACF_SendCopyData", function(_, Player) + local Class = net.ReadString() + local List = util.JSONToTable(net.ReadString()) + + if IsValid(Player) then return end -- Trust nobody, not even net messages + + table.SortByMember(List, "Key", true) + + CopiedData[Class] = List + Selected = Class + + if not Disabled[Class] then + Disabled[Class] = {} + end + + RunConsoleCommand("acf_reload_copy_menu") -- Yeah. +end) + +local function GetIcon(Class, Key) + local Data = Disabled[Class] + + return Data[Key] and "icon16/delete.png" or "icon16/accept.png" +end + +local function PopulateTree(Tree, Data) + local Height = 0.5 + + Tree:Clear() + + for _, Info in ipairs(Data) do + local Icon = GetIcon(Selected, Info.Key) + local Node = Tree:AddNode(Info.Key, Icon) + local Value = Info.Value + local Type = type(Value) + local Size = 3 + + local TypeNode = Node:AddNode("Type: " .. Type, "icon16/cog.png") + TypeNode.RootNode = Node + + if Type ~= "table" then + local Base = Node:AddNode("Value: " .. tostring(Value), "icon16/information.png") + Base.RootNode = Node + else + local Base = Node:AddNode("Value:", "icon16/information.png") + Base.RootNode = Node + + for K, V in pairs(Value) do + local Extra = Base:AddNode(tostring(K) .. " = " .. tostring(V), "icon16/bullet_black.png") + Extra.RootNode = Node + + Size = Size + 1 + end + + Base:ExpandTo(true) + + -- We don't want this node to be collapsible + function Base:SetExpanded() + end + end + + Node:ExpandTo(true) + + -- We don't want this node to be collapsible + function Node:SetExpanded() + end + + Height = Height + Size + end + + Tree:SetHeight(Tree:GetLineHeight() * Height) +end + +local function UpdateComboBox(ComboBox) + ComboBox:Clear() + + for Class, Data in pairs(CopiedData) do + ComboBox:AddChoice(Class, Data, Class == Selected) + end +end + +function ACF.CreateCopyMenu(Panel) + local Menu = ACF.CopyMenu + + if not IsValid(Menu) then + Menu = vgui.Create("ACF_Panel") + Menu.Panel = Panel + + Panel:AddItem(Menu) + + ACF.CopyMenu = Menu + else + Menu:ClearAllTemporal() + Menu:ClearAll() + end + + local Reload = Menu:AddButton("Reload Menu") + Reload:SetTooltip("You can also type 'acf_reload_copy_menu' in console.") + function Reload:DoClickInternal() + RunConsoleCommand("acf_reload_copy_menu") + end + + ACF.SetToolMode("acfcopy", "Main", "CopyPaste") + + if not Selected then + return Menu:AddLabel("Right click an ACF entity to copy its data.") + end + + local ClassList = Menu:AddComboBox() + local TreeList = Menu:AddPanel("DTree") + + function ClassList:OnSelect(_, Class, Data) + Selected = Class + + PopulateTree(TreeList, Data) + end + + function TreeList:OnNodeSelected(Node) + if Node.RootNode then + return self:SetSelectedItem(Node.RootNode) + end + + local Key = Node:GetText() + local Data = Disabled[Selected] + + -- A ternary won't work here + if Data[Key] then + Data[Key] = nil + else + Data[Key] = true + end + + net.Start("ACF_SendDisabledData") + net.WriteString(Selected) + net.WriteString(Key) + net.WriteBool(Data[Key] or false) + net.SendToServer() + + Node:SetIcon(GetIcon(Selected, Key)) + end + + UpdateComboBox(ClassList) +end + diff --git a/lua/acf/client/cl_menu.lua b/lua/acf/client/cl_spawn_menu.lua similarity index 96% rename from lua/acf/client/cl_menu.lua rename to lua/acf/client/cl_spawn_menu.lua index 43115b48b..890785422 100644 --- a/lua/acf/client/cl_menu.lua +++ b/lua/acf/client/cl_spawn_menu.lua @@ -168,8 +168,8 @@ do -- ACF Menu context panel Tree:SetHeight(Tree:GetLineHeight() * (Tree.BaseHeight + NewParent.Count)) end - function ACF.BuildContextPanel(Panel) - local Menu = ACF.Menu + function ACF.CreateSpawnMenu(Panel) + local Menu = ACF.SpawnMenu if not IsValid(Menu) then Menu = vgui.Create("ACF_Panel") @@ -177,16 +177,16 @@ do -- ACF Menu context panel Panel:AddItem(Menu) - ACF.Menu = Menu + ACF.SpawnMenu = Menu else Menu:ClearAllTemporal() Menu:ClearAll() end local Reload = Menu:AddButton("Reload Menu") - Reload:SetTooltip("You can also type 'acf_reload_menu' in console.") + Reload:SetTooltip("You can also type 'acf_reload_spawn_menu' in console.") function Reload:DoClickInternal() - ACF.BuildContextPanel(Panel) + ACF.CreateSpawnMenu(Panel) end local Tree = Menu:AddPanel("DTree") diff --git a/lua/weapons/gmod_tool/stools/acf_menu2.lua b/lua/weapons/gmod_tool/stools/acf_menu2.lua index 3b60960cf..58506f295 100644 --- a/lua/weapons/gmod_tool/stools/acf_menu2.lua +++ b/lua/weapons/gmod_tool/stools/acf_menu2.lua @@ -30,12 +30,12 @@ if CLIENT then cam.End3D() end - TOOL.BuildCPanel = ACF.BuildContextPanel + TOOL.BuildCPanel = ACF.CreateSpawnMenu - concommand.Add("acf_reload_menu", function() - if not IsValid(ACF.Menu) then return end + concommand.Add("acf_reload_spawn_menu", function() + if not IsValid(ACF.SpawnMenu) then return end - ACF.BuildContextPanel(ACF.Menu.Panel) + ACF.CreateSpawnMenu(ACF.SpawnMenu.Panel) end) hook.Add("ACF_DrawBoxes", "ACF Draw Hitboxes", function(Entity) diff --git a/lua/weapons/gmod_tool/stools/acfcopy.lua b/lua/weapons/gmod_tool/stools/acfcopy.lua index dba5566bd..06670a401 100644 --- a/lua/weapons/gmod_tool/stools/acfcopy.lua +++ b/lua/weapons/gmod_tool/stools/acfcopy.lua @@ -1,92 +1,17 @@ -local cat = ((ACF.CustomToolCategory and ACF.CustomToolCategory:GetBool()) and "ACF" or "Construction") -TOOL.Category = cat -TOOL.Name = "#Tool.acfcopy.listname" -TOOL.Author = "looter" -TOOL.Command = nil -TOOL.ConfigName = "" -TOOL.GearboxCopyData = {} -TOOL.AmmoCopyData = {} +TOOL.Name = "ACF Copy Tool" +TOOL.Category = "Construction" + +ACF.LoadToolFunctions(TOOL) if CLIENT then - language.Add("Tool.acfcopy.listname", "ACF Copy Tool") language.Add("Tool.acfcopy.name", "Armored Combat Framework") - language.Add("Tool.acfcopy.desc", "Copy ammo or gearbox data from one object to another") - language.Add("Tool.acfcopy.0", "Left click to paste data, Right click to copy data") - - function TOOL.BuildCPanel() - end -end + language.Add("Tool.acfcopy.desc", "Copy information from one ACF entity to another") --- Update -function TOOL:LeftClick(trace) - if CLIENT then return end - local ent = trace.Entity - if not IsValid(ent) then return false end - local pl = self:GetOwner() + TOOL.BuildCPanel = ACF.CreateCopyMenu - if (ent:GetClass() == "acf_gearbox" and #self.GearboxCopyData > 1 and ent.CanUpdate) then - local success, msg = ent:Update(self.GearboxCopyData) - ACF_SendNotify(pl, success, msg) - end + concommand.Add("acf_reload_copy_menu", function() + if not IsValid(ACF.CopyMenu) then return end - if (ent:GetClass() == "acf_ammo" and #self.AmmoCopyData > 1 and ent.CanUpdate) then - local success, msg = ent:Update(self.AmmoCopyData) - ACF_SendNotify(pl, success, msg) - end - - return true + ACF.CreateCopyMenu(ACF.CopyMenu.Panel) + end) end - --- Copy -function TOOL:RightClick(trace) - if CLIENT then return end - local ent = trace.Entity - if not IsValid(ent) then return false end - local pl = self:GetOwner() - - if (ent:GetClass() == "acf_gearbox") then - local ArgsTable = {} - -- zero out the un-needed tool trace information - ArgsTable[1] = pl - ArgsTable[2] = 0 - ArgsTable[3] = 0 - ArgsTable[4] = ent.Id - -- build gear data - ArgsTable[5] = ent.GearTable[1] - ArgsTable[6] = ent.GearTable[2] - ArgsTable[7] = ent.GearTable[3] - ArgsTable[8] = ent.GearTable[4] - ArgsTable[9] = ent.GearTable[5] - ArgsTable[10] = ent.GearTable[6] - ArgsTable[11] = ent.GearTable[7] - ArgsTable[12] = ent.GearTable[8] - ArgsTable[13] = ent.GearTable[9] - ArgsTable[14] = ent.GearTable.Final - self.GearboxCopyData = ArgsTable - ACF_SendNotify(pl, true, "Gearbox copied successfully!") - end - - if (ent:GetClass() == "acf_ammo") then - -- zero out the un-needed tool trace information - self.AmmoCopyData = { - pl, - 0, - 0, - -- build ammo data - ent.RoundId, - ent.RoundType, - ent.RoundPropellant, - ent.RoundProjectile, - ent.RoundData5, - ent.RoundData6, - ent.RoundData7, - ent.RoundData8, - ent.RoundData9, - ent.RoundData10, - } - - ACF_SendNotify(pl, true, "Ammo copied successfully!") - end - - return true -end \ No newline at end of file diff --git a/lua/weapons/gmod_tool/stools/acfmenu.lua b/lua/weapons/gmod_tool/stools/acfmenu.lua index a0b909c55..8b359c8ef 100644 --- a/lua/weapons/gmod_tool/stools/acfmenu.lua +++ b/lua/weapons/gmod_tool/stools/acfmenu.lua @@ -32,11 +32,7 @@ if CLIENT then language.Add( "Tool.acfmenu.0", "Left click to spawn the entity of your choice, Right click to link an entity to another (+Use to unlink)" ) language.Add( "Tool.acfmenu.1", "Right click to link the selected sensor to a pod" ) - language.Add( "Undone_ACF Entity", "Undone ACF Entity" ) - language.Add( "Undone_acf_gearbox", "Undone ACF Gearbox" ) - language.Add( "Undone_acf_ammo", "Undone ACF Ammo" ) language.Add( "SBoxLimit_acf_rack", "You've reached the ACF Launchers limit!" ) - language.Add( "SBoxLimit_acf_ammo", "You've reached the ACF Explosives limit!" ) language.Add( "SBoxLimit_acf_sensor", "You've reached the ACF Sensors limit!" ) local DrawBoxes = GetConVar("acf_drawboxes") From 4628b6118c99d1bf3cb88b6f362432dfee0d5172 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Wed, 28 Oct 2020 18:22:11 -0300 Subject: [PATCH 136/279] Improved scalable bases + added missing bits from last commit - Added shared ENT:SetScale function to base_scalable class. - Scalable entities will no longer have an unmovable clientside physics object. - Added missing tool operation updates for the ACF Menu and ACF Copy tools. --- lua/acf/shared/tool_operations/acf_copy.lua | 154 ++++++++++++++++++++ lua/acf/shared/tool_operations/acf_menu.lua | 5 + lua/entities/base_scalable/cl_init.lua | 57 +++++--- lua/entities/base_scalable/init.lua | 55 ++++--- lua/entities/base_scalable/shared.lua | 10 +- lua/entities/base_scalable_box/cl_init.lua | 1 - lua/entities/base_scalable_box/init.lua | 1 - 7 files changed, 241 insertions(+), 42 deletions(-) create mode 100644 lua/acf/shared/tool_operations/acf_copy.lua diff --git a/lua/acf/shared/tool_operations/acf_copy.lua b/lua/acf/shared/tool_operations/acf_copy.lua new file mode 100644 index 000000000..c7341efba --- /dev/null +++ b/lua/acf/shared/tool_operations/acf_copy.lua @@ -0,0 +1,154 @@ +local CopiedData = {} +local Disabled = {} +local ACF = ACF + +local function GetDisabledData(Player, Class) + return Disabled[Player][Class] +end + +if SERVER then + util.AddNetworkString("ACF_SendCopyData") + util.AddNetworkString("ACF_SendDisabledData") + + net.Receive("ACF_SendDisabledData", function(_, Player) + local Class = net.ReadString() + local Data = net.ReadString() + local State = net.ReadBool() or nil + + if not IsValid(Player) then return end + + local DisabledData = GetDisabledData(Player, Class) + + DisabledData[Data] = State + end) + + hook.Add("PlayerInitialSpawn", "ACF Copy Data", function(Player) + CopiedData[Player] = {} + Disabled[Player] = {} + end) + + hook.Add("PlayerDisconnected", "ACF Copy Data", function(Player) + CopiedData[Player] = nil + Disabled[Player] = nil + end) +end + +local function GetCopyData(Player, Class) + return CopiedData[Player][Class] +end + +local function SaveCopyData(Player, Entity) + local Class = Entity:GetClass() + local Data = GetCopyData(Player, Class) + local List = {} + local Count = 0 + + if not Data then + Data = {} + + CopiedData[Player][Class] = Data + else + for K in pairs(Data) do + Data[K] = nil + end + end + + for _, V in ipairs(Entity.DataStore) do + local Value = Entity[V] + + if Value ~= nil then + Count = Count + 1 + + Data[V] = Value + List[Count] = { + Key = V, + Value = Value, + } + end + end + + if not GetDisabledData(Player, Class) then + Disabled[Player][Class] = {} + end + + return util.TableToJSON(List) +end + +ACF.RegisterOperation("acfcopy", "Main", "CopyPaste", { + OnLeftClick = function(Tool, Trace) + if Trace.HitSky then return false end + + local Entity = Trace.Entity + local Player = Tool:GetOwner() + + if not IsValid(Entity) then return false end + if not isfunction(Entity.Update) then + ACF.SendMessage(Player, "Error", "This entity doesn't support updating!") + return false + end + + local Class = Entity:GetClass() + local Saved = GetCopyData(Player, Class) + + if not Saved then + ACF.SendMessage(Player, "Error", "No information has been copied for '", Class, "' entities!") + return false + end + + local DisabledData = GetDisabledData(Player, Class) + local Data = {} + + for K, V in pairs(Saved) do + local Value = V + + if DisabledData[K] then + Value = Entity[K] + end + + Data[K] = Value + end + + local Result, Message = Entity:Update(Data) + + if not Result then + Message = "Couldn't update entity: " .. Message + end + + ACF.SendMessage(Player, Result and "Info" or "Error", Message) + + return true + end, + OnRightClick = function(Tool, Trace) + if Trace.HitSky then return false end + + local Entity = Trace.Entity + + if not IsValid(Entity) then return false end + if not Entity.DataStore then return false end + + local Player = Tool:GetOwner() + local List = SaveCopyData(Player, Entity) + + net.Start("ACF_SendCopyData") + net.WriteString(Entity:GetClass()) + net.WriteString(List) + net.Send(Player) + + return true + end, +}) + +ACF.RegisterToolInfo("acfcopy", "Main", "CopyPaste", { + name = "left", + text = "Update the ACF entity with the copied information for its class.", +}) + +ACF.RegisterToolInfo("acfcopy", "Main", "CopyPaste", { + name = "right", + text = "Copy the relevant information from an ACF entity.", +}) + +ACF.RegisterToolInfo("acfcopy", "Main", "CopyPaste", { + name = "info", + text = "You can toggle the copied information you want to apply/ignore when updating an ACF entity on the tool menu.", +}) diff --git a/lua/acf/shared/tool_operations/acf_menu.lua b/lua/acf/shared/tool_operations/acf_menu.lua index 85bcf0dbf..426cb6cc4 100644 --- a/lua/acf/shared/tool_operations/acf_menu.lua +++ b/lua/acf/shared/tool_operations/acf_menu.lua @@ -79,6 +79,11 @@ do -- Spawner operation return false end + if not Class.Spawn then + SendMessage(Player, "Error", ClassName, " doesn't have a spawn function assigned to it.") + return false + end + local Position = Trace.HitPos + Trace.HitNormal * 128 local Angles = Trace.HitNormal:Angle():Up():Angle() diff --git a/lua/entities/base_scalable/cl_init.lua b/lua/entities/base_scalable/cl_init.lua index a5349cb29..9f388572b 100644 --- a/lua/entities/base_scalable/cl_init.lua +++ b/lua/entities/base_scalable/cl_init.lua @@ -4,6 +4,30 @@ include("shared.lua") local Queued = {} +local function ChangeSize(Entity, Size) + if not isvector(Size) then return false end + if Entity.Size == Size then return false end + if not Entity:GetOriginalSize() then return false end + + local Original = Entity:GetOriginalSize() + local Scale = Vector(Size.x / Original.x, Size.y / Original.y, Size.z / Original.z) + + if Entity.ApplyNewSize then Entity:ApplyNewSize(Size, Scale) end + + Entity.Size = Size + Entity.Scale = Scale + + local PhysObj = Entity:GetPhysicsObject() + + if IsValid(PhysObj) then + if Entity.OnResized then Entity:OnResized(Size, Scale) end + + hook.Run("OnEntityResized", Entity, PhysObj, Size, Scale) + end + + return true, Size, Scale +end + function ENT:Initialize() BaseClass.Initialize(self) @@ -28,26 +52,20 @@ function ENT:GetOriginalSize() return self.OriginalSize end -function ENT:GetSize() - return self.Size -end - -function ENT:SetSize(NewSize) - if not isvector(NewSize) then return end - if self.Size == NewSize then return end - if not self:GetOriginalSize() then return end +function ENT:SetSize(Size) + if not isvector(Size) then return false end - if self.ApplyNewSize then self:ApplyNewSize(NewSize) end + return ChangeSize(self, Size) +end - self.Size = NewSize +function ENT:SetScale(Scale) + if isnumber(Scale) then Scale = Vector(Scale, Scale, Scale) end + if not isvector(Scale) then return false end - local PhysObj = self:GetPhysicsObject() + local Original = self:GetOriginalSize() + local Size = Vector(Original.x, Original.y, Original.z) * Scale - if IsValid(PhysObj) then - if self.OnResized then self:OnResized(NewSize) end - - hook.Run("OnEntityResized", self, PhysObj, NewSize) - end + return ChangeSize(self, Size) end function ENT:CalcAbsolutePosition() -- Faking sync @@ -92,10 +110,9 @@ net.Receive("RequestSize", function() end) -- Commented out for the moment, something's causing crashes --- TODO: Maybe hijack PhysObj:EnableMotion instead? ---hook.Add("PhysgunPickup", "Scalable Ent Physgun", function(_, Ent) - --if Ent.IsScalable then return false end ---end) +hook.Add("PhysgunPickup", "Scalable Ent Physgun", function(_, Ent) + if Ent.IsScalable then return false end +end) hook.Add("NetworkEntityCreated", "Scalable Ent Full Update", function(Ent) if Ent.IsScalable then diff --git a/lua/entities/base_scalable/init.lua b/lua/entities/base_scalable/init.lua index 41189f949..5e9069051 100644 --- a/lua/entities/base_scalable/init.lua +++ b/lua/entities/base_scalable/init.lua @@ -62,6 +62,32 @@ local function NetworkSize(Entity, Player) timer.Create("ACF Network Sizes", 0, 1, SendQueued) end +local function ChangeSize(Entity, Size) + if Entity.Size == Size then return false end + + local Original = Entity:GetOriginalSize() + local Scale = Vector(Size.x / Original.x, Size.y / Original.y, Size.z / Original.z) + + if Entity.ApplyNewSize then Entity:ApplyNewSize(Size, Scale) end + + -- If it's not a new entity, then network the new size + -- Otherwise, the entity will request its size by itself + if Entity.Size then NetworkSize(Entity) end + + Entity.Size = Size + Entity.Scale = Scale + + local PhysObj = Entity:GetPhysicsObject() + + if IsValid(PhysObj) then + if Entity.OnResized then Entity:OnResized(Size, Scale) end + + hook.Run("OnEntityResized", Entity, PhysObj, Size, Scale) + end + + return true, Size, Scale +end + function ENT:Initialize() BaseClass.Initialize(self) @@ -86,29 +112,20 @@ function ENT:GetOriginalSize() return self.OriginalSize end -function ENT:GetSize() - return self.Size -end - -function ENT:SetSize(NewSize) - if not isvector(NewSize) then return end - if self.Size == NewSize then return end - - if self.ApplyNewSize then self:ApplyNewSize(NewSize) end +function ENT:SetSize(Size) + if not isvector(Size) then return false end - -- If it's not a new entity, then network the new size - -- Otherwise, the entity will request its size by itself - if self.Size then NetworkSize(self) end + return ChangeSize(self, Size) +end - self.Size = NewSize +function ENT:SetScale(Scale) + if isnumber(Scale) then Scale = Vector(Scale, Scale, Scale) end + if not isvector(Scale) then return false end - local PhysObj = self:GetPhysicsObject() + local Original = self:GetOriginalSize() + local Size = Vector(Original.x, Original.y, Original.z) * Scale - if IsValid(PhysObj) then - if self.OnResized then self:OnResized(NewSize) end - - hook.Run("OnEntityResized", self, PhysObj, NewSize) - end + return ChangeSize(self, Size) end do -- AdvDupe2 duped parented ammo workaround diff --git a/lua/entities/base_scalable/shared.lua b/lua/entities/base_scalable/shared.lua index 4ea49fa76..267cd8cae 100644 --- a/lua/entities/base_scalable/shared.lua +++ b/lua/entities/base_scalable/shared.lua @@ -2,5 +2,13 @@ DEFINE_BASECLASS("base_wire_entity") ENT.PrintName = "Base Scalable Entity" ENT.WireDebugName = "Base Scalable Entity" -ENT.Contact = "Don't" +ENT.Contact = "Don't" ENT.IsScalable = true + +function ENT:GetSize() + return self.Size +end + +function ENT:GetScale() + return self.Scale +end diff --git a/lua/entities/base_scalable_box/cl_init.lua b/lua/entities/base_scalable_box/cl_init.lua index 7c67768e5..d0ed0f5a3 100644 --- a/lua/entities/base_scalable_box/cl_init.lua +++ b/lua/entities/base_scalable_box/cl_init.lua @@ -13,7 +13,6 @@ function ENT:ApplyNewSize(NewSize) self:PhysicsInitBox(-Bounds, Bounds) self:SetRenderBounds(-Bounds, Bounds) self:EnableCustomCollisions(true) - self:SetMoveType(MOVETYPE_NONE) self:DrawShadow(false) local PhysObj = self:GetPhysicsObject() diff --git a/lua/entities/base_scalable_box/init.lua b/lua/entities/base_scalable_box/init.lua index 4d23ed005..8d15f28c1 100644 --- a/lua/entities/base_scalable_box/init.lua +++ b/lua/entities/base_scalable_box/init.lua @@ -27,7 +27,6 @@ function ENT:ApplyNewSize(NewSize) self:PhysicsInitBox(-Bounds, Bounds) self:EnableCustomCollisions(true) - self:SetSolid(SOLID_VPHYSICS) local PhysObj = self:GetPhysicsObject() From bea11f7fb14a34c4d6aace5e730c43bd4130049e Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Wed, 28 Oct 2020 20:13:12 -0300 Subject: [PATCH 137/279] Added entity event hooks - Added several server-side hooks for entity spawn and update events: ACF_VerifyData, ACF_OnEntitySpawn, ACF_OnEntityUpdate and ACF_OnEntityLast. For gearboxes, there's also ACF_OnSetupInputs and ACF_OnSetupOutputs. - Entity classes can now also perform certain actions by using the next functions: Class.VerifyData, Class.OnSpawn, Class.OnUpdate and Class.OnLast. Gearbox classes can also use Class.SetupInputs and Class.SetupOutputs. - Weapons and engines will now return the class name instead of the ID as their ACF entity type. - Transfer cases, double differentials, differentials and clutches can now use their neutral gear. --- lua/acf/client/menu_items/gearboxes_menu.lua | 9 +- lua/acf/client/menu_items/weapons_menu.lua | 6 +- lua/acf/shared/engine_types/electric.lua | 2 +- lua/acf/shared/gearboxes/3-auto.lua | 119 +++++- lua/acf/shared/gearboxes/5-auto.lua | 120 +++++- lua/acf/shared/gearboxes/7-auto.lua | 120 +++++- lua/acf/shared/gearboxes/clutch.lua | 2 +- lua/acf/shared/gearboxes/cvt.lua | 77 +++- lua/acf/shared/gearboxes/differential.lua | 2 +- lua/acf/shared/gearboxes/doublediff.lua | 29 +- lua/acf/shared/gearboxes/transfer.lua | 2 +- lua/entities/acf_engine/init.lua | 90 ++-- lua/entities/acf_fueltank/init.lua | 74 +++- lua/entities/acf_gearbox/init.lua | 410 +++++++++---------- lua/entities/acf_gun/init.lua | 70 +++- 15 files changed, 774 insertions(+), 358 deletions(-) diff --git a/lua/acf/client/menu_items/gearboxes_menu.lua b/lua/acf/client/menu_items/gearboxes_menu.lua index 423e51e3a..fe5d44fae 100644 --- a/lua/acf/client/menu_items/gearboxes_menu.lua +++ b/lua/acf/client/menu_items/gearboxes_menu.lua @@ -54,7 +54,6 @@ local function CreateMenu(Menu) Selected[Choices] = Index ACF.WriteValue("GearboxClass", Data.ID) - ACF.WriteValue("MaxGears", Data.Gears.Max) LoadSortedList(GearboxList, Data.Items, "ID") end @@ -119,7 +118,7 @@ do -- Default Menus local ValuesData = Values[Class.ID] - for I = math.max(1, Gears.Min), Gears.Max do + for I = 1, Gears.Max do local Variable = "Gear" .. I local Default = ValuesData[Variable] @@ -333,7 +332,7 @@ do -- Default Menus local Delta = UnitMult / Mult - for I = math.max(1, Gears.Min), Gears.Max do + for I = 1, Gears.Max do local Var = "Shift" .. I local Old = ACF.ReadNumber(Var) @@ -345,7 +344,7 @@ do -- Default Menus UnitMult = Mult end - for I = math.max(1, Gears.Min), Gears.Max do + for I = 1, Gears.Max do local GearVar = "Gear" .. I local DefGear = ValuesData[GearVar] @@ -464,7 +463,7 @@ do -- Default Menus local WheelDiameter = ValuesData.WheelDiameter local Multiplier = math.pi * UpshiftRPM * TotalRatio * FinalDrive * WheelDiameter / (60 * UnitMult) - for I = math.max(1, Gears.Min), Gears.Max do + for I = 1, Gears.Max do local Gear = ValuesData["Gear" .. I] ACF.WriteValue("Shift" .. I, Gear * Multiplier) diff --git a/lua/acf/client/menu_items/weapons_menu.lua b/lua/acf/client/menu_items/weapons_menu.lua index bb1106c7e..4145ba0de 100644 --- a/lua/acf/client/menu_items/weapons_menu.lua +++ b/lua/acf/client/menu_items/weapons_menu.lua @@ -121,7 +121,7 @@ local function CreateMenu(Menu) Selected[Choices] = Index ACF.WriteValue("Weapon", Data.ID) - ACF.WriteValue("Destiny", Data.Destiny) + ACF.WriteValue("Destiny", Data.Destiny or "Weapons") EntName:SetText(Data.Name) EntData:SetText(UpdateEntityData()) @@ -166,7 +166,7 @@ local function CreateMenu(Menu) local Choices = Sorted[GetAmmoList(ClassList.Selected.ID)] Selected[Choices] = Index - ACF.WriteValue("Ammo", Data.ID) + ACF.WriteValue("AmmoType", Data.ID) AmmoDesc:SetText(Data.Description .. "\n\nThis entity can be fully parented.") @@ -179,7 +179,7 @@ local function CreateMenu(Menu) local Ammo = self.Selected local ToolData = ACF.GetToolData() - AmmoData = Ammo:ClientConvert(Menu, ToolData) + AmmoData = Ammo:ClientConvert(ToolData) Menu:ClearTemporal(AmmoBase) Menu:StartTemporal(AmmoBase) diff --git a/lua/acf/shared/engine_types/electric.lua b/lua/acf/shared/engine_types/electric.lua index 11d39fd65..28f3501d3 100644 --- a/lua/acf/shared/engine_types/electric.lua +++ b/lua/acf/shared/engine_types/electric.lua @@ -12,6 +12,6 @@ ACF.RegisterEngineType("Electric", { end, CalculateFuelUsage = function(Entity) -- Electric engines use current power output, not max - return ACF.FuelRate / Entity.Efficiency * 3600 + return ACF.FuelRate * Entity.Efficiency / 3600 end }) diff --git a/lua/acf/shared/gearboxes/3-auto.lua b/lua/acf/shared/gearboxes/3-auto.lua index 9eaf51010..118781c1d 100644 --- a/lua/acf/shared/gearboxes/3-auto.lua +++ b/lua/acf/shared/gearboxes/3-auto.lua @@ -18,6 +18,26 @@ local ShiftS = 0.25 local ShiftM = 0.35 local ShiftL = 0.5 +local function CheckNumber(Value) + if not Value then return end -- nil or false, both are not numbers + + return tonumber(Value) +end + +local function InitGearbox(Gearbox) + local Gears = Gearbox.Gears + + Gearbox.Automatic = true + Gearbox.ShiftScale = 1 + Gearbox.Hold = false + Gearbox.Drive = 0 + Gearbox.GearCount = Gearbox.MaxGear + 1 + + Gears[Gearbox.GearCount] = Gearbox.Reverse + + Gearbox:ChangeDrive(1) +end + ACF.RegisterGearboxClass("3-Auto", { Name = "3-Speed Automatic", CreateMenu = ACF.AutomaticGearboxMenu, @@ -25,6 +45,90 @@ ACF.RegisterGearboxClass("3-Auto", { Min = 0, Max = 3, }, + OnSpawn = InitGearbox, + OnUpdate = InitGearbox, + VerifyData = function(Data, Class) + do -- Shift point table verification + local Points = Data.ShiftPoints + local Mult = Data.ShiftUnit or 1 + local Max = Class.Gears.Max + + if not istable(Points) then + local Encoded = Data.Gear9 and tostring(Data.Gear9) + + Points = { [0] = -1 } + + if Encoded then + local Count = 0 + + for Point in string.gmatch(Encoded, "[^,]+") do + Count = Count + 1 + + if Count > Max then break end + + Points[Count] = CheckNumber(Point) or Count * 100 + end + end + + Data.ShiftPoints = Points + else + Points[0] = -1 + end + + for I = 1, Max do + local Point = CheckNumber(Points[I]) + + if not Point then + Point = (CheckNumber(Data["Shift" .. I]) or I * 100) * Mult + + Data["Shift" .. I] = nil + end + + Points[I] = math.Clamp(Point, 0, 9999) + end + end + + do -- Reverse gear verification + local Reverse = CheckNumber(Data.Reverse) + + if not Reverse then + Reverse = CheckNumber(Data.Gear8) or -1 + + Data.Gear8 = nil + end + + Data.Reverse = math.Clamp(Reverse, -1, 1) + end + end, + SetupInputs = function(List) + local Count = #List + + List[Count + 1] = "Hold Gear" + List[Count + 2] = "Shift Speed Scale" + end, + OnLast = function(Gearbox) + Gearbox.Automatic = nil + Gearbox.ShiftScale = nil + Gearbox.Drive = nil + Gearbox.Hold = nil + end, + GetGearsText = function(Gearbox) + local GearText = "Gear %s: %s, Upshift @ %s kph / %s mph\n" + local Text = "%sReverse gear: %s\n" + local Points = Gearbox.ShiftPoints + local Gears = Gearbox.Gears + local GearsText = "" + + for I = 1, Gearbox.MaxGear do + local Ratio = math.Round(Gears[I], 2) + local KPH = math.Round(Points[I] / 10.936, 1) + local MPH = math.Round(Points[I] / 17.6, 1) + + GearsText = GearsText .. GearText:format(I, Ratio, KPH, MPH) + end + + return Text:format(GearsText, math.Round(Gearbox.Reverse, 2)) + end, }) do -- Inline Gearboxes @@ -35,7 +139,6 @@ do -- Inline Gearboxes Mass = Gear3SW, Switch = ShiftS, MaxTorque = Gear3ST, - Automatic = true, }) ACF.RegisterGearbox("3Gear-A-L-M", "3-Auto", { @@ -45,7 +148,6 @@ do -- Inline Gearboxes Mass = Gear3MW, Switch = ShiftM, MaxTorque = Gear3MT, - Automatic = true, }) ACF.RegisterGearbox("3Gear-A-L-L", "3-Auto", { @@ -55,7 +157,6 @@ do -- Inline Gearboxes Mass = Gear3LW, Switch = ShiftL, MaxTorque = Gear3LT, - Automatic = true, }) end @@ -67,7 +168,6 @@ do -- Inline Dual Clutch Gearboxes Mass = Gear3SW, Switch = ShiftS, MaxTorque = Gear3ST, - Automatic = true, DualClutch = true, }) @@ -78,7 +178,6 @@ do -- Inline Dual Clutch Gearboxes Mass = Gear3MW, Switch = ShiftM, MaxTorque = Gear3MT, - Automatic = true, DualClutch = true, }) @@ -89,7 +188,6 @@ do -- Inline Dual Clutch Gearboxes Mass = Gear3LW, Switch = ShiftL, MaxTorque = Gear3LT, - Automatic = true, DualClutch = true, }) end @@ -102,7 +200,6 @@ do -- Transaxial Gearboxes Mass = Gear3SW, Switch = ShiftS, MaxTorque = Gear3ST, - Automatic = true, }) ACF.RegisterGearbox("3Gear-A-T-M", "3-Auto", { @@ -112,7 +209,6 @@ do -- Transaxial Gearboxes Mass = Gear3MW, Switch = ShiftM, MaxTorque = Gear3MT, - Automatic = true, }) ACF.RegisterGearbox("3Gear-A-T-L", "3-Auto", { @@ -122,7 +218,6 @@ do -- Transaxial Gearboxes Mass = Gear3LW, Switch = ShiftL, MaxTorque = Gear3LT, - Automatic = true, }) end @@ -134,7 +229,6 @@ do -- Transaxial Dual Clutch Gearboxes Mass = Gear3SW, Switch = ShiftS, MaxTorque = Gear3ST, - Automatic = true, DualClutch = true, }) @@ -145,7 +239,6 @@ do -- Transaxial Dual Clutch Gearboxes Mass = Gear3MW, Switch = ShiftM, MaxTorque = Gear3MT, - Automatic = true, DualClutch = true, }) @@ -156,7 +249,6 @@ do -- Transaxial Dual Clutch Gearboxes Mass = Gear3LW, Switch = ShiftL, MaxTorque = Gear3LT, - Automatic = true, DualClutch = true, }) end @@ -169,7 +261,6 @@ do -- Straight-through Gearboxes Mass = math.floor(Gear3SW * StWB), Switch = ShiftS, MaxTorque = math.floor(Gear3ST * StTB), - Automatic = true, }) ACF.RegisterGearbox("3Gear-A-ST-M", "3-Auto", { @@ -179,7 +270,6 @@ do -- Straight-through Gearboxes Mass = math.floor(Gear3MW * StWB), Switch = ShiftM, MaxTorque = math.floor(Gear3MT * StTB), - Automatic = true, }) ACF.RegisterGearbox("3Gear-A-ST-L", "3-Auto", { @@ -189,6 +279,5 @@ do -- Straight-through Gearboxes Mass = math.floor(Gear3LW * StWB), Switch = ShiftL, MaxTorque = math.floor(Gear3LT * StTB), - Automatic = true, }) end diff --git a/lua/acf/shared/gearboxes/5-auto.lua b/lua/acf/shared/gearboxes/5-auto.lua index c0755a1ca..30c510a9d 100644 --- a/lua/acf/shared/gearboxes/5-auto.lua +++ b/lua/acf/shared/gearboxes/5-auto.lua @@ -18,13 +18,116 @@ local ShiftS = 0.25 local ShiftM = 0.35 local ShiftL = 0.5 +local function CheckNumber(Value) + if not Value then return end -- nil or false, both are not numbers + + return tonumber(Value) +end + +local function InitGearbox(Gearbox) + local Gears = Gearbox.Gears + + Gearbox.Automatic = true + Gearbox.ShiftScale = 1 + Gearbox.Hold = false + Gearbox.GearCount = Gearbox.MaxGear + 1 + + Gears[Gearbox.GearCount] = Gearbox.Reverse + + Gearbox:ChangeDrive(1) +end + ACF.RegisterGearboxClass("5-Auto", { Name = "5-Speed Automatic", CreateMenu = ACF.AutomaticGearboxMenu, Gears = { Min = 0, Max = 5, - } + }, + OnSpawn = InitGearbox, + OnUpdate = InitGearbox, + VerifyData = function(Data, Class) + do -- Shift point table verification + local Points = Data.ShiftPoints + local Mult = Data.ShiftUnit or 1 + local Max = Class.Gears.Max + + if not istable(Points) then + local Encoded = Data.Gear9 and tostring(Data.Gear9) + + Points = { [0] = -1 } + + if Encoded then + local Count = 0 + + for Point in string.gmatch(Encoded, "[^,]+") do + Count = Count + 1 + + if Count > Max then break end + + Points[Count] = CheckNumber(Point) or Count * 100 + end + end + + Data.ShiftPoints = Points + else + Points[0] = -1 + end + + for I = 1, Max do + local Point = CheckNumber(Points[I]) + + if not Point then + Point = (CheckNumber(Data["Shift" .. I]) or I * 100) * Mult + + Data["Shift" .. I] = nil + end + + Points[I] = math.Clamp(Point, 0, 9999) + end + end + + do -- Reverse gear verification + local Reverse = CheckNumber(Data.Reverse) + + if not Reverse then + Reverse = CheckNumber(Data.Gear8) or -1 + + Data.Gear8 = nil + end + + Data.Reverse = math.Clamp(Reverse, -1, 1) + end + end, + SetupInputs = function(List) + local Count = #List + + List[Count + 1] = "Hold Gear" + List[Count + 2] = "Shift Speed Scale" + end, + OnLast = function(Gearbox) + Gearbox.Automatic = nil + Gearbox.ShiftScale = nil + Gearbox.Drive = nil + Gearbox.Hold = nil + end, + GetGearsText = function(Gearbox) + local GearText = "Gear %s: %s, Upshift @ %s kph / %s mph\n" + local Text = "%sReverse gear: %s\n" + local Points = Gearbox.ShiftPoints + local Gears = Gearbox.Gears + local GearsText = "" + + for I = 1, Gearbox.MaxGear do + local Ratio = math.Round(Gears[I], 2) + local KPH = math.Round(Points[I] / 10.936, 1) + local MPH = math.Round(Points[I] / 17.6, 1) + + GearsText = GearsText .. GearText:format(I, Ratio, KPH, MPH) + end + + return Text:format(GearsText, math.Round(Gearbox.Reverse, 2)) + end, }) do -- Inline Gearboxes @@ -35,7 +138,6 @@ do -- Inline Gearboxes Mass = Gear5SW, Switch = ShiftS, MaxTorque = Gear5ST, - Automatic = true, }) ACF.RegisterGearbox("5Gear-A-L-M", "5-Auto", { @@ -45,7 +147,6 @@ do -- Inline Gearboxes Mass = Gear5MW, Switch = ShiftM, MaxTorque = Gear5MT, - Automatic = true, }) ACF.RegisterGearbox("5Gear-A-L-L", "5-Auto", { @@ -55,7 +156,6 @@ do -- Inline Gearboxes Mass = Gear5LW, Switch = ShiftL, MaxTorque = Gear5LT, - Automatic = true, }) end @@ -67,7 +167,6 @@ do -- Inline Dual Clutch Gearboxes Mass = Gear5SW, Switch = ShiftS, MaxTorque = Gear5ST, - Automatic = true, DualClutch = true, }) @@ -78,7 +177,6 @@ do -- Inline Dual Clutch Gearboxes Mass = Gear5MW, Switch = ShiftM, MaxTorque = Gear5MT, - Automatic = true, DualClutch = true, }) @@ -89,7 +187,6 @@ do -- Inline Dual Clutch Gearboxes Mass = Gear5LW, Switch = ShiftL, MaxTorque = Gear5LT, - Automatic = true, DualClutch = true, }) end @@ -102,7 +199,6 @@ do -- Transaxial Gearboxes Mass = Gear5SW, Switch = ShiftS, MaxTorque = Gear5ST, - Automatic = true, }) ACF.RegisterGearbox("5Gear-A-T-M", "5-Auto", { @@ -112,7 +208,6 @@ do -- Transaxial Gearboxes Mass = Gear5MW, Switch = ShiftM, MaxTorque = Gear5MT, - Automatic = true, }) ACF.RegisterGearbox("5Gear-A-T-L", "5-Auto", { @@ -122,7 +217,6 @@ do -- Transaxial Gearboxes Mass = Gear5LW, Switch = ShiftL, MaxTorque = Gear5LT, - Automatic = true, }) end @@ -134,7 +228,6 @@ do -- Transaxial Dual Clutch Gearboxes Mass = Gear5SW, Switch = ShiftS, MaxTorque = Gear5ST, - Automatic = true, DualClutch = true, }) @@ -145,7 +238,6 @@ do -- Transaxial Dual Clutch Gearboxes Mass = Gear5MW, Switch = ShiftM, MaxTorque = Gear5MT, - Automatic = true, DualClutch = true, }) @@ -156,7 +248,6 @@ do -- Transaxial Dual Clutch Gearboxes Mass = Gear5LW, Switch = ShiftL, MaxTorque = Gear5LT, - Automatic = true, DualClutch = true, }) end @@ -169,7 +260,6 @@ do -- Straight-through Gearboxes Mass = math.floor(Gear5SW * StWB), Switch = ShiftS, MaxTorque = math.floor(Gear5ST * StTB), - Automatic = true, }) ACF.RegisterGearbox("5Gear-A-ST-M", "5-Auto", { @@ -179,7 +269,6 @@ do -- Straight-through Gearboxes Mass = math.floor(Gear5MW * StWB), Switch = ShiftM, MaxTorque = math.floor(Gear5MT * StTB), - Automatic = true, }) ACF.RegisterGearbox("5Gear-A-ST-L", "5-Auto", { @@ -189,6 +278,5 @@ do -- Straight-through Gearboxes Mass = math.floor(Gear5LW * StWB), Switch = ShiftL, MaxTorque = math.floor(Gear5LT * StTB), - Automatic = true, }) end diff --git a/lua/acf/shared/gearboxes/7-auto.lua b/lua/acf/shared/gearboxes/7-auto.lua index 9f0c3b785..db3f57df1 100644 --- a/lua/acf/shared/gearboxes/7-auto.lua +++ b/lua/acf/shared/gearboxes/7-auto.lua @@ -18,13 +18,116 @@ local ShiftS = 0.25 local ShiftM = 0.35 local ShiftL = 0.5 +local function CheckNumber(Value) + if not Value then return end -- nil or false, both are not numbers + + return tonumber(Value) +end + +local function InitGearbox(Gearbox) + local Gears = Gearbox.Gears + + Gearbox.Automatic = true + Gearbox.ShiftScale = 1 + Gearbox.Hold = false + Gearbox.GearCount = Gearbox.MaxGear + 1 + + Gears[Gearbox.GearCount] = Gearbox.Reverse + + Gearbox:ChangeDrive(1) +end + ACF.RegisterGearboxClass("7-Auto", { Name = "7-Speed Automatic", CreateMenu = ACF.AutomaticGearboxMenu, Gears = { Min = 0, Max = 7, - } + }, + OnSpawn = InitGearbox, + OnUpdate = InitGearbox, + VerifyData = function(Data, Class) + do -- Shift point table verification + local Points = Data.ShiftPoints + local Mult = Data.ShiftUnit or 1 + local Max = Class.Gears.Max + + if not istable(Points) then + local Encoded = Data.Gear9 and tostring(Data.Gear9) + + Points = { [0] = -1 } + + if Encoded then + local Count = 0 + + for Point in string.gmatch(Encoded, "[^,]+") do + Count = Count + 1 + + if Count > Max then break end + + Points[Count] = CheckNumber(Point) or Count * 100 + end + end + + Data.ShiftPoints = Points + else + Points[0] = -1 + end + + for I = 1, Max do + local Point = CheckNumber(Points[I]) + + if not Point then + Point = (CheckNumber(Data["Shift" .. I]) or I * 100) * Mult + + Data["Shift" .. I] = nil + end + + Points[I] = math.Clamp(Point, 0, 9999) + end + end + + do -- Reverse gear verification + local Reverse = CheckNumber(Data.Reverse) + + if not Reverse then + Reverse = CheckNumber(Data.Gear8) or -1 + + Data.Gear8 = nil + end + + Data.Reverse = math.Clamp(Reverse, -1, 1) + end + end, + SetupInputs = function(List) + local Count = #List + + List[Count + 1] = "Hold Gear" + List[Count + 2] = "Shift Speed Scale" + end, + OnLast = function(Gearbox) + Gearbox.Automatic = nil + Gearbox.ShiftScale = nil + Gearbox.Drive = nil + Gearbox.Hold = nil + end, + GetGearsText = function(Gearbox) + local GearText = "Gear %s: %s, Upshift @ %s kph / %s mph\n" + local Text = "%sReverse gear: %s\n" + local Points = Gearbox.ShiftPoints + local Gears = Gearbox.Gears + local GearsText = "" + + for I = 1, Gearbox.MaxGear do + local Ratio = math.Round(Gears[I], 2) + local KPH = math.Round(Points[I] / 10.936, 1) + local MPH = math.Round(Points[I] / 17.6, 1) + + GearsText = GearsText .. GearText:format(I, Ratio, KPH, MPH) + end + + return Text:format(GearsText, math.Round(Gearbox.Reverse, 2)) + end, }) do -- Inline Gearboxes @@ -35,7 +138,6 @@ do -- Inline Gearboxes Mass = Gear7SW, Switch = ShiftS, MaxTorque = Gear7ST, - Automatic = true, }) ACF.RegisterGearbox("7Gear-A-L-M", "7-Auto", { @@ -45,7 +147,6 @@ do -- Inline Gearboxes Mass = Gear7MW, Switch = ShiftM, MaxTorque = Gear7MT, - Automatic = true, }) ACF.RegisterGearbox("7Gear-A-L-L", "7-Auto", { @@ -55,7 +156,6 @@ do -- Inline Gearboxes Mass = Gear7LW, Switch = ShiftL, MaxTorque = Gear7LT, - Automatic = true, }) end @@ -67,7 +167,6 @@ do -- Inline Dual Clutch Gearboxes Mass = Gear7SW, Switch = ShiftS, MaxTorque = Gear7ST, - Automatic = true, DualClutch = true, }) @@ -78,7 +177,6 @@ do -- Inline Dual Clutch Gearboxes Mass = Gear7MW, Switch = ShiftM, MaxTorque = Gear7MT, - Automatic = true, DualClutch = true, }) @@ -89,7 +187,6 @@ do -- Inline Dual Clutch Gearboxes Mass = Gear7LW, Switch = ShiftL, MaxTorque = Gear7LT, - Automatic = true, DualClutch = true, }) end @@ -102,7 +199,6 @@ do -- Transaxial Gearboxes Mass = Gear7SW, Switch = ShiftS, MaxTorque = Gear7ST, - Automatic = true, }) ACF.RegisterGearbox("7Gear-A-T-M", "7-Auto", { @@ -112,7 +208,6 @@ do -- Transaxial Gearboxes Mass = Gear7MW, Switch = ShiftM, MaxTorque = Gear7MT, - Automatic = true, }) ACF.RegisterGearbox("7Gear-A-T-L", "7-Auto", { @@ -122,7 +217,6 @@ do -- Transaxial Gearboxes Mass = Gear7LW, Switch = ShiftL, MaxTorque = Gear7LT, - Automatic = true, }) end @@ -134,7 +228,6 @@ do -- Transaxial Dual Clutch Gearboxes Mass = Gear7SW, Switch = ShiftS, MaxTorque = Gear7ST, - Automatic = true, DualClutch = true, }) @@ -145,7 +238,6 @@ do -- Transaxial Dual Clutch Gearboxes Mass = Gear7MW, Switch = ShiftM, MaxTorque = Gear7MT, - Automatic = true, DualClutch = true, }) @@ -156,7 +248,6 @@ do -- Transaxial Dual Clutch Gearboxes Mass = Gear7LW, Switch = ShiftL, MaxTorque = Gear7LT, - Automatic = true, DualClutch = true, }) end @@ -169,7 +260,6 @@ do -- Straight-through Gearboxes Mass = math.floor(Gear7SW * StWB), Switch = ShiftS, MaxTorque = math.floor(Gear7ST * StTB), - Automatic = true, }) ACF.RegisterGearbox("7Gear-A-ST-M", "7-Auto", { @@ -179,7 +269,6 @@ do -- Straight-through Gearboxes Mass = math.floor(Gear7MW * StWB), Switch = ShiftM, MaxTorque = math.floor(Gear7MT * StTB), - Automatic = true, }) ACF.RegisterGearbox("7Gear-A-ST-L", "7-Auto", { @@ -189,6 +278,5 @@ do -- Straight-through Gearboxes Mass = math.floor(Gear7LW * StWB), Switch = ShiftL, MaxTorque = math.floor(Gear7LT * StTB), - Automatic = true, }) end diff --git a/lua/acf/shared/gearboxes/clutch.lua b/lua/acf/shared/gearboxes/clutch.lua index 642388edc..97681f4bb 100644 --- a/lua/acf/shared/gearboxes/clutch.lua +++ b/lua/acf/shared/gearboxes/clutch.lua @@ -90,7 +90,7 @@ ACF.RegisterGearboxClass("Clutch", { Name = "Clutch", CreateMenu = ACF.ManualGearboxMenu, Gears = { - Min = 1, + Min = 0, Max = 1, } }) diff --git a/lua/acf/shared/gearboxes/cvt.lua b/lua/acf/shared/gearboxes/cvt.lua index 4051cf546..6675f1ea5 100644 --- a/lua/acf/shared/gearboxes/cvt.lua +++ b/lua/acf/shared/gearboxes/cvt.lua @@ -323,13 +323,73 @@ ACF_DefineGearbox("CVT-ST-L", { } }) +local function CheckNumber(Value) + if not Value then return end -- nil or false, both are not numbers + + return tonumber(Value) +end + +local function InitGearbox(Gearbox) + local Gears = Gearbox.Gears + + Gearbox.CVT = true + Gearbox.CVTRatio = 0 + + WireLib.TriggerOutput(Gearbox, "Min Target RPM", Gears.MinRPM) + WireLib.TriggerOutput(Gearbox, "Max Target RPM", Gears.MaxRPM) +end + ACF.RegisterGearboxClass("CVT", { Name = "CVT", CreateMenu = ACF.CVTGearboxMenu, Gears = { Min = 0, Max = 2, - } + }, + OnSpawn = InitGearbox, + OnUpdate = InitGearbox, + VerifyData = function(Data) + local Min, Max = Data.MinRPM, Data.MaxRPM + + Data.Gears[1] = 0.01 + + if not Min then + Min = CheckNumber(Data.Gear3) or 3000 + + Data.Gear3 = nil + end + + if not Max then + Max = CheckNumber(Data.Gear4) or 5000 + + Data.Gear4 = nil + end + + Data.MinRPM = math.Clamp(Min, 1, 9900) + Data.MaxRPM = math.Clamp(Max, Data.MinRPM + 100, 10000) + end, + SetupInputs = function(List) + List[#List + 1] = "CVT Ratio" + end, + SetupOutputs = function(List) + local Count = #List + + List[Count + 1] = "Min Target RPM" + List[Count + 2] = "Max Target RPM" + end, + OnLast = function(Gearbox) + Gearbox.CVT = nil + Gearbox.CVTRatio = nil + end, + GetGearsText = function(Gearbox) + local Text = "Reverse Gear: %s\nTarget: %s - %s RPM" + local Gears = Gearbox.Gears + local Reverse = math.Round(Gears[2], 2) + local Min = math.Round(Gearbox.MinRPM, 0) + local Max = math.Round(Gearbox.MaxRPM, 0) + + return Text:format(Reverse, Min, Max) + end, }) do -- Inline Gearboxes @@ -340,7 +400,6 @@ do -- Inline Gearboxes Mass = GearCVTSW, Switch = 0.15, MaxTorque = GearCVTST, - CVT = true, }) ACF.RegisterGearbox("CVT-L-M", "CVT", { @@ -350,7 +409,6 @@ do -- Inline Gearboxes Mass = GearCVTMW, Switch = 0.2, MaxTorque = GearCVTMT, - CVT = true, }) ACF.RegisterGearbox("CVT-L-L", "CVT", { @@ -360,7 +418,6 @@ do -- Inline Gearboxes Mass = GearCVTLW, Switch = 0.3, MaxTorque = GearCVTLT, - CVT = true, }) end @@ -373,7 +430,6 @@ do -- Inline Dual Clutch Gearboxes Switch = 0.15, MaxTorque = GearCVTST, DualClutch = true, - CVT = true, }) ACF.RegisterGearbox("CVT-LD-M", "CVT", { @@ -384,7 +440,6 @@ do -- Inline Dual Clutch Gearboxes Switch = 0.2, MaxTorque = GearCVTMT, DualClutch = true, - CVT = true, }) ACF.RegisterGearbox("CVT-LD-L", "CVT", { @@ -395,7 +450,6 @@ do -- Inline Dual Clutch Gearboxes Switch = 0.3, MaxTorque = GearCVTLT, DualClutch = true, - CVT = true, }) end @@ -407,7 +461,6 @@ do -- Transaxial Gearboxes Mass = GearCVTSW, Switch = 0.15, MaxTorque = GearCVTST, - CVT = true, }) ACF.RegisterGearbox("CVT-T-M", "CVT", { @@ -417,7 +470,6 @@ do -- Transaxial Gearboxes Mass = GearCVTMW, Switch = 0.2, MaxTorque = GearCVTMT, - CVT = true, }) ACF.RegisterGearbox("CVT-T-L", "CVT", { @@ -427,7 +479,6 @@ do -- Transaxial Gearboxes Mass = GearCVTLW, Switch = 0.3, MaxTorque = GearCVTLT, - CVT = true, }) end @@ -440,7 +491,6 @@ do -- Transaxial Dual Clutch Gearboxes Switch = 0.15, MaxTorque = GearCVTST, DualClutch = true, - CVT = true, }) ACF.RegisterGearbox("CVT-TD-M", "CVT", { @@ -451,7 +501,6 @@ do -- Transaxial Dual Clutch Gearboxes Switch = 0.2, MaxTorque = GearCVTMT, DualClutch = true, - CVT = true, }) ACF.RegisterGearbox("CVT-TD-L", "CVT", { @@ -462,7 +511,6 @@ do -- Transaxial Dual Clutch Gearboxes Switch = 0.3, MaxTorque = GearCVTLT, DualClutch = true, - CVT = true, }) end @@ -474,7 +522,6 @@ do -- Straight-through Gearboxes Mass = math.floor(GearCVTSW * StWB), Switch = 0.15, MaxTorque = math.floor(GearCVTST * StTB), - CVT = true, }) ACF.RegisterGearbox("CVT-ST-M", "CVT", { @@ -484,7 +531,6 @@ do -- Straight-through Gearboxes Mass = math.floor(GearCVTMW * StWB), Switch = 0.2, MaxTorque = math.floor(GearCVTMT * StTB), - CVT = true, }) ACF.RegisterGearbox("CVT-ST-L", "CVT", { @@ -494,6 +540,5 @@ do -- Straight-through Gearboxes Mass = math.floor(GearCVTLW * StWB), Switch = 0.3, MaxTorque = math.floor(GearCVTLT * StTB), - CVT = true, }) end diff --git a/lua/acf/shared/gearboxes/differential.lua b/lua/acf/shared/gearboxes/differential.lua index 36c4b7412..f1607826c 100644 --- a/lua/acf/shared/gearboxes/differential.lua +++ b/lua/acf/shared/gearboxes/differential.lua @@ -227,7 +227,7 @@ ACF.RegisterGearboxClass("Differential", { Name = "Differential", CreateMenu = ACF.ManualGearboxMenu, Gears = { - Min = 1, + Min = 0, Max = 1, } }) diff --git a/lua/acf/shared/gearboxes/doublediff.lua b/lua/acf/shared/gearboxes/doublediff.lua index 64fbed8d0..b346e2867 100644 --- a/lua/acf/shared/gearboxes/doublediff.lua +++ b/lua/acf/shared/gearboxes/doublediff.lua @@ -68,16 +68,34 @@ ACF_DefineGearbox("DoubleDiff-T-L", { } }) +local function InitGearbox(Gearbox) + Gearbox.DoubleDiff = true + Gearbox.SteerRate = 0 + + Gearbox:SetBodygroup(1, 1) +end + ACF.RegisterGearboxClass("DoubleDiff", { - Name = "Regenerative Steering", + Name = "Double Differential", CreateMenu = ACF.ManualGearboxMenu, Gears = { - Min = 1, + Min = 0, Max = 1, - } + }, + OnSpawn = InitGearbox, + OnUpdate = InitGearbox, + SetupInputs = function(List) + List[#List + 1] = "Steer Rate" + end, + OnLast = function(Gearbox) + Gearbox.DoubleDiff = nil + Gearbox.SteerRate = nil + + Gearbox:SetBodygroup(1, 0) + end, }) -do -- Inline Gearboxes +do -- Transaxial Gearboxes ACF.RegisterGearbox("DoubleDiff-T-S", "DoubleDiff", { Name = "Double Differential, Small", Description = "A light duty regenerative steering transmission.", @@ -86,7 +104,6 @@ do -- Inline Gearboxes Switch = 0.2, MaxTorque = GearDDST, DualClutch = true, - DoubleDiff = true, }) ACF.RegisterGearbox("DoubleDiff-T-M", "DoubleDiff", { @@ -97,7 +114,6 @@ do -- Inline Gearboxes Switch = 0.35, MaxTorque = GearDDMT, DualClutch = true, - DoubleDiff = true, }) ACF.RegisterGearbox("DoubleDiff-T-L", "DoubleDiff", { @@ -108,6 +124,5 @@ do -- Inline Gearboxes Switch = 0.5, MaxTorque = GearDDLT, DualClutch = true, - DoubleDiff = true, }) end diff --git a/lua/acf/shared/gearboxes/transfer.lua b/lua/acf/shared/gearboxes/transfer.lua index 2ffff9163..2366563d4 100644 --- a/lua/acf/shared/gearboxes/transfer.lua +++ b/lua/acf/shared/gearboxes/transfer.lua @@ -127,7 +127,7 @@ ACF.RegisterGearboxClass("Transfer", { Name = "Transfer Case", CreateMenu = ACF.ManualGearboxMenu, Gears = { - Min = 1, + Min = 0, Max = 2, } }) diff --git a/lua/entities/acf_engine/init.lua b/lua/entities/acf_engine/init.lua index cfb68f78d..d332340a7 100644 --- a/lua/entities/acf_engine/init.lua +++ b/lua/entities/acf_engine/init.lua @@ -229,6 +229,8 @@ end --===============================================================================================-- do -- Spawn and Update functions + local HookRun = hook.Run + local function VerifyData(Data) -- Entity was created via menu tool if Data.Engine then @@ -239,6 +241,16 @@ do -- Spawn and Update functions if not Class then Data.Id = "5.7-V8" + + Class = ACF.GetClassGroup(Engines, Data.Id) + end + + do -- External verifications + if Class.VerifyData then + Class.VerifyData(Data, Class) + end + + HookRun("ACF_VerifyData", "acf_engine", Data, Class) end end @@ -256,28 +268,29 @@ do -- Spawn and Update functions Entity[V] = Data[V] end - Entity.Name = EngineData.Name - Entity.ShortName = EngineData.ID - Entity.EntType = Class.ID - Entity.SoundPitch = EngineData.Pitch or 1 - Entity.PeakTorque = EngineData.Torque - Entity.PeakTorqueHeld = EngineData.Torque - Entity.IdleRPM = EngineData.RPM.Idle - Entity.PeakMinRPM = EngineData.RPM.PeakMin - Entity.PeakMaxRPM = EngineData.RPM.PeakMax - Entity.LimitRPM = EngineData.RPM.Limit + Entity.Name = EngineData.Name + Entity.ShortName = EngineData.ID + Entity.EntType = Class.Name + Entity.ClassData = Class + Entity.SoundPitch = EngineData.Pitch or 1 + Entity.PeakTorque = EngineData.Torque + Entity.PeakTorqueHeld = EngineData.Torque + Entity.IdleRPM = EngineData.RPM.Idle + Entity.PeakMinRPM = EngineData.RPM.PeakMin + Entity.PeakMaxRPM = EngineData.RPM.PeakMax + Entity.LimitRPM = EngineData.RPM.Limit Entity.FlywheelOverride = EngineData.RPM.Override - Entity.Inertia = EngineData.FlywheelMass * 3.1416 ^ 2 - Entity.IsElectric = EngineData.IsElectric - Entity.IsTrans = EngineData.IsTrans -- driveshaft outputs to the side - Entity.FuelTypes = EngineData.Fuel or { Petrol = true } - Entity.FuelType = next(EngineData.Fuel) - Entity.EngineType = EngineType.ID - Entity.Efficiency = EngineType.Efficiency * GetEfficiencyMult() - Entity.TorqueScale = EngineType.TorqueScale - Entity.HealthMult = EngineType.HealthMult - Entity.HitBoxes = ACF.HitBoxes[EngineData.Model] - Entity.Out = Entity:WorldToLocal(Entity:GetAttachment(Entity:LookupAttachment("driveshaft")).Pos) + Entity.Inertia = EngineData.FlywheelMass * 3.1416 ^ 2 + Entity.IsElectric = EngineData.IsElectric + Entity.IsTrans = EngineData.IsTrans -- driveshaft outputs to the side + Entity.FuelTypes = EngineData.Fuel or { Petrol = true } + Entity.FuelType = next(EngineData.Fuel) + Entity.EngineType = EngineType.ID + Entity.Efficiency = EngineType.Efficiency * GetEfficiencyMult() + Entity.TorqueScale = EngineType.TorqueScale + Entity.HealthMult = EngineType.HealthMult + Entity.HitBoxes = ACF.HitBoxes[EngineData.Model] + Entity.Out = Entity:WorldToLocal(Entity:GetAttachment(Entity:LookupAttachment("driveshaft")).Pos) Entity:SetNWString("WireName", "ACF " .. Entity.Name) @@ -306,8 +319,6 @@ do -- Spawn and Update functions local Phys = Entity:GetPhysicsObject() if IsValid(Phys) then Phys:SetMass(EngineData.Mass) end - - Entity:UpdateOverlay(true) end function MakeACF_Engine(Player, Pos, Angle, Data) @@ -343,7 +354,7 @@ do -- Spawn and Update functions Engine.SoundPath = EngineData.Sound Engine.Inputs = WireLib.CreateInputs(Engine, { "Active", "Throttle" }) Engine.Outputs = WireLib.CreateOutputs(Engine, { "RPM", "Torque", "Power", "Fuel Use", "Entity [ENTITY]", "Mass", "Physical Mass" }) - Engine.DataStore = ACF.GetEntClassVars("acf_engine") + Engine.DataStore = ACF.GetEntityArguments("acf_engine") WireLib.TriggerOutput(Engine, "Entity", Engine) @@ -353,6 +364,10 @@ do -- Spawn and Update functions Class.OnSpawn(Engine, Data, Class, EngineData) end + HookRun("ACF_OnEntitySpawn", "acf_engine", Engine, Data, Class, EngineData) + + Engine:UpdateOverlay(true) + do -- Mass entity mod removal local EntMods = Data and Data.EntityMods @@ -377,9 +392,16 @@ do -- Spawn and Update functions VerifyData(Data) - local Class = ACF.GetClassGroup(Engines, Data.Id) + local Class = ACF.GetClassGroup(Engines, Data.Id) local EngineData = Class.Lookup[Data.Id] - local Feedback = "" + local OldClass = self.ClassData + local Feedback = "" + + if OldClass.OnLast then + OldClass.OnLast(self, OldClass) + end + + HookRun("ACF_OnEntityLast", "acf_engine", self, OldClass) ACF.SaveEntity(self) @@ -391,6 +413,8 @@ do -- Spawn and Update functions Class.OnUpdate(self, Data, Class, EngineData) end + HookRun("ACF_OnEntityUpdate", "acf_engine", self, Data, Class, EngineData) + if next(self.Gearboxes) then local Count, Total = 0, 0 @@ -435,6 +459,12 @@ do -- Spawn and Update functions end end + self:UpdateOverlay(true) + + net.Start("ACF_UpdateEntity") + net.WriteEntity(self) + net.Broadcast() + return true, "Engine updated successfully!" .. Feedback end end @@ -804,6 +834,14 @@ function ENT:PostEntityPaste(Player, Ent, CreatedEntities) end function ENT:OnRemove() + local Class = self.ClassData + + if Class.OnLast then + Class.OnLast(self, Class) + end + + HookRun("ACF_OnEntityLast", "acf_engine", self, Class) + if self.Sound then self.Sound:Stop() end diff --git a/lua/entities/acf_fueltank/init.lua b/lua/entities/acf_fueltank/init.lua index 2ba4cbfaf..6612150d0 100644 --- a/lua/entities/acf_fueltank/init.lua +++ b/lua/entities/acf_fueltank/init.lua @@ -17,6 +17,7 @@ local Inputs = ACF.GetInputActions("acf_fueltank") local RefillDist = ACF.RefillDistance * ACF.RefillDistance local TimerCreate = timer.Create local TimerExists = timer.Exists +local HookRun = hook.Run local Wall = 0.03937 --wall thickness in inches (1mm) local function CanRefuel(Refill, Tank, Distance) @@ -42,12 +43,22 @@ do -- Spawn and Update functions if not Class then Data.Id = "Jerry_Can" + + Class = ACF.GetClassGroup(FuelTanks, Data.Id) end -- Making sure to provide a valid fuel type if not (Data.FuelType and FuelTypes[Data.FuelType]) then Data.FuelType = "Petrol" end + + do -- External verifications + if Class.VerifyData then + Class.VerifyData(Data, Class) + end + + HookRun("ACF_VerifyData", "acf_fueltank", Data, Class) + end end local function UpdateFuelTank(Entity, Data, Class, FuelTank) @@ -72,15 +83,16 @@ do -- Spawn and Update functions Percentage = Entity.Fuel / Entity.Capacity end - Entity.Name = FuelTank.Name - Entity.ShortName = Entity.Id - Entity.EntType = Class.Name - Entity.FuelDensity = FuelData.Density - Entity.Volume = PhysObj:GetVolume() - (Area * Wall) -- total volume of tank (cu in), reduced by wall thickness - Entity.Capacity = Entity.Volume * ACF.CuIToLiter * ACF.TankVolumeMul * 0.4774 --internal volume available for fuel in liters, with magic realism number - Entity.EmptyMass = (Area * Wall) * 16.387 * (7.9 / 1000) -- total wall volume * cu in to cc * density of steel (kg/cc) - Entity.IsExplosive = FuelTank.IsExplosive - Entity.NoLinks = FuelTank.Unlinkable + Entity.Name = FuelTank.Name + Entity.ShortName = Entity.Id + Entity.EntType = Class.Name + Entity.ClassData = Class + Entity.FuelDensity = FuelData.Density + Entity.Volume = PhysObj:GetVolume() - (Area * Wall) -- total volume of tank (cu in), reduced by wall thickness + Entity.Capacity = Entity.Volume * ACF.CuIToLiter * ACF.TankVolumeMul * 0.4774 --internal volume available for fuel in liters, with magic realism number + Entity.EmptyMass = (Area * Wall) * 16.387 * (7.9 / 1000) -- total wall volume * cu in to cc * density of steel (kg/cc) + Entity.IsExplosive = FuelTank.IsExplosive + Entity.NoLinks = FuelTank.Unlinkable Entity.HitBoxes = { Main = { Pos = Entity:OBBCenter(), @@ -102,7 +114,6 @@ do -- Spawn and Update functions Entity.ACF.Model = FuelTank.Model Entity:UpdateMass(true) - Entity:UpdateOverlay(true) WireLib.TriggerOutput(Entity, "Fuel", Entity.Fuel) WireLib.TriggerOutput(Entity, "Capacity", Entity.Capacity) @@ -132,22 +143,23 @@ do -- Spawn and Update functions Tank.Owner = Player -- MUST be stored on ent for PP Tank.Engines = {} Tank.Leaking = 0 - Tank.CanUpdate = true Tank.LastThink = 0 Tank.Inputs = WireLib.CreateInputs(Tank, { "Active", "Refuel Duty" }) Tank.Outputs = WireLib.CreateOutputs(Tank, { "Activated", "Fuel", "Capacity", "Leaking", "Entity [ENTITY]" }) - Tank.DataStore = ACF.GetEntClassVars("acf_fueltank") + Tank.DataStore = ACF.GetEntityArguments("acf_fueltank") WireLib.TriggerOutput(Tank, "Entity", Tank) - ActiveTanks[Tank] = true - UpdateFuelTank(Tank, Data, Class, FuelTank) if Class.OnSpawn then Class.OnSpawn(Tank, Data, Class, FuelTank) end + HookRun("ACF_OnEntitySpawn", "acf_fueltank", Tank, Data, Class, FuelTank) + + Tank:UpdateOverlay(true) + do -- Mass entity mod removal local EntMods = Data and Data.EntityMods @@ -159,6 +171,8 @@ do -- Spawn and Update functions -- Fuel tanks should be active by default Tank:TriggerInput("Active", 1) + ActiveTanks[Tank] = true + CheckLegal(Tank) return Tank @@ -174,8 +188,15 @@ do -- Spawn and Update functions local Class = ACF.GetClassGroup(FuelTanks, Data.Id) local FuelTank = Class.Lookup[Data.Id] + local OldClass = self.ClassData local Feedback = "" + if OldClass.OnLast then + OldClass.OnLast(self, OldClass) + end + + HookRun("ACF_OnEntityLast", "acf_fueltank", self, OldClass) + ACF.SaveEntity(self) UpdateFuelTank(self, Data, Class, FuelTank) @@ -186,6 +207,8 @@ do -- Spawn and Update functions Class.OnUpdate(self, Data, Class, FuelTank) end + HookRun("ACF_OnEntityUpdate", "acf_fueltank", self, Data, Class, FuelTank) + if next(self.Engines) then local FuelType = self.FuelType local NoLinks = self.NoLinks @@ -210,6 +233,8 @@ do -- Spawn and Update functions end end + self:UpdateOverlay(true) + net.Start("ACF_UpdateEntity") net.WriteEntity(self) net.Broadcast() @@ -256,9 +281,7 @@ function ENT:ACF_OnDamage(Entity, Energy, FrArea, Angle, Inflictor, _, Type) if self.Exploding or NoExplode or not self.IsExplosive then return HitRes end if HitRes.Kill then - if hook.Run("ACF_FuelExplode", self) == false then return HitRes end - - self.Exploding = true + if HookRun("ACF_FuelExplode", self) == false then return HitRes end if IsValid(Inflictor) and Inflictor:IsPlayer() then self.Inflictor = Inflictor @@ -274,10 +297,9 @@ function ENT:ACF_OnDamage(Entity, Energy, FrArea, Angle, Inflictor, _, Type) --it's gonna blow if math.random() < (ExplodeChance + Ratio) then - if hook.Run("ACF_FuelExplode", self) == false then return HitRes end + if HookRun("ACF_FuelExplode", self) == false then return HitRes end self.Inflictor = Inflictor - self.Exploding = true self:Detonate() else --spray some fuel around @@ -292,7 +314,9 @@ function ENT:ACF_OnDamage(Entity, Energy, FrArea, Angle, Inflictor, _, Type) end function ENT:Detonate() - self.Damaged = nil -- Prevent multiple explosions + if self.Exploding then return end + + self.Exploding = true -- Prevent multiple explosions local Pos = self:LocalToWorld(self:OBBCenter() + VectorRand() * (self:OBBMaxs() - self:OBBMins()) / 2) local ExplosiveMass = (math.max(self.Fuel, self.Capacity * 0.0025) / self.FuelDensity) * 0.1 @@ -491,7 +515,7 @@ function ENT:Think() if CanRefuel(self, Tank, Position:DistToSqr(Tank:GetPos())) then local Exchange = math.min(DeltaTime * ACF.RefillSpeed * ACF.FuelRate / 1750, self.Fuel, Tank.Capacity - Tank.Fuel) - if hook.Run("ACF_CanRefuel", self, Tank, Exchange) == false then continue end + if HookRun("ACF_CanRefuel", self, Tank, Exchange) == false then continue end self:Consume(Exchange) Tank:Consume(-Exchange) @@ -513,6 +537,14 @@ function ENT:Think() end function ENT:OnRemove() + local Class = self.ClassData + + if Class.OnLast then + Class.OnLast(self, Class) + end + + HookRun("ACF_OnEntityLast", "acf_fueltank", self, Class) + for Engine in pairs(self.Engines) do self:Unlink(Engine) end diff --git a/lua/entities/acf_gearbox/init.lua b/lua/entities/acf_gearbox/init.lua index 844127996..4ad77a7e3 100644 --- a/lua/entities/acf_gearbox/init.lua +++ b/lua/entities/acf_gearbox/init.lua @@ -152,39 +152,12 @@ ACF.RegisterClassUnlink("acf_gearbox", "acf_gearbox", UnlinkGearbox) ACF.RegisterClassUnlink("acf_gearbox", "tire", UnlinkWheel) local CheckLegal = ACF_CheckLegal -local ClassLink = ACF.GetClassLink +local ClassLink = ACF.GetClassLink local ClassUnlink = ACF.GetClassUnlink -local Gearboxes = ACF.Classes.Gearboxes +local Gearboxes = ACF.Classes.Gearboxes local Inputs = ACF.GetInputActions("acf_gearbox") -local Clamp = math.Clamp - -local function ChangeGear(Entity, Value) - Value = Clamp(math.floor(Value), Entity.MinGear, Entity.MaxRealGear) - - if Entity.Gear == Value then return end - - Entity.Gear = Value - Entity.GearRatio = Entity.Gears[Value] * Entity.Gears.Final - Entity.ChangeFinished = ACF.CurTime + Entity.SwitchTime - Entity.InGear = false - - Entity:EmitSound("buttons/lever7.wav", 250, 100) - Entity:UpdateOverlay() - - WireLib.TriggerOutput(Entity, "Current Gear", Value) - WireLib.TriggerOutput(Entity, "Ratio", Entity.GearRatio) -end - ---handles gearing for automatics; 0=neutral, 1=forward autogearing, 2=reverse -local function ChangeDrive(Entity, Value) - Value = Clamp(math.floor(Value), 0, 2) - - if Entity.Drive == Value then return end - - Entity.Drive = Value - - ChangeGear(Entity, Value == 2 and Entity.Reverse or Value) -end +local Clamp = math.Clamp +local HookRun = hook.Run local function CheckRopes(Entity, Target) if not next(Entity[Target]) then return end @@ -236,115 +209,100 @@ end --===============================================================================================-- do -- Spawn and Update functions - local function VerifyData(Data) - Data.Id = Data.Gearbox or Data.Id + local function CheckNumber(Value) + if not Value then return end -- nil or false, both are not numbers - local Class = ACF.GetClassGroup(Gearboxes, Data.Id) + return tonumber(Value) + end - if not Class then - Data.Id = "2Gear-T-S" + local function VerifyData(Data) + if not Data.Gearbox then + Data.Gearbox = Data.Id or "2Gear-T-S" end - if Data.Gearbox then -- Entity was created via menu tool - local Mult = Data.ShiftUnit - local Points = { [0] = -1 } - local Gears = { [0] = 0 } + local Class = ACF.GetClassGroup(Gearboxes, Data.Gearbox) - for I = 1, Data.MaxGears do - Gears[I] = Clamp(Data["Gear" .. I], -1, 1) + if not Class then + Data.Gearbox = "2Gear-T-S" - if Data["Shift" .. I] then - local Value = tonumber(Data["Shift" .. I]) * Mult + Class = ACF.GetClassGroup(Gearboxes, "2Gear-T-S") + end - Points[I] = Clamp(Value, 0, 9999) - end - end + do -- Gears table verification + local Gears = Data.Gears - Gears.Final = Clamp(Data.FinalDrive, -1, 1) + if not istable(Gears) then + Gears = { [0] = 0 } - if Data.Reverse then - Gears.Reverse = Clamp(Data.Reverse, -1, 1) + Data.Gears = Gears + else + Gears[0] = 0 end - if Data.MinRPM then - Gears.MinRPM = Clamp(Data.MinRPM, 1, 9900) - Gears.MaxRPM = Clamp(Data.MaxRPM, Gears.MinRPM + 100, 10000) - end + for I = 1, Class.Gears.Max do + local Gear = CheckNumber(Gears[I]) - Data.Gears = Gears - Data.ShiftPoints = Points + if not Gear then + Gear = CheckNumber(Data["Gear" .. I]) or I * 0.1 - elseif Data.Gear0 then -- Backwards compatibility with ACF-2 dupes - local Points = { [0] = -1 } - local Gears = { [0] = 0 } - local Count = 0 - local Final = tonumber(Data.Gear0) or 1 - local MinRPM = tonumber(Data.Gear3) or 1 - local MaxRPM = tonumber(Data.Gear4) or 101 - local Reverse = tonumber(Data.Gear8) or -1 + Data["Gear" .. I] = nil + end - Gears.Final = Clamp(Final, -1, 1) - Gears.MinRPM = Clamp(MinRPM, 1, 9900) - Gears.MaxRPM = Clamp(MaxRPM, MinRPM + 100, 10000) - Gears.Reverse = Clamp(Reverse, -1, 1) + Gears[I] = Clamp(Gear, -1, 1) + end + end - for Point in string.gmatch(Data.Gear9, "[^,]+") do - local Value = tonumber(Point) + do -- Final drive verification + local Final = CheckNumber(Data.FinalDrive) - Count = Count + 1 + if not Final then + Final = CheckNumber(Data.Gear0) or 1 - Points[Count] = Value and Clamp(Value, 0, 9999) + Data.Gear0 = nil end - for I = 1, 8 do - local Value = tonumber(Data["Gear" .. I]) + Data.FinalDrive = Clamp(Final, -1, 1) + end - if Value then - Gears[I] = Clamp(Data["Gear" .. I], -1, 1) - end + do -- External verifications + if Class.VerifyData then + Class.VerifyData(Data, Class) end - Data.Gears = Gears - Data.ShiftPoints = Points + HookRun("ACF_VerifyData", "acf_gearbox", Data, Class) end end - local function CreateInputs(Entity) + local function CreateInputs(Entity, Data, Class, Gearbox) local List = { "Gear", "Gear Up", "Gear Down" } - if Entity.CVT then - List[#List + 1] = "CVT Ratio" - elseif Entity.DoubleDiff then - List[#List + 1] = "Steer Rate" - elseif Entity.Automatic then - List[#List + 1] = "Hold Gear" - List[#List + 1] = "Shift Speed Scale" + if Class.SetupInputs then + Class.SetupInputs(List, Entity, Data, Class, Gearbox) end - if Entity.DualClutch then - List[#List + 1] = "Left Clutch" - List[#List + 1] = "Right Clutch" - List[#List + 1] = "Left Brake" - List[#List + 1] = "Right Brake" + HookRun("ACF_OnSetupInputs", "acf_gearbox", List, Entity, Data, Class, Gearbox) + + if Entity.Inputs then + Entity.Inputs = WireLib.AdjustInputs(Entity, List) else - List[#List + 1] = "Clutch" - List[#List + 1] = "Brake" + Entity.Inputs = WireLib.CreateInputs(Entity, List) end - - Entity.Inputs = WireLib.CreateInputs(Entity, List) end - local function CreateOutputs(Entity) - local List = { "Ratio", "Entity [ENTITY]", "Current Gear" } + local function CreateOutputs(Entity, Data, Class, Gearbox) + local List = { "Current Gear", "Ratio", "Entity [ENTITY]" } - if Entity.CVT then - List[#List + 1] = "Min Target RPM" - List[#List + 1] = "Max Target RPM" + if Class.SetupOutputs then + Class.SetupOutputs(List, Entity, Data, Class, Gearbox) end - Entity.Outputs = WireLib.CreateOutputs(Entity, List) + HookRun("ACF_OnSetupOutputs", "acf_gearbox", List, Entity, Data, Class, Gearbox) - WireLib.TriggerOutput(Entity, "Entity", Entity) + if Entity.Outputs then + Entity.Outputs = WireLib.AdjustOutputs(Entity, List) + else + Entity.Outputs = WireLib.CreateOutputs(Entity, List) + end end local function UpdateGearbox(Entity, Data, Class, Gearbox) @@ -358,63 +316,26 @@ do -- Spawn and Update functions Entity[V] = Data[V] end - Entity.Name = Gearbox.Name - Entity.ShortName = Entity.Id - Entity.EntType = Class.ID - Entity.SwitchTime = Gearbox.Switch - Entity.MaxTorque = Gearbox.MaxTorque - Entity.MinGear = Class.Gears.Min - Entity.MaxGear = Class.Gears.Max - Entity.MaxRealGear = Entity.MaxGear - Entity.DualClutch = Gearbox.DualClutch - Entity.CVT = Gearbox.CVT - Entity.DoubleDiff = Gearbox.DoubleDiff - Entity.Automatic = Gearbox.Automatic - Entity.LClutch = Entity.MaxTorque - Entity.RClutch = Entity.MaxTorque - Entity.In = Entity:WorldToLocal(Entity:GetAttachment(Entity:LookupAttachment("input")).Pos) - Entity.OutL = Entity:WorldToLocal(Entity:GetAttachment(Entity:LookupAttachment("driveshaftL")).Pos) - Entity.OutR = Entity:WorldToLocal(Entity:GetAttachment(Entity:LookupAttachment("driveshaftR")).Pos) - Entity.HitBoxes = ACF.HitBoxes[Gearbox.Model] - - CreateInputs(Entity) - CreateOutputs(Entity) - - local Gears = Entity.Gears - - if Entity.CVT then - Entity.CVTRatio = 0 - - Gears[1] = 0.01 - - WireLib.TriggerOutput(Entity, "Min Target RPM", Gears.MinRPM) - WireLib.TriggerOutput(Entity, "Max Target RPM", Gears.MaxRPM) - - Entity.ShiftPoints = nil - Gears.Reverse = nil - - elseif Entity.Automatic then - Entity.MaxRealGear = Entity.MaxGear + 1 - Entity.Reverse = Entity.MaxRealGear - Entity.ShiftScale = 1 - Entity.Hold = false - Entity.Drive = 1 - - Gears[Entity.Reverse] = Gears.Reverse - Gears.MinRPM = nil - Gears.MaxRPM = nil - else - Entity.ShiftPoints = nil - Gears.Reverse = nil - Gears.MinRPM = nil - Gears.MaxRPM = nil - end + Entity.Name = Gearbox.Name + Entity.ShortName = Gearbox.ID + Entity.EntType = Class.Name + Entity.ClassData = Class + Entity.SwitchTime = Gearbox.Switch + Entity.MaxTorque = Gearbox.MaxTorque + Entity.MinGear = Class.Gears.Min + Entity.MaxGear = Class.Gears.Max + Entity.GearCount = Entity.MaxGear + Entity.LClutch = Entity.MaxTorque + Entity.RClutch = Entity.MaxTorque + Entity.In = Entity:WorldToLocal(Entity:GetAttachment(Entity:LookupAttachment("input")).Pos) + Entity.OutL = Entity:WorldToLocal(Entity:GetAttachment(Entity:LookupAttachment("driveshaftL")).Pos) + Entity.OutR = Entity:WorldToLocal(Entity:GetAttachment(Entity:LookupAttachment("driveshaftR")).Pos) + Entity.HitBoxes = ACF.HitBoxes[Gearbox.Model] + + CreateInputs(Entity, Data, Class, Gearbox) + CreateOutputs(Entity, Data, Class, Gearbox) - if Entity.DualClutch or Entity.DoubleDiff then - Entity:SetBodygroup(1, 1) - else - Entity:SetBodygroup(1, 0) - end + WireLib.TriggerOutput(Entity, "Entity", Entity) Entity:SetNWString("WireName", "ACF " .. Entity.Name) @@ -426,24 +347,58 @@ do -- Spawn and Update functions local Phys = Entity:GetPhysicsObject() if IsValid(Phys) then Phys:SetMass(Gearbox.Mass) end - -- Force gearbox to forget its gear and drive - Entity.Drive = nil - Entity.Gear = nil + Entity:ChangeGear(1) + end - if Entity.Auto then - ChangeDrive(Entity, 1) - else - ChangeGear(Entity, 1) + -- Some information may still be passed from the menu tool + -- We don't want to save it on the entity if it's not needed + local function CleanupData(Class, Gearbox, _, _, GearboxData) + if Class ~= "acf_gearbox" then return end + + if not Gearbox.Automatic then + Gearbox.Reverse = nil + end + + if not Gearbox.CVT then + Gearbox.MinRPM = nil + Gearbox.MaxRPM = nil end - Entity:UpdateOverlay(true) + if GearboxData.DualClutch then + Gearbox:SetBodygroup(1, 1) + end end + hook.Add("ACF_OnEntitySpawn", "ACF Cleanup Gearbox Data", CleanupData) + hook.Add("ACF_OnEntityUpdate", "ACF Cleanup Gearbox Data", CleanupData) + hook.Add("ACF_OnSetupInputs", "ACF Cleanup Gearbox Data", function(Class, List, _, _, _, GearboxData) + if Class ~= "acf_gearbox" then return end + + local Count = #List + + if GearboxData.DualClutch then + List[Count + 1] = "Left Clutch" + List[Count + 2] = "Right Clutch" + List[Count + 3] = "Left Brake" + List[Count + 4] = "Right Brake" + else + List[Count + 1] = "Clutch" + List[Count + 2] = "Brake" + end + end) + hook.Add("ACF_OnEntityLast", "ACF Cleanup Gearbox Data", function(Class, Gearbox) + if Class ~= "acf_gearbox" then return end + + Gearbox:SetBodygroup(1, 0) + end) + + ------------------------------------------------------------------------------- + function MakeACF_Gearbox(Player, Pos, Angle, Data) VerifyData(Data) - local Class = ACF.GetClassGroup(Gearboxes, Data.Id) - local GearboxData = Class.Lookup[Data.Id] + local Class = ACF.GetClassGroup(Gearboxes, Data.Gearbox) + local GearboxData = Class.Lookup[Data.Gearbox] local Limit = Class.LimitConVar.Name if not Player:CheckLimit(Limit) then return end @@ -469,11 +424,10 @@ do -- Spawn and Update functions Gearbox.TorqueOutput = 0 Gearbox.LBrake = 0 Gearbox.RBrake = 0 - Gearbox.SteerRate = 0 Gearbox.ChangeFinished = 0 Gearbox.InGear = false Gearbox.LastActive = 0 - Gearbox.DataStore = ACF.GetEntClassVars("acf_gearbox") + Gearbox.DataStore = ACF.GetEntityArguments("acf_gearbox") UpdateGearbox(Gearbox, Data, Class, GearboxData) @@ -481,6 +435,10 @@ do -- Spawn and Update functions Class.OnSpawn(Gearbox, Data, Class, GearboxData) end + HookRun("ACF_OnEntitySpawn", "acf_gearbox", Gearbox, Data, Class, GearboxData) + + Gearbox:UpdateOverlay(true) + do -- Mass entity mod removal local EntMods = Data and Data.EntityMods @@ -503,7 +461,7 @@ do -- Spawn and Update functions return Gearbox end - ACF.RegisterEntityClass("acf_gearbox", MakeACF_Gearbox, "Id", "Gears", "ShiftPoints") + ACF.RegisterEntityClass("acf_gearbox", MakeACF_Gearbox, "Gearbox", "Gears", "FinalDrive", "ShiftPoints", "Reverse", "MinRPM", "MaxRPM") ACF.RegisterLinkSource("acf_gearbox", "GearboxIn") ACF.RegisterLinkSource("acf_gearbox", "GearboxOut") ACF.RegisterLinkSource("acf_gearbox", "Engines") @@ -514,9 +472,16 @@ do -- Spawn and Update functions function ENT:Update(Data) VerifyData(Data) - local Class = ACF.GetClassGroup(Gearboxes, Data.Id) - local GearboxData = Class.Lookup[Data.Id] - local Feedback = "" + local Class = ACF.GetClassGroup(Gearboxes, Data.Gearbox) + local GearboxData = Class.Lookup[Data.Gearbox] + local OldClass = self.ClassData + local Feedback = "" + + if OldClass.OnLast then + OldClass.OnLast(self, OldClass) + end + + HookRun("ACF_OnEntityLast", "acf_gearbox", self, OldClass) ACF.SaveEntity(self) @@ -528,6 +493,8 @@ do -- Spawn and Update functions Class.OnUpdate(self, Data, Class, GearboxData) end + HookRun("ACF_OnEntityUpdate", "acf_gearbox", self, Data, Class, GearboxData) + if next(self.Engines) then local Count, Total = 0, 0 @@ -604,6 +571,12 @@ do -- Spawn and Update functions end end + self:UpdateOverlay(true) + + net.Start("ACF_UpdateEntity") + net.WriteEntity(self) + net.Broadcast() + return true, "Gearbox updated successfully!" .. Feedback end end @@ -614,9 +587,9 @@ end function ENT:Enable() if self.Automatic then - ChangeDrive(self, self.OldGear) + self:ChangeDrive(self.OldGear) else - ChangeGear(self, self.OldGear) + self:ChangeGear(self.OldGear) end self.OldGear = nil @@ -628,9 +601,9 @@ function ENT:Disable() self.OldGear = self.Automatic and self.Drive or self.Gear if self.Automatic then - ChangeDrive(self, 0) + self:ChangeDrive(0) else - ChangeGear(self, 0) + self:ChangeGear(0) end self:UpdateOverlay() @@ -641,34 +614,18 @@ local function Overlay(Ent) Ent:SetOverlayText("Disabled: " .. Ent.DisableReason .. "\n" .. Ent.DisableDescription) else local Text = "Current Gear: " .. Ent.Gear .. "\n\n" .. Ent.Name .. "\n" + local GearsText = Ent.ClassData.GetGearsText and Ent.ClassData.GetGearsText(Ent) local Gears = Ent.Gears - if Ent.CVT then - local CVT = "Reverse Gear: %s\nTarget: %s - %s RPM\n" - local Reverse = math.Round(Gears[2], 2) - local Min = math.Round(Gears.MinRPM) - local Max = math.Round(Gears.MaxRPM) - - Text = Text .. CVT:format(Reverse, Min, Max) - elseif Ent.Automatic then - local Gear = "Gear %s: %s, Upshift @ %s kph / %s mph\n" - - for i = 1, Ent.MaxGear do - local Ratio = math.Round(Gears[i], 2) - local KPH = math.Round(Ent.ShiftPoints[i] / 10.936, 1) - local MPH = math.Round(Ent.ShiftPoints[i] / 17.6, 1) - - Text = Text .. Gear:format(i, Ratio, KPH, MPH) - end - - Text = Text .. "Reverse gear: " .. math.Round(Gears[Ent.Reverse], 2) .. "\n" + if GearsText and GearsText ~= "" then + Text = Text .. GearsText .. "\n" else for i = 1, Ent.MaxGear do Text = Text .. "Gear " .. i .. ": " .. math.Round(Gears[i], 2) .. "\n" end end - Text = Text .. "Final Drive: " .. math.Round(Gears.Final, 2) .. "\n" + Text = Text .. "Final Drive: " .. math.Round(Ent.FinalDrive, 2) .. "\n" Text = Text .. "Torque Rating: " .. Ent.MaxTorque .. " Nm / " .. math.Round(Ent.MaxTorque * 0.73) .. " ft-lb\n" Text = Text .. "Torque Output: " .. math.floor(Ent.TorqueOutput) .. " Nm / " .. math.Round(Ent.TorqueOutput * 0.73) .. " ft-lb" @@ -702,9 +659,9 @@ end ACF.AddInputAction("acf_gearbox", "Gear", function(Entity, Value) if Entity.Automatic then - ChangeDrive(Entity, Value) + Entity:ChangeDrive(Value) else - ChangeGear(Entity, Value) + Entity:ChangeGear(Value) end end) @@ -712,9 +669,9 @@ ACF.AddInputAction("acf_gearbox", "Gear Up", function(Entity, Value) if Value == 0 then return end if Entity.Automatic then - ChangeDrive(Entity, Entity.Drive + 1) + Entity:ChangeDrive(Entity.Drive + 1) else - ChangeGear(Entity, Entity.Gear + 1) + Entity:ChangeGear(Entity.Gear + 1) end end) @@ -722,9 +679,9 @@ ACF.AddInputAction("acf_gearbox", "Gear Down", function(Entity, Value) if Value == 0 then return end if Entity.Automatic then - ChangeDrive(Entity, Entity.Drive - 1) + Entity:ChangeDrive(Entity.Drive - 1) else - ChangeGear(Entity, Entity.Gear - 1) + Entity:ChangeGear(Entity.Gear - 1) end end) @@ -782,6 +739,33 @@ function ENT:TriggerInput(Name, Value) end end +-- Handles gearing for automatic gearboxes. 0 = Neutral, 1 = Drive, 2 = Reverse +function ENT:ChangeDrive(Value) + Value = Clamp(math.floor(Value), 0, 2) + + if self.Drive == Value then return end + + self.Drive = Value + + self:ChangeGear(Value == 2 and self.GearCount or Value) +end + +function ENT:ChangeGear(Value) + Value = Clamp(math.floor(Value), self.MinGear, self.GearCount) + + if self.Gear == Value then return end + + self.Gear = Value + self.InGear = false + self.GearRatio = self.Gears[Value] * self.FinalDrive + self.ChangeFinished = ACF.CurTime + self.SwitchTime + + self:EmitSound("buttons/lever7.wav", 250, 100) + + WireLib.TriggerOutput(self, "Current Gear", Value) + WireLib.TriggerOutput(self, "Ratio", self.GearRatio) +end + function ENT:Calc(InputRPM, InputInertia) if self.Disabled then return 0 end if self.LastActive == ACF.CurTime then return self.TorqueOutput end @@ -797,10 +781,10 @@ function ENT:Calc(InputRPM, InputInertia) if self.CVTRatio > 0 then self.Gears[1] = Clamp(self.CVTRatio, 0.01, 1) else - self.Gears[1] = Clamp((InputRPM - self.Gears.MinRPM) / (self.Gears.MaxRPM - self.Gears.MinRPM), 0.05, 1) + self.Gears[1] = Clamp((InputRPM - self.MinRPM) / (self.MaxRPM - self.MinRPM), 0.05, 1) end - self.GearRatio = self.Gears[1] * self.Gears.Final + self.GearRatio = self.Gears[1] * self.FinalDrive WireLib.TriggerOutput(self, "Ratio", self.GearRatio) end @@ -809,9 +793,9 @@ function ENT:Calc(InputRPM, InputInertia) local PhysVel = BoxPhys:GetVelocity():Length() if not self.Hold and self.Gear ~= self.MaxGear and PhysVel > (self.ShiftPoints[self.Gear] * self.ShiftScale) then - ChangeGear(self, self.Gear + 1) + self:ChangeGear(self.Gear + 1) elseif PhysVel < (self.ShiftPoints[self.Gear - 1] * self.ShiftScale) then - ChangeGear(self, self.Gear - 1) + self:ChangeGear(self.Gear - 1) end end @@ -994,6 +978,14 @@ function ENT:PostEntityPaste(Player, Ent, CreatedEntities) end function ENT:OnRemove() + local Class = self.ClassData + + if Class.OnLast then + Class.OnLast(self, Class) + end + + HookRun("ACF_OnEntityLast", "acf_gearbox", self, Class) + for Engine in pairs(self.Engines) do self:Unlink(Engine) end diff --git a/lua/entities/acf_gun/init.lua b/lua/entities/acf_gun/init.lua index 0dcbf0aef..36951bd3c 100644 --- a/lua/entities/acf_gun/init.lua +++ b/lua/entities/acf_gun/init.lua @@ -50,6 +50,14 @@ do -- Spawn and Update functions -------------------------------- if not Class then Data.Id = Data.Id and Updated[Data.Id] or "50mmC" end + + do -- External verifications + if Class.VerifyData then + Class.VerifyData(Data, Class) + end + + HookRun("ACF_VerifyData", "acf_gun", Data, Class) + end end local function UpdateWeapon(Entity, Data, Class, Weapon) @@ -71,21 +79,22 @@ do -- Spawn and Update functions -------------------------------- Entity[V] = Data[V] end - Entity.Name = Weapon.Name - Entity.ShortName = Entity.Id - Entity.EntType = Class.Name - Entity.Caliber = Caliber - Entity.Class = Weapon.ClassID - Entity.MagReload = Weapon.MagReload - Entity.MagSize = Weapon.MagSize or 1 - Entity.Cyclic = Weapon.Cyclic and 60 / Weapon.Cyclic - Entity.ReloadTime = Entity.Cyclic or 1 - Entity.Spread = Class.Spread - Entity.MinLengthBonus = 0.75 * 3.1416 * (Caliber * 0.5) ^ 2 * Weapon.Round.MaxLength - Entity.HitBoxes = ACF.HitBoxes[Weapon.Model] - Entity.Long = Class.LongBarrel - Entity.NormalMuzzle = Entity:WorldToLocal(Entity:GetAttachment(Entity:LookupAttachment("muzzle")).Pos) - Entity.Muzzle = Entity.NormalMuzzle + Entity.Name = Weapon.Name + Entity.ShortName = Entity.Id + Entity.EntType = Class.Name + Entity.ClassData = Class + Entity.Caliber = Caliber + Entity.Class = Class.ID -- Needed for custom killicons + Entity.MagReload = Weapon.MagReload + Entity.MagSize = Weapon.MagSize or 1 + Entity.Cyclic = Weapon.Cyclic and 60 / Weapon.Cyclic + Entity.ReloadTime = Entity.Cyclic or 1 + Entity.Spread = Class.Spread + Entity.MinLengthBonus = 0.75 * 3.1416 * (Caliber * 0.5) ^ 2 * Weapon.Round.MaxLength + Entity.HitBoxes = ACF.HitBoxes[Weapon.Model] + Entity.Long = Class.LongBarrel + Entity.NormalMuzzle = Entity:WorldToLocal(Entity:GetAttachment(Entity:LookupAttachment("muzzle")).Pos) + Entity.Muzzle = Entity.NormalMuzzle -- Set NWvars Entity:SetNWString("WireName", "ACF " .. Weapon.Name) @@ -111,8 +120,6 @@ do -- Spawn and Update functions -------------------------------- local Phys = Entity:GetPhysicsObject() if IsValid(Phys) then Phys:SetMass(Weapon.Mass) end - - Entity:UpdateOverlay(true) end function MakeACF_Weapon(Player, Pos, Angle, Data) @@ -144,7 +151,7 @@ do -- Spawn and Update functions -------------------------------- Gun.Crates = {} Gun.CurrentShot = 0 Gun.BulletData = { Type = "Empty", PropMass = 0, ProjMass = 0, Tracer = 0 } - Gun.DataStore = ACF.GetEntClassVars("acf_gun") + Gun.DataStore = ACF.GetEntityArguments("acf_gun") Gun:SetNWString("Sound", Class.Sound) @@ -159,6 +166,10 @@ do -- Spawn and Update functions -------------------------------- Class.OnSpawn(Gun, Data, Class, Weapon) end + HookRun("ACF_OnEntitySpawn", "acf_gun", Gun, Data, Class, Weapon) + + Gun:UpdateOverlay(true) + do -- Mass entity mod removal local EntMods = Data and Data.EntityMods @@ -188,13 +199,20 @@ do -- Spawn and Update functions -------------------------------- VerifyData(Data) - local Class = ACF.GetClassGroup(Weapons, Data.Id) - local Weapon = Class.Lookup[Data.Id] + local Class = ACF.GetClassGroup(Weapons, Data.Id) + local Weapon = Class.Lookup[Data.Id] + local OldClass = self.ClassData if self.State ~= "Empty" then self:Unload() end + if OldClass.OnLast then + OldClass.OnLast(self, OldClass) + end + + HookRun("ACF_OnEntityLast", "acf_gun", self, OldClass) + ACF.SaveEntity(self) UpdateWeapon(self, Data, Class, Weapon) @@ -205,12 +223,16 @@ do -- Spawn and Update functions -------------------------------- Class.OnUpdate(self, Data, Class, Weapon) end + HookRun("ACF_OnEntityUpdate", "acf_gun", self, Data, Class, Weapon) + if next(self.Crates) then for Crate in pairs(self.Crates) do self:Unlink(Crate) end end + self:UpdateOverlay(true) + net.Start("ACF_UpdateEntity") net.WriteEntity(self) net.Broadcast() @@ -817,6 +839,14 @@ do -- Metamethods -------------------------------- end function ENT:OnRemove() + local Class = self.ClassData + + if Class.OnLast then + Class.OnLast(self, Class) + end + + HookRun("ACF_OnEntityLast", "acf_gun", self, Class) + for Crate in pairs(self.Crates) do self:Unlink(Crate) end From f267d40ef59185b9206305ff9bb4fc413c4f5360 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Wed, 28 Oct 2020 21:53:53 -0300 Subject: [PATCH 138/279] Adapted acf_ammo to work with the new menu - The new menu tool will now be capable of spawning ACF ammo crates. Attempting to do this with the old menu tool with throw errors. - Ammo crates can now be fully updated with the new menu tool. - Ammo crates are now compatible with the improved ACF Copy tool. - Ammo crates now use the new ACF entity event and class hooks. - Ammo types can now add the following actions to ammo crates: OnFirst and OnLast. These will be called any time an ammo crate is created, update or removed. - Renamed all the ammo crate entity class arguments for easier identification. - Updated all ammo type definitions. Some functions may now only exist on the server or the client. Networking ammo type info will now use the NW2Var library. - Weapon definitions will now use the IsBoxed flag to define if their ammunition is stored on boxes. - Updated the ACF.RoundBaseGunpower function to support different weapon data destinations. - Added ACF.AddWeaponrySource, ACF.FindWeaponrySource and ACF.GetWeaponrySources functions to add possible sources for weapon data. - Updated acf_bullet_effect to use the NW2Var library. - Updated a few E2 and SF functions. --- lua/acf/base/sh_round_functions.lua | 84 +- lua/acf/shared/ammo_types/ap.lua | 303 ++-- lua/acf/shared/ammo_types/apcr.lua | 18 +- lua/acf/shared/ammo_types/apds.lua | 22 +- lua/acf/shared/ammo_types/apfsds.lua | 21 +- lua/acf/shared/ammo_types/aphe.lua | 218 +-- lua/acf/shared/ammo_types/fl.lua | 305 ++-- lua/acf/shared/ammo_types/he.lua | 174 +-- lua/acf/shared/ammo_types/heat.lua | 536 +++---- lua/acf/shared/ammo_types/heatfs.lua | 18 +- lua/acf/shared/ammo_types/hp.lua | 189 +-- lua/acf/shared/ammo_types/refill.lua | 159 +- lua/acf/shared/ammo_types/smoke.lua | 316 ++-- lua/acf/shared/guns/grenadelauncher.lua | 2 + lua/acf/shared/guns/heavymachinegun.lua | 4 + lua/acf/shared/guns/machinegun.lua | 4 + lua/acf/shared/guns/mortar.lua | 2 +- lua/acf/shared/guns/rotaryautocannon.lua | 2 +- lua/acf/shared/guns/semiauto.lua | 6 + lua/acf/shared/guns/smokelauncher.lua | 3 + lua/acf/shared/hitboxes.lua | 1 - lua/acf/shared/rounds/acf_roundfunctions.lua | 4 +- lua/acf/shared/rounds/heat.lua | 1 - lua/acf/shared/rounds/heatfs.lua | 1 - lua/acf/shared/rounds/refill.lua | 26 + lua/effects/acf_bullet_effect.lua | 22 +- lua/entities/acf_ammo/cl_init.lua | 7 +- lua/entities/acf_ammo/init.lua | 1369 ++++++++--------- lua/entities/acf_engine/init.lua | 5 +- lua/entities/acf_gun/init.lua | 8 +- .../core/custom/acffunctions.lua | 2 +- lua/starfall/libs_sv/acffunctions.lua | 12 +- 32 files changed, 2024 insertions(+), 1820 deletions(-) diff --git a/lua/acf/base/sh_round_functions.lua b/lua/acf/base/sh_round_functions.lua index 054c7996a..51f986173 100644 --- a/lua/acf/base/sh_round_functions.lua +++ b/lua/acf/base/sh_round_functions.lua @@ -1,19 +1,22 @@ +local Classes = ACF.Classes +local GetClassGroup = ACF.GetClassGroup + function ACF.RoundBaseGunpowder(ToolData, Data) - local Class = ACF.Classes[ToolData.Destiny] - local ClassData = Class and Class[ToolData.WeaponClass] - local WeaponData = ClassData and ClassData.Lookup[ToolData.Weapon] + local Source = Classes[ToolData.Destiny] + local Class = Source and GetClassGroup(Source, ToolData.Weapon) + local Weapon = Class and Class.Lookup[ToolData.Weapon] local GUIData = {} - if not WeaponData then return Data, GUIData end + if not Weapon then return Data, GUIData end - local RoundData = WeaponData.Round + local RoundData = Weapon.Round - Data.Caliber = WeaponData.Caliber - Data.FrArea = 3.1416 * (Data.Caliber * 0.05) ^ 2 + Data.Caliber = Weapon.Caliber * 0.1 -- Bullet caliber will have to stay in cm + Data.FrArea = 3.1416 * (Data.Caliber * 0.5) ^ 2 GUIData.MaxRoundLength = math.Round(RoundData.MaxLength * (Data.LengthAdj or 1), 2) GUIData.MinPropLength = 0.01 - GUIData.MinProjLength = math.Round(Data.Caliber * 0.15, 2) + GUIData.MinProjLength = math.Round(Data.Caliber * 1.5, 2) local DesiredProp = math.Round(RoundData.PropMass * 1000 / ACF.PDensity / Data.FrArea, 2) local AllowedProp = GUIData.MaxRoundLength - GUIData.MinProjLength @@ -30,7 +33,7 @@ function ACF.UpdateRoundSpecs(ToolData, Data, GUIData) GUIData = GUIData or Data Data.Priority = Data.Priority or "Projectile" - Data.Tracer = ToolData.Tracer and math.Round(Data.Caliber * 0.015, 2) or 0 + Data.Tracer = ToolData.Tracer and math.Round(Data.Caliber * 0.15, 2) or 0 local Projectile = math.Clamp(ToolData.Projectile + Data.Tracer, GUIData.MinProjLength, GUIData.MaxProjLength) local Propellant = math.Clamp(ToolData.Propellant, GUIData.MinPropLength, GUIData.MaxPropLength) @@ -49,38 +52,47 @@ function ACF.UpdateRoundSpecs(ToolData, Data, GUIData) GUIData.ProjVolume = Data.FrArea * Data.ProjLength end -local Classes = ACF.Classes -local Ignore = { - -- Old - GunClass = true, - Radar = true, - Rack = true, - -- New/upcoming - EngineTypes = true, - Components = true, - AmmoTypes = true, - FuelTanks = true, - FuelTypes = true, - Gearboxes = true, - Guidances = true, - Entities = true, - Engines = true, - Sensors = true, - Crates = true, - Racks = true, - Fuzes = true, +local Weaponry = { + Missiles = Classes.Missiles, + Weapons = Classes.Weapons, } -function ACF.GetWeaponBlacklist(Whitelist) +-- In case you might want to add more +function ACF.AddWeaponrySource(Class) + if not Class then return end + if not Classes[Class] then return end + + Weaponry[Class] = Classes[Class] +end + +function ACF.GetWeaponrySources() local Result = {} - for K, V in pairs(Classes) do - if Ignore[K] then continue end + for K, V in pairs(Weaponry) do + Result[K] = V + end + + return Result +end + +function ACF.FindWeaponrySource(ID) + if not ID then return end - for ID in pairs(V) do - if Whitelist[ID] then continue end + for Key, Source in pairs(Weaponry) do + if ACF.GetClassGroup(Source, ID) then + return Key, Source + end + end +end + +function ACF.GetWeaponBlacklist(Whitelist) + local Result = {} - Result[ID] = true + for _, Source in pairs(Weaponry) do + for ID in pairs(Source) do + if not Whitelist[ID] then + Result[ID] = true + end end end @@ -90,7 +102,7 @@ end function ACF.RoundShellCapacity(Momentum, FrArea, Caliber, ProjLength) local MinWall = 0.2 + ((Momentum / FrArea) ^ 0.7) * 0.02 --The minimal shell wall thickness required to survive firing at the current energy level local Length = math.max(ProjLength - MinWall, 0) - local Radius = math.max((Caliber * 0.05) - MinWall, 0) + local Radius = math.max((Caliber * 0.5) - MinWall, 0) local Volume = 3.1416 * Radius ^ 2 * Length return Volume, Length, Radius --Returning the cavity volume and the minimum wall thickness diff --git a/lua/acf/shared/ammo_types/ap.lua b/lua/acf/shared/ammo_types/ap.lua index b0a1102b1..258131e71 100644 --- a/lua/acf/shared/ammo_types/ap.lua +++ b/lua/acf/shared/ammo_types/ap.lua @@ -1,9 +1,7 @@ local Ammo = ACF.RegisterAmmoType("AP") -local DecalIndex = ACF.GetAmmoDecalIndex function Ammo:OnLoaded() self.Name = "Armor Piercing" - self.Type = "Ammo" self.Model = "models/munitions/round_100mm_shot.mdl" self.Description = "A shell made out of a solid piece of steel, meant to penetrate armor." self.Blacklist = { @@ -13,8 +11,12 @@ function Ammo:OnLoaded() } end -function Ammo:Create(_, BulletData) - ACF_CreateBullet(BulletData) +function Ammo:GetDisplayData(BulletData) + local Energy = ACF_Kinetic(BulletData.MuzzleVel * 39.37, BulletData.ProjMass, BulletData.LimitVel) + + return { + MaxPen = (Energy.Penetration / BulletData.PenArea) * ACF.KEtoRHA + } end function Ammo:UpdateRoundData(ToolData, Data, GUIData) @@ -32,10 +34,7 @@ function Ammo:UpdateRoundData(ToolData, Data, GUIData) end end -function Ammo:BaseConvert(_, ToolData) - if not ToolData.Projectile then ToolData.Projectile = 0 end - if not ToolData.Propellant then ToolData.Propellant = 0 end - +function Ammo:BaseConvert(ToolData) local Data, GUIData = ACF.RoundBaseGunpowder(ToolData, {}) Data.ShovePower = 0.2 @@ -49,174 +48,214 @@ function Ammo:BaseConvert(_, ToolData) return Data, GUIData end -function Ammo:ClientConvert(_, ToolData) - local Data, GUIData = self:BaseConvert(_, ToolData) +function Ammo:VerifyData(ToolData) + if not ToolData.Projectile then + local Projectile = ToolData.RoundProjectile - if GUIData then - for K, V in pairs(GUIData) do - Data[K] = V - end + ToolData.Projectile = Projectile and tonumber(Projectile) or 0 end - return Data -end + if not ToolData.Propellant then + local Propellant = ToolData.RoundPropellant -function Ammo:ServerConvert(_, ToolData) - local Data = self:BaseConvert(_, ToolData) + ToolData.Propellant = Propellant and tonumber(Propellant) or 0 + end - Data.Id = ToolData.Weapon - Data.Type = ToolData.Ammo + if ToolData.Tracer == nil then + local Data10 = ToolData.RoundData10 - return Data + ToolData.Tracer = Data10 and tobool(tonumber(Data10)) or false -- Haha "0.00" is true but 0 isn't + end end -function Ammo:Network(Crate, BulletData) - Crate:SetNW2String("AmmoType", "AP") - Crate:SetNW2String("AmmoID", BulletData.Id) - Crate:SetNW2Float("Caliber", BulletData.Caliber) - Crate:SetNW2Float("ProjMass", BulletData.ProjMass) - Crate:SetNW2Float("PropMass", BulletData.PropMass) - Crate:SetNW2Float("DragCoef", BulletData.DragCoef) - Crate:SetNW2Float("MuzzleVel", BulletData.MuzzleVel) - Crate:SetNW2Float("Tracer", BulletData.Tracer) -end +if SERVER then + ACF.AddEntityArguments("acf_ammo", "Projectile", "Propellant", "Tracer") -- Adding extra info to ammo crates -function Ammo:GetDisplayData(BulletData) - local Energy = ACF_Kinetic(BulletData.MuzzleVel * 39.37, BulletData.ProjMass, BulletData.LimitVel) + function Ammo:OnLast(Entity) + Entity.Projectile = nil + Entity.Propellant = nil + Entity.Tracer = nil - return { - MaxPen = (Energy.Penetration / BulletData.PenArea) * ACF.KEtoRHA - } -end + -- Cleanup the leftovers aswell + Entity.RoundProjectile = nil + Entity.RoundPropellant = nil + Entity.RoundData10 = nil + end -function Ammo:GetCrateText(BulletData) - local Data = self:GetDisplayData(BulletData) - local Text = "Muzzle Velocity: %s m/s\nMax Penetration: %s mm" + function Ammo:Create(_, BulletData) + ACF_CreateBullet(BulletData) + end - return Text:format(math.Round(BulletData.MuzzleVel, 2), math.Round(Data.MaxPen, 2)) -end + function Ammo:ServerConvert(ToolData) + self:VerifyData(ToolData) -function Ammo:PropImpact(_, Bullet, Target, HitNormal, HitPos, Bone) - if ACF_Check(Target) then - local Speed = Bullet.Flight:Length() / ACF.Scale - local Energy = ACF_Kinetic(Speed, Bullet.ProjMass, Bullet.LimitVel) - local HitRes = ACF_RoundImpact(Bullet, Speed, Energy, Target, HitPos, HitNormal, Bone) + local Data = self:BaseConvert(ToolData) - if HitRes.Overkill > 0 then - table.insert(Bullet.Filter, Target) --"Penetrate" (Ingoring the prop for the retry trace) + Data.Id = ToolData.Weapon + Data.Type = ToolData.AmmoType - Bullet.Flight = Bullet.Flight:GetNormalized() * (Energy.Kinetic * (1 - HitRes.Loss) * 2000 / Bullet.ProjMass) ^ 0.5 * 39.37 + return Data + end + + function Ammo:Network(Entity, BulletData) + Entity:SetNW2String("AmmoType", "AP") + Entity:SetNW2String("AmmoID", BulletData.Id) + Entity:SetNW2Float("Caliber", BulletData.Caliber) + Entity:SetNW2Float("ProjMass", BulletData.ProjMass) + Entity:SetNW2Float("PropMass", BulletData.PropMass) + Entity:SetNW2Float("DragCoef", BulletData.DragCoef) + Entity:SetNW2Float("Tracer", BulletData.Tracer) + end + function Ammo:GetCrateName() + end + + function Ammo:GetCrateText(BulletData) + local Data = self:GetDisplayData(BulletData) + local Text = "Muzzle Velocity: %s m/s\nMax Penetration: %s mm" + + return Text:format(math.Round(BulletData.MuzzleVel, 2), math.Round(Data.MaxPen, 2)) + end + + function Ammo:PropImpact(_, Bullet, Target, HitNormal, HitPos, Bone) + if ACF_Check(Target) then + local Speed = Bullet.Flight:Length() / ACF.Scale + local Energy = ACF_Kinetic(Speed, Bullet.ProjMass, Bullet.LimitVel) + local HitRes = ACF_RoundImpact(Bullet, Speed, Energy, Target, HitPos, HitNormal, Bone) + + if HitRes.Overkill > 0 then + table.insert(Bullet.Filter, Target) --"Penetrate" (Ingoring the prop for the retry trace) + + Bullet.Flight = Bullet.Flight:GetNormalized() * (Energy.Kinetic * (1 - HitRes.Loss) * 2000 / Bullet.ProjMass) ^ 0.5 * 39.37 + + return "Penetrated" + elseif HitRes.Ricochet then + return "Ricochet" + else + return false + end + else + table.insert(Bullet.Filter, Target) + + return "Penetrated" + end + end + + function Ammo:WorldImpact(_, Bullet, HitPos, HitNormal) + local Energy = ACF_Kinetic(Bullet.Flight:Length() / ACF.Scale, Bullet.ProjMass, Bullet.LimitVel) + local HitRes = ACF_PenetrateGround(Bullet, Energy, HitPos, HitNormal) + + if HitRes.Penetrated then return "Penetrated" elseif HitRes.Ricochet then return "Ricochet" else return false end - else - table.insert(Bullet.Filter, Target) + end - return "Penetrated" + function Ammo:OnFlightEnd(Index) + ACF_RemoveBullet(Index) end -end +else + ACF.RegisterAmmoDecal("AP", "damage/ap_pen", "damage/ap_rico") + + local DecalIndex = ACF.GetAmmoDecalIndex -function Ammo:WorldImpact(_, Bullet, HitPos, HitNormal) - local Energy = ACF_Kinetic(Bullet.Flight:Length() / ACF.Scale, Bullet.ProjMass, Bullet.LimitVel) - local HitRes = ACF_PenetrateGround(Bullet, Energy, HitPos, HitNormal) + function Ammo:ClientConvert(ToolData) + self:VerifyData(ToolData) - if HitRes.Penetrated then - return "Penetrated" - elseif HitRes.Ricochet then - return "Ricochet" - else - return false + local Data, GUIData = self:BaseConvert(ToolData) + + if GUIData then + for K, V in pairs(GUIData) do + Data[K] = V + end + end + + return Data end -end -function Ammo:OnFlightEnd(Index) - ACF_RemoveBullet(Index) -end -function Ammo:ImpactEffect(_, Bullet) - local Effect = EffectData() - Effect:SetOrigin(Bullet.SimPos) - Effect:SetNormal(Bullet.SimFlight:GetNormalized()) - Effect:SetRadius(Bullet.Caliber) - Effect:SetDamageType(DecalIndex(Bullet.AmmoType)) + function Ammo:ImpactEffect(_, Bullet) + local Effect = EffectData() + Effect:SetOrigin(Bullet.SimPos) + Effect:SetNormal(Bullet.SimFlight:GetNormalized()) + Effect:SetRadius(Bullet.Caliber) + Effect:SetDamageType(DecalIndex(Bullet.AmmoType)) - util.Effect("ACF_Impact", Effect) -end + util.Effect("ACF_Impact", Effect) + end -function Ammo:PenetrationEffect(_, Bullet) - local Effect = EffectData() - Effect:SetOrigin(Bullet.SimPos) - Effect:SetNormal(Bullet.SimFlight:GetNormalized()) - Effect:SetScale(Bullet.SimFlight:Length()) - Effect:SetMagnitude(Bullet.RoundMass) - Effect:SetRadius(Bullet.Caliber) - Effect:SetDamageType(DecalIndex(Bullet.AmmoType)) + function Ammo:PenetrationEffect(_, Bullet) + local Effect = EffectData() + Effect:SetOrigin(Bullet.SimPos) + Effect:SetNormal(Bullet.SimFlight:GetNormalized()) + Effect:SetScale(Bullet.SimFlight:Length()) + Effect:SetMagnitude(Bullet.RoundMass) + Effect:SetRadius(Bullet.Caliber) + Effect:SetDamageType(DecalIndex(Bullet.AmmoType)) - util.Effect("ACF_Penetration", Effect) -end + util.Effect("ACF_Penetration", Effect) + end -function Ammo:RicochetEffect(_, Bullet) - local Effect = EffectData() - Effect:SetOrigin(Bullet.SimPos) - Effect:SetNormal(Bullet.SimFlight:GetNormalized()) - Effect:SetScale(Bullet.SimFlight:Length()) - Effect:SetMagnitude(Bullet.RoundMass) - Effect:SetRadius(Bullet.Caliber) - Effect:SetDamageType(DecalIndex(Bullet.AmmoType)) + function Ammo:RicochetEffect(_, Bullet) + local Effect = EffectData() + Effect:SetOrigin(Bullet.SimPos) + Effect:SetNormal(Bullet.SimFlight:GetNormalized()) + Effect:SetScale(Bullet.SimFlight:Length()) + Effect:SetMagnitude(Bullet.RoundMass) + Effect:SetRadius(Bullet.Caliber) + Effect:SetDamageType(DecalIndex(Bullet.AmmoType)) - util.Effect("ACF_Ricochet", Effect) -end + util.Effect("ACF_Ricochet", Effect) + end -function Ammo:MenuAction(Menu, ToolData, Data) - local Tracer = Menu:AddCheckBox("Tracer") - Tracer:SetDataVar("Tracer", "OnChange") - Tracer:SetValueFunction(function(Panel) - ToolData.Tracer = ACF.ReadBool("Tracer") + function Ammo:MenuAction(Menu, ToolData, Data) + local Tracer = Menu:AddCheckBox("Tracer") + Tracer:SetDataVar("Tracer", "OnChange") + Tracer:SetValueFunction(function(Panel) + ToolData.Tracer = ACF.ReadBool("Tracer") - self:UpdateRoundData(ToolData, Data) + self:UpdateRoundData(ToolData, Data) - ACF.WriteValue("Projectile", Data.ProjLength) - ACF.WriteValue("Propellant", Data.PropLength) + ACF.WriteValue("Projectile", Data.ProjLength) + ACF.WriteValue("Propellant", Data.PropLength) - Panel:SetText("Tracer : " .. Data.Tracer .. " cm") - Panel:SetValue(ToolData.Tracer) + Panel:SetText("Tracer : " .. Data.Tracer .. " cm") + Panel:SetValue(ToolData.Tracer) - return ToolData.Tracer - end) + return ToolData.Tracer + end) - local RoundStats = Menu:AddLabel() - RoundStats:TrackDataVar("Projectile", "SetText") - RoundStats:TrackDataVar("Propellant") - RoundStats:SetValueFunction(function() - self:UpdateRoundData(ToolData, Data) + local RoundStats = Menu:AddLabel() + RoundStats:TrackDataVar("Projectile", "SetText") + RoundStats:TrackDataVar("Propellant") + RoundStats:SetValueFunction(function() + self:UpdateRoundData(ToolData, Data) - local Text = "Muzzle Velocity : %s m/s\nProjectile Mass : %s\nPropellant Mass : %s" - local MuzzleVel = math.Round(Data.MuzzleVel * ACF.Scale, 2) - local ProjMass = ACF.GetProperMass(Data.ProjMass) - local PropMass = ACF.GetProperMass(Data.PropMass) + local Text = "Muzzle Velocity : %s m/s\nProjectile Mass : %s\nPropellant Mass : %s" + local MuzzleVel = math.Round(Data.MuzzleVel * ACF.Scale, 2) + local ProjMass = ACF.GetProperMass(Data.ProjMass) + local PropMass = ACF.GetProperMass(Data.PropMass) - return Text:format(MuzzleVel, ProjMass, PropMass) - end) + return Text:format(MuzzleVel, ProjMass, PropMass) + end) - local PenStats = Menu:AddLabel() - PenStats:TrackDataVar("Projectile", "SetText") - PenStats:TrackDataVar("Propellant") - PenStats:SetValueFunction(function() - self:UpdateRoundData(ToolData, Data) + local PenStats = Menu:AddLabel() + PenStats:TrackDataVar("Projectile", "SetText") + PenStats:TrackDataVar("Propellant") + PenStats:SetValueFunction(function() + self:UpdateRoundData(ToolData, Data) - local Text = "Penetration : %s mm RHA\nAt 300m : %s mm RHA @ %s m/s\nAt 800m : %s mm RHA @ %s m/s" - local MaxPen = math.Round(Data.MaxPen, 2) - local R1V, R1P = ACF.PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 300) - local R2V, R2P = ACF.PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 800) + local Text = "Penetration : %s mm RHA\nAt 300m : %s mm RHA @ %s m/s\nAt 800m : %s mm RHA @ %s m/s" + local MaxPen = math.Round(Data.MaxPen, 2) + local R1V, R1P = ACF.PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 300) + local R2V, R2P = ACF.PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 800) - return Text:format(MaxPen, R1P, R1V, R2P, R2V) - end) + return Text:format(MaxPen, R1P, R1V, R2P, R2V) + end) - Menu:AddLabel("Note: The penetration range data is an approximation and may not be entirely accurate.") + Menu:AddLabel("Note: The penetration range data is an approximation and may not be entirely accurate.") + end end - -ACF.RegisterAmmoDecal("AP", "damage/ap_pen", "damage/ap_rico") diff --git a/lua/acf/shared/ammo_types/apcr.lua b/lua/acf/shared/ammo_types/apcr.lua index 6d76b9e2f..174025dcd 100644 --- a/lua/acf/shared/ammo_types/apcr.lua +++ b/lua/acf/shared/ammo_types/apcr.lua @@ -6,6 +6,7 @@ function Ammo:OnLoaded() self.Name = "Armor Piercing Composite Rigid" self.Description = "A hardened core munition designed for weapons in the 1940s." self.Blacklist = ACF.GetWeaponBlacklist({ + RAC = true, AL = true, AC = true, SA = true, @@ -29,10 +30,7 @@ function Ammo:UpdateRoundData(ToolData, Data, GUIData) end end -function Ammo:BaseConvert(_, ToolData) - if not ToolData.Projectile then ToolData.Projectile = 0 end - if not ToolData.Propellant then ToolData.Propellant = 0 end - +function Ammo:BaseConvert(ToolData) local Data, GUIData = ACF.RoundBaseGunpowder(ToolData, {}) Data.ShovePower = 0.2 @@ -46,10 +44,12 @@ function Ammo:BaseConvert(_, ToolData) return Data, GUIData end -function Ammo:Network(Crate, BulletData) - Ammo.BaseClass.Network(self, Crate, BulletData) +if SERVER then + function Ammo:Network(Entity, BulletData) + Ammo.BaseClass.Network(self, Entity, BulletData) - Crate:SetNW2String("AmmoType", "APCR") + Entity:SetNW2String("AmmoType", "APCR") + end +else + ACF.RegisterAmmoDecal("APCR", "damage/apcr_pen", "damage/apcr_rico") end - -ACF.RegisterAmmoDecal("APCR", "damage/apcr_pen", "damage/apcr_rico") diff --git a/lua/acf/shared/ammo_types/apds.lua b/lua/acf/shared/ammo_types/apds.lua index 0d3758179..891f0d4c1 100644 --- a/lua/acf/shared/ammo_types/apds.lua +++ b/lua/acf/shared/ammo_types/apds.lua @@ -6,6 +6,7 @@ function Ammo:OnLoaded() self.Name = "Armor Piercing Discarging Sabot" self.Description = "A subcaliber munition designed to trade damage for penetration. Loses energy quickly over distance." self.Blacklist = ACF.GetWeaponBlacklist({ + RAC = true, AL = true, AC = true, SA = true, @@ -18,7 +19,7 @@ function Ammo:UpdateRoundData(ToolData, Data, GUIData) ACF.UpdateRoundSpecs(ToolData, Data, GUIData) - local Cylinder = (3.1416 * (Data.Caliber * 0.05) ^ 2) * Data.ProjLength * 0.5 -- A cylinder 1/2 the length of the projectile + local Cylinder = (3.1416 * (Data.Caliber * 0.5) ^ 2) * Data.ProjLength * 0.5 -- A cylinder 1/2 the length of the projectile local Hole = Data.RoundArea * Data.ProjLength * 0.25 -- Volume removed by the hole the dart passes through local SabotMass = (Cylinder - Hole) * 2.7 * 0.65 * 0.001 -- Aluminum sabot @@ -32,13 +33,10 @@ function Ammo:UpdateRoundData(ToolData, Data, GUIData) end end -function Ammo:BaseConvert(_, ToolData) - if not ToolData.Projectile then ToolData.Projectile = 0 end - if not ToolData.Propellant then ToolData.Propellant = 0 end - +function Ammo:BaseConvert(ToolData) local Data, GUIData = ACF.RoundBaseGunpowder(ToolData, {}) local SubCaliberRatio = 0.375 -- Ratio of projectile to gun caliber - local Area = 3.1416 * (Data.Caliber * 0.05 * SubCaliberRatio) ^ 2 + local Area = 3.1416 * (Data.Caliber * 0.5 * SubCaliberRatio) ^ 2 Data.RoundArea = Area Data.ShovePower = 0.2 @@ -52,10 +50,12 @@ function Ammo:BaseConvert(_, ToolData) return Data, GUIData end -function Ammo:Network(Crate, BulletData) - Ammo.BaseClass.Network(self, Crate, BulletData) +if SERVER then + function Ammo:Network(Entity, BulletData) + Ammo.BaseClass.Network(self, Entity, BulletData) - Crate:SetNW2String("AmmoType", "APDS") + Entity:SetNW2String("AmmoType", "APDS") + end +else + ACF.RegisterAmmoDecal("APDS", "damage/apcr_pen", "damage/apcr_rico") end - -ACF.RegisterAmmoDecal("APDS", "damage/apcr_pen", "damage/apcr_rico") diff --git a/lua/acf/shared/ammo_types/apfsds.lua b/lua/acf/shared/ammo_types/apfsds.lua index c95173b71..9e03fe30e 100644 --- a/lua/acf/shared/ammo_types/apfsds.lua +++ b/lua/acf/shared/ammo_types/apfsds.lua @@ -16,7 +16,7 @@ function Ammo:UpdateRoundData(ToolData, Data, GUIData) ACF.UpdateRoundSpecs(ToolData, Data, GUIData) - local Cylinder = (3.1416 * (Data.Caliber * 0.05) ^ 2) * Data.ProjLength * 0.25 -- A cylinder 1/4 the length of the projectile + local Cylinder = (3.1416 * (Data.Caliber * 0.5) ^ 2) * Data.ProjLength * 0.25 -- A cylinder 1/4 the length of the projectile local Hole = Data.RoundArea * Data.ProjLength * 0.25 -- Volume removed by the hole the dart passes through local SabotMass = (Cylinder - Hole) * 2.7 * 0.25 * 0.001 -- A cylinder with a hole the size of the dart in it and im no math wizard so we're just going to take off 3/4 of the mass for the cutout since sabots are shaped like this: ][ @@ -30,13 +30,10 @@ function Ammo:UpdateRoundData(ToolData, Data, GUIData) end end -function Ammo:BaseConvert(_, ToolData) - if not ToolData.Projectile then ToolData.Projectile = 0 end - if not ToolData.Propellant then ToolData.Propellant = 0 end - +function Ammo:BaseConvert(ToolData) local Data, GUIData = ACF.RoundBaseGunpowder(ToolData, {}) local SubCaliberRatio = 0.29 -- Ratio of projectile to gun caliber - local Area = 3.1416 * (Data.Caliber * 0.05 * SubCaliberRatio) ^ 2 + local Area = 3.1416 * (Data.Caliber * 0.5 * SubCaliberRatio) ^ 2 Data.RoundArea = Area Data.ShovePower = 0.2 @@ -50,10 +47,12 @@ function Ammo:BaseConvert(_, ToolData) return Data, GUIData end -function Ammo:Network(Crate, BulletData) - Ammo.BaseClass.Network(self, Crate, BulletData) +if SERVER then + function Ammo:Network(Entity, BulletData) + Ammo.BaseClass.Network(self, Entity, BulletData) - Crate:SetNW2String("AmmoType", "APFSDS") + Entity:SetNW2String("AmmoType", "APFSDS") + end +else + ACF.RegisterAmmoDecal("APFSDS", "damage/apcr_pen", "damage/apcr_rico") end - -ACF.RegisterAmmoDecal("APFSDS", "damage/apcr_pen", "damage/apcr_rico") diff --git a/lua/acf/shared/ammo_types/aphe.lua b/lua/acf/shared/ammo_types/aphe.lua index 54986b0da..ed4093933 100644 --- a/lua/acf/shared/ammo_types/aphe.lua +++ b/lua/acf/shared/ammo_types/aphe.lua @@ -13,6 +13,18 @@ function Ammo:OnLoaded() } end +function Ammo:GetDisplayData(BulletData) + local Data = Ammo.BaseClass.GetDisplayData(self, BulletData) + local FragMass = BulletData.ProjMass - BulletData.FillerMass + + Data.BlastRadius = BulletData.FillerMass ^ 0.33 * 8 + Data.Fragments = math.max(math.floor((BulletData.FillerMass / FragMass) * ACF.HEFrag), 2) + Data.FragMass = FragMass / Data.Fragments + Data.FragVel = (BulletData.FillerMass * ACF.HEPower * 1000 / Data.FragMass / Data.Fragments) ^ 0.5 + + return Data +end + function Ammo:UpdateRoundData(ToolData, Data, GUIData) GUIData = GUIData or Data @@ -39,11 +51,7 @@ function Ammo:UpdateRoundData(ToolData, Data, GUIData) end end -function Ammo:BaseConvert(_, ToolData) - if not ToolData.Projectile then ToolData.Projectile = 0 end - if not ToolData.Propellant then ToolData.Propellant = 0 end - if not ToolData.FillerMass then ToolData.FillerMass = 0 end - +function Ammo:BaseConvert(ToolData) local Data, GUIData = ACF.RoundBaseGunpowder(ToolData, {}) GUIData.MinFillerVol = 0 @@ -58,130 +66,136 @@ function Ammo:BaseConvert(_, ToolData) return Data, GUIData end -function Ammo:Network(Crate, BulletData) - Crate:SetNW2String("AmmoType", "APHE") - Crate:SetNW2String("AmmoID", BulletData.Id) - Crate:SetNW2Float("Caliber", BulletData.Caliber) - Crate:SetNW2Float("ProjMass", BulletData.ProjMass) - Crate:SetNW2Float("FillerMass", BulletData.FillerMass) - Crate:SetNW2Float("PropMass", BulletData.PropMass) - Crate:SetNW2Float("DragCoef", BulletData.DragCoef) - Crate:SetNW2Float("MuzzleVel", BulletData.MuzzleVel) - Crate:SetNW2Float("Tracer", BulletData.Tracer) +function Ammo:VerifyData(ToolData) + Ammo.BaseClass.VerifyData(self, ToolData) + + if not ToolData.FillerMass then + local Data5 = ToolData.RoundData5 + + ToolData.FillerMass = Data5 and tonumber(Data5) or 0 + end end -function Ammo:GetDisplayData(BulletData) - local Data = Ammo.BaseClass.GetDisplayData(self, BulletData) - local FragMass = BulletData.ProjMass - BulletData.FillerMass +if SERVER then + ACF.AddEntityArguments("acf_ammo", "FillerMass") -- Adding extra info to ammo crates - Data.BlastRadius = BulletData.FillerMass ^ 0.33 * 8 - Data.Fragments = math.max(math.floor((BulletData.FillerMass / FragMass) * ACF.HEFrag), 2) - Data.FragMass = FragMass / Data.Fragments - Data.FragVel = (BulletData.FillerMass * ACF.HEPower * 1000 / Data.FragMass / Data.Fragments) ^ 0.5 + function Ammo:OnLast(Entity) + Ammo.BaseClass.OnLast(self, Entity) - return Data -end + Entity.FillerMass = nil + Entity.RoundData5 = nil -- Cleanup the leftovers aswell + + Entity:SetNW2Float("FillerMass", 0) + end -function Ammo:GetCrateText(BulletData) - local BaseText = Ammo.BaseClass.GetCrateText(self, BulletData) - local Text = BaseText .. "\nBlast Radius: %s m\nBlast Energy: %s KJ" - local Data = self:GetDisplayData(BulletData) + function Ammo:Network(Entity, BulletData) + Ammo.BaseClass.Network(self, Entity, BulletData) - return Text:format(math.Round(Data.BlastRadius, 2), math.Round(BulletData.FillerMass * ACF.HEPower, 2)) -end + Entity:SetNW2String("AmmoType", "APHE") + Entity:SetNW2Float("FillerMass", BulletData.FillerMass) + end -function Ammo:OnFlightEnd(Index, Bullet, HitPos) - ACF_HE(HitPos - Bullet.Flight:GetNormalized() * 3, Bullet.FillerMass, Bullet.ProjMass - Bullet.FillerMass, Bullet.Owner, nil, Bullet.Gun) + function Ammo:GetCrateText(BulletData) + local BaseText = Ammo.BaseClass.GetCrateText(self, BulletData) + local Text = BaseText .. "\nBlast Radius: %s m\nBlast Energy: %s KJ" + local Data = self:GetDisplayData(BulletData) - Ammo.BaseClass.OnFlightEnd(self, Index, Bullet, Hitpos) -end + return Text:format(math.Round(Data.BlastRadius, 2), math.Round(BulletData.FillerMass * ACF.HEPower, 2)) + end -function Ammo:ImpactEffect(_, Bullet) - local Effect = EffectData() - Effect:SetOrigin(Bullet.SimPos) - Effect:SetNormal(Bullet.SimFlight:GetNormalized()) - Effect:SetScale(math.max(Bullet.FillerMass ^ 0.33 * 8 * 39.37, 1)) - Effect:SetRadius(Bullet.Caliber) + function Ammo:OnFlightEnd(Index, Bullet, HitPos) + ACF_HE(HitPos, Bullet.FillerMass, Bullet.ProjMass - Bullet.FillerMass, Bullet.Owner, nil, Bullet.Gun) - util.Effect("ACF_Explosion", Effect) -end + Ammo.BaseClass.OnFlightEnd(self, Index, Bullet, Hitpos) + end +else + ACF.RegisterAmmoDecal("APHE", "damage/ap_pen", "damage/ap_rico") -function Ammo:MenuAction(Menu, ToolData, Data) - local FillerMass = Menu:AddSlider("Filler Volume", 0, Data.MaxFillerVol, 2) - FillerMass:SetDataVar("FillerMass", "OnValueChanged") - FillerMass:TrackDataVar("Projectile") - FillerMass:SetValueFunction(function(Panel) - ToolData.FillerMass = math.Round(ACF.ReadNumber("FillerMass"), 2) + function Ammo:ImpactEffect(_, Bullet) + local Effect = EffectData() + Effect:SetOrigin(Bullet.SimPos) + Effect:SetNormal(Bullet.SimFlight:GetNormalized()) + Effect:SetScale(math.max(Bullet.FillerMass ^ 0.33 * 8 * 39.37, 1)) + Effect:SetRadius(Bullet.Caliber) - self:UpdateRoundData(ToolData, Data) + util.Effect("ACF_Explosion", Effect) + end - Panel:SetMax(Data.MaxFillerVol) - Panel:SetValue(Data.FillerVol) + function Ammo:MenuAction(Menu, ToolData, Data) + local FillerMass = Menu:AddSlider("Filler Volume", 0, Data.MaxFillerVol, 2) + FillerMass:SetDataVar("FillerMass", "OnValueChanged") + FillerMass:TrackDataVar("Projectile") + FillerMass:SetValueFunction(function(Panel) + ToolData.FillerMass = math.Round(ACF.ReadNumber("FillerMass"), 2) - return Data.FillerVol - end) + self:UpdateRoundData(ToolData, Data) - local Tracer = Menu:AddCheckBox("Tracer") - Tracer:SetDataVar("Tracer", "OnChange") - Tracer:SetValueFunction(function(Panel) - ToolData.Tracer = ACF.ReadBool("Tracer") + Panel:SetMax(Data.MaxFillerVol) + Panel:SetValue(Data.FillerVol) - self:UpdateRoundData(ToolData, Data) + return Data.FillerVol + end) - ACF.WriteValue("Projectile", Data.ProjLength) - ACF.WriteValue("Propellant", Data.PropLength) + local Tracer = Menu:AddCheckBox("Tracer") + Tracer:SetDataVar("Tracer", "OnChange") + Tracer:SetValueFunction(function(Panel) + ToolData.Tracer = ACF.ReadBool("Tracer") - Panel:SetText("Tracer : " .. Data.Tracer .. " cm") - Panel:SetValue(ToolData.Tracer) + self:UpdateRoundData(ToolData, Data) - return ToolData.Tracer - end) + ACF.WriteValue("Projectile", Data.ProjLength) + ACF.WriteValue("Propellant", Data.PropLength) - local RoundStats = Menu:AddLabel() - RoundStats:TrackDataVar("Projectile", "SetText") - RoundStats:TrackDataVar("Propellant") - RoundStats:TrackDataVar("FillerMass") - RoundStats:SetValueFunction(function() - self:UpdateRoundData(ToolData, Data) + Panel:SetText("Tracer : " .. Data.Tracer .. " cm") + Panel:SetValue(ToolData.Tracer) - local Text = "Muzzle Velocity : %s m/s\nProjectile Mass : %s\nPropellant Mass : %s\nExplosive Mass : %s" - local MuzzleVel = math.Round(Data.MuzzleVel * ACF.Scale, 2) - local ProjMass = ACF.GetProperMass(Data.ProjMass) - local PropMass = ACF.GetProperMass(Data.PropMass) - local Filler = ACF.GetProperMass(Data.FillerMass) + return ToolData.Tracer + end) - return Text:format(MuzzleVel, ProjMass, PropMass, Filler) - end) + local RoundStats = Menu:AddLabel() + RoundStats:TrackDataVar("Projectile", "SetText") + RoundStats:TrackDataVar("Propellant") + RoundStats:TrackDataVar("FillerMass") + RoundStats:SetValueFunction(function() + self:UpdateRoundData(ToolData, Data) - local FillerStats = Menu:AddLabel() - FillerStats:TrackDataVar("FillerMass", "SetText") - FillerStats:SetValueFunction(function() - self:UpdateRoundData(ToolData, Data) + local Text = "Muzzle Velocity : %s m/s\nProjectile Mass : %s\nPropellant Mass : %s\nExplosive Mass : %s" + local MuzzleVel = math.Round(Data.MuzzleVel * ACF.Scale, 2) + local ProjMass = ACF.GetProperMass(Data.ProjMass) + local PropMass = ACF.GetProperMass(Data.PropMass) + local Filler = ACF.GetProperMass(Data.FillerMass) - local Text = "Blast Radius : %s m\nFragments : %s\nFragment Mass : %s\nFragment Velocity : %s m/s" - local Blast = math.Round(Data.BlastRadius, 2) - local FragMass = ACF.GetProperMass(Data.FragMass) - local FragVel = math.Round(Data.FragVel, 2) + return Text:format(MuzzleVel, ProjMass, PropMass, Filler) + end) - return Text:format(Blast, Data.Fragments, FragMass, FragVel) - end) + local FillerStats = Menu:AddLabel() + FillerStats:TrackDataVar("FillerMass", "SetText") + FillerStats:SetValueFunction(function() + self:UpdateRoundData(ToolData, Data) - local PenStats = Menu:AddLabel() - PenStats:TrackDataVar("Projectile", "SetText") - PenStats:TrackDataVar("Propellant") - PenStats:TrackDataVar("FillerMass") - PenStats:SetValueFunction(function() - self:UpdateRoundData(ToolData, Data) + local Text = "Blast Radius : %s m\nFragments : %s\nFragment Mass : %s\nFragment Velocity : %s m/s" + local Blast = math.Round(Data.BlastRadius, 2) + local FragMass = ACF.GetProperMass(Data.FragMass) + local FragVel = math.Round(Data.FragVel, 2) - local Text = "Penetration : %s mm RHA\nAt 300m : %s mm RHA @ %s m/s\nAt 800m : %s mm RHA @ %s m/s" - local MaxPen = math.Round(Data.MaxPen, 2) - local R1V, R1P = ACF.PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 300) - local R2V, R2P = ACF.PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 800) + return Text:format(Blast, Data.Fragments, FragMass, FragVel) + end) - return Text:format(MaxPen, R1P, R1V, R2P, R2V) - end) + local PenStats = Menu:AddLabel() + PenStats:TrackDataVar("Projectile", "SetText") + PenStats:TrackDataVar("Propellant") + PenStats:TrackDataVar("FillerMass") + PenStats:SetValueFunction(function() + self:UpdateRoundData(ToolData, Data) - Menu:AddLabel("Note: The penetration range data is an approximation and may not be entirely accurate.") -end + local Text = "Penetration : %s mm RHA\nAt 300m : %s mm RHA @ %s m/s\nAt 800m : %s mm RHA @ %s m/s" + local MaxPen = math.Round(Data.MaxPen, 2) + local R1V, R1P = ACF.PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 300) + local R2V, R2P = ACF.PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 800) -ACF.RegisterAmmoDecal("APHE", "damage/ap_pen", "damage/ap_rico") + return Text:format(MaxPen, R1P, R1V, R2P, R2V) + end) + + Menu:AddLabel("Note: The penetration range data is an approximation and may not be entirely accurate.") + end +end \ No newline at end of file diff --git a/lua/acf/shared/ammo_types/fl.lua b/lua/acf/shared/ammo_types/fl.lua index 88574ed19..2b92c8f0d 100644 --- a/lua/acf/shared/ammo_types/fl.lua +++ b/lua/acf/shared/ammo_types/fl.lua @@ -16,55 +16,12 @@ function Ammo:OnLoaded() } end -function Ammo:Create(Gun, BulletData) - local FlechetteData = { - Caliber = math.Round(BulletData.FlechetteRadius * 0.2, 2), - Id = BulletData.Id, - Type = "AP", - Owner = BulletData.Owner, - Crate = BulletData.Crate, - Gun = BulletData.Gun, - Pos = BulletData.Pos, - FrArea = BulletData.FlechetteArea, - ProjMass = BulletData.FlechetteMass, - DragCoef = BulletData.FlechetteDragCoef, - Tracer = BulletData.Tracer, - LimitVel = BulletData.LimitVel, - Ricochet = BulletData.Ricochet, - PenArea = BulletData.FlechettePenArea, - ShovePower = BulletData.ShovePower, - KETransfert = BulletData.KETransfert, - } - - --if ammo is cooking off, shoot in random direction - if Gun:GetClass() == "acf_ammo" then - local MuzzleVec = VectorRand() - - for _ = 1, BulletData.Flechettes do - local Inaccuracy = VectorRand() / 360 * ((Gun.Spread or 0) + BulletData.FlechetteSpread) - - FlechetteData.Flight = (MuzzleVec + Inaccuracy):GetNormalized() * BulletData.MuzzleVel * 39.37 + Gun:GetVelocity() - - ACF_CreateBullet(FlechetteData) - end - else - local BaseInaccuracy = math.tan(math.rad(Gun:GetSpread())) - local AddInaccuracy = math.tan(math.rad(BulletData.FlechetteSpread)) - local MuzzleVec = Gun:GetForward() - - for _ = 1, BulletData.Flechettes do - local GunUp, GunRight = Gun:GetUp(), Gun:GetRight() - local BaseInaccuracyMult = math.random() ^ (1 / math.Clamp(ACF.GunInaccuracyBias, 0.5, 4)) * (GunUp * (2 * math.random() - 1) + GunRight * (2 * math.random() - 1)):GetNormalized() - local AddSpreadMult = math.random() ^ (1 / math.Clamp(ACF.GunInaccuracyBias, 0.5, 4)) * (GunUp * (2 * math.random() - 1) + GunRight * (2 * math.random() - 1)):GetNormalized() - - BaseSpread = BaseInaccuracy * BaseInaccuracyMult - AddSpread = AddInaccuracy * AddSpreadMult - - FlechetteData.Flight = (MuzzleVec + BaseSpread + AddSpread):GetNormalized() * BulletData.MuzzleVel * 39.37 + Gun:GetVelocity() +function Ammo:GetDisplayData(BulletData) + local Energy = ACF_Kinetic(BulletData.MuzzleVel * 39.37, BulletData.FlechetteMass, BulletData.LimitVel) - ACF_CreateBullet(FlechetteData) - end - end + return { + MaxPen = (Energy.Penetration / BulletData.FlechettePenArea) * ACF.KEtoRHA + } end function Ammo:UpdateRoundData(ToolData, Data, GUIData) @@ -79,7 +36,7 @@ function Ammo:UpdateRoundData(ToolData, Data, GUIData) Data.Flechettes = Flechettes Data.FlechetteSpread = math.Clamp(ToolData.Spread, Data.MinSpread, Data.MaxSpread) - Data.FlechetteRadius = (((PackRatio * RadiusAdj * Data.Caliber * 0.05) ^ 2) / Data.Flechettes) ^ 0.5 + Data.FlechetteRadius = (((PackRatio * RadiusAdj * Data.Caliber * 0.5) ^ 2) / Data.Flechettes) ^ 0.5 Data.FlechetteArea = 3.1416 * Data.FlechetteRadius ^ 2 -- area of a single flechette Data.FlechetteMass = Data.FlechetteArea * (Data.ProjLength * 7.9 / 1000) -- volume of single flechette * density of steel Data.FlechettePenArea = (PenAdj * Data.FlechetteArea) ^ ACF.PenAreaMod @@ -94,23 +51,18 @@ function Ammo:UpdateRoundData(ToolData, Data, GUIData) end end -function Ammo:BaseConvert(_, ToolData) - if not ToolData.Projectile then ToolData.Projectile = 0 end - if not ToolData.Propellant then ToolData.Propellant = 0 end - if not ToolData.Flechettes then ToolData.Flechettes = 3 end - if not ToolData.Spread then ToolData.Spread = 5 end - +function Ammo:BaseConvert(ToolData) local Data, GUIData = ACF.RoundBaseGunpowder(ToolData, { LengthAdj = 0.5 }) local GunClass = ToolData.WeaponClass if GunClass == "SA" then - Data.MaxFlechettes = math.Clamp(math.floor(Data.Caliber * 0.3 - 4.5), 1, 32) + Data.MaxFlechettes = math.Clamp(math.floor(Data.Caliber * 3 - 4.5), 1, 32) elseif GunClass == "MO" then - Data.MaxFlechettes = math.Clamp(math.floor(Data.Caliber * 0.4) - 12, 1, 32) + Data.MaxFlechettes = math.Clamp(math.floor(Data.Caliber * 4) - 12, 1, 32) elseif GunClass == "HW" then - Data.MaxFlechettes = math.Clamp(math.floor(Data.Caliber * 0.4) - 10, 1, 32) + Data.MaxFlechettes = math.Clamp(math.floor(Data.Caliber * 4) - 10, 1, 32) else - Data.MaxFlechettes = math.Clamp(math.floor(Data.Caliber * 0.4) - 8, 1, 32) + Data.MaxFlechettes = math.Clamp(math.floor(Data.Caliber * 4) - 8, 1, 32) end Data.MinFlechettes = math.min(6, Data.MaxFlechettes) --force bigger guns to have higher min count @@ -127,114 +79,185 @@ function Ammo:BaseConvert(_, ToolData) return Data, GUIData end -function Ammo:Network(Crate, BulletData) - Crate:SetNW2String("AmmoType", "FL") - Crate:SetNW2String("AmmoID", BulletData.Id) - Crate:SetNW2Float("PropMass", BulletData.PropMass) - Crate:SetNW2Float("MuzzleVel", BulletData.MuzzleVel) - Crate:SetNW2Float("Tracer", BulletData.Tracer) - Crate:SetNW2Float("Caliber", math.Round(BulletData.FlechetteRadius * 0.2, 2)) - Crate:SetNW2Float("ProjMass", BulletData.FlechetteMass) - Crate:SetNW2Float("DragCoef", BulletData.FlechetteDragCoef) - Crate:SetNW2Float("FillerMass", 0) -end +function Ammo:VerifyData(ToolData) + Ammo.BaseClass.VerifyData(self, ToolData) -function Ammo:GetDisplayData(BulletData) - local Energy = ACF_Kinetic(BulletData.MuzzleVel * 39.37, BulletData.FlechetteMass, BulletData.LimitVel) + if not ToolData.Flechettes then + local Data5 = ToolData.RoundData5 - return { - MaxPen = (Energy.Penetration / BulletData.FlechettePenArea) * ACF.KEtoRHA - } + ToolData.Flechettes = Data5 and tonumber(Data5) or 0 + end + + if not ToolData.Spread then + local Data6 = ToolData.RoundData6 + + ToolData.Spread = Data6 and tonumber(Data6) or 0 + end end -function Ammo:GetCrateText(BulletData) - local Text = "Muzzle Velocity: %s m/s\nMax Penetration: %s mm\nMax Spread: %s degrees" - local Data = self:GetDisplayData(BulletData) - local Gun = ACF.Weapons.Guns[BulletData.Id] - local Spread = 0 +if SERVER then + ACF.AddEntityArguments("acf_ammo", "Flechettes", "Spread") -- Adding extra info to ammo crates + + function Ammo:OnLast(Entity) + Ammo.BaseClass.OnLast(self, Entity) - if Gun then - local GunClass = ACF.Classes.GunClass[Gun.gunclass] + Entity.Flechettes = nil + Entity.Spread = nil - Spread = GunClass and (GunClass.spread * ACF.GunInaccuracyScale) or 0 + -- Cleanup the leftovers aswell + Entity.RoundData5 = nil + Entity.RoundData6 = nil end - return Text:format(math.Round(BulletData.MuzzleVel, 2), math.Round(Data.MaxPen, 2), math.Round(BulletData.FlechetteSpread + Spread, 2)) -end + function Ammo:Create(Gun, BulletData) + local FlechetteData = { + Caliber = math.Round(BulletData.FlechetteRadius * 0.2, 2), + Id = BulletData.Id, + Type = "AP", + Owner = BulletData.Owner, + Entity = BulletData.Entity, + Gun = BulletData.Gun, + Pos = BulletData.Pos, + FrArea = BulletData.FlechetteArea, + ProjMass = BulletData.FlechetteMass, + DragCoef = BulletData.FlechetteDragCoef, + Tracer = BulletData.Tracer, + LimitVel = BulletData.LimitVel, + Ricochet = BulletData.Ricochet, + PenArea = BulletData.FlechettePenArea, + ShovePower = BulletData.ShovePower, + KETransfert = BulletData.KETransfert, + } + + --if ammo is cooking off, shoot in random direction + if Gun:GetClass() == "acf_ammo" then + local MuzzleVec = VectorRand() + + for _ = 1, BulletData.Flechettes do + local Inaccuracy = VectorRand() / 360 * ((Gun.Spread or 0) + BulletData.FlechetteSpread) + + FlechetteData.Flight = (MuzzleVec + Inaccuracy):GetNormalized() * BulletData.MuzzleVel * 39.37 + Gun:GetVelocity() + + ACF_CreateBullet(FlechetteData) + end + else + local BaseInaccuracy = math.tan(math.rad(Gun:GetSpread())) + local AddInaccuracy = math.tan(math.rad(BulletData.FlechetteSpread)) + local MuzzleVec = Gun:GetForward() + + for _ = 1, BulletData.Flechettes do + local GunUp, GunRight = Gun:GetUp(), Gun:GetRight() + local BaseInaccuracyMult = math.random() ^ (1 / math.Clamp(ACF.GunInaccuracyBias, 0.5, 4)) * (GunUp * (2 * math.random() - 1) + GunRight * (2 * math.random() - 1)):GetNormalized() + local AddSpreadMult = math.random() ^ (1 / math.Clamp(ACF.GunInaccuracyBias, 0.5, 4)) * (GunUp * (2 * math.random() - 1) + GunRight * (2 * math.random() - 1)):GetNormalized() + + BaseSpread = BaseInaccuracy * BaseInaccuracyMult + AddSpread = AddInaccuracy * AddSpreadMult + + FlechetteData.Flight = (MuzzleVec + BaseSpread + AddSpread):GetNormalized() * BulletData.MuzzleVel * 39.37 + Gun:GetVelocity() + + ACF_CreateBullet(FlechetteData) + end + end + end -function Ammo:MenuAction(Menu, ToolData, Data) - local Flechettes = Menu:AddSlider("Flechette Amount", Data.MinFlechettes, Data.MaxFlechettes) - Flechettes:SetDataVar("Flechettes", "OnValueChanged") - Flechettes:SetValueFunction(function(Panel) - ToolData.Flechettes = math.floor(ACF.ReadNumber("Flechettes")) + function Ammo:Network(Entity, BulletData) + Ammo.BaseClass.Network(self, Entity, BulletData) - Ammo:UpdateRoundData(ToolData, Data) + Entity:SetNW2String("AmmoType", "FL") + Entity:SetNW2Float("Caliber", math.Round(BulletData.FlechetteRadius * 0.2, 2)) + Entity:SetNW2Float("ProjMass", BulletData.FlechetteMass) + Entity:SetNW2Float("DragCoef", BulletData.FlechetteDragCoef) + end - Panel:SetValue(Data.Flechettes) + function Ammo:GetCrateText(BulletData) + local Text = "Muzzle Velocity: %s m/s\nMax Penetration: %s mm\nMax Spread: %s degrees" + local Data = self:GetDisplayData(BulletData) + local Gun = ACF.Weapons.Guns[BulletData.Id] + local Spread = 0 - return Data.Flechettes - end) + if Gun then + local GunClass = ACF.Classes.GunClass[Gun.gunclass] - local Spread = Menu:AddSlider("Flechette Spread", Data.MinSpread, Data.MaxSpread, 2) - Spread:SetDataVar("Spread", "OnValueChanged") - Spread:SetValueFunction(function(Panel) - ToolData.Spread = ACF.ReadNumber("Spread") + Spread = GunClass and (GunClass.spread * ACF.GunInaccuracyScale) or 0 + end - Ammo:UpdateRoundData(ToolData, Data) + return Text:format(math.Round(BulletData.MuzzleVel, 2), math.Round(Data.MaxPen, 2), math.Round(BulletData.FlechetteSpread + Spread, 2)) + end +else + ACF.RegisterAmmoDecal("FL", "damage/ap_pen", "damage/ap_rico") - Panel:SetValue(Data.FlechetteSpread) + function Ammo:MenuAction(Menu, ToolData, Data) + local Flechettes = Menu:AddSlider("Flechette Amount", Data.MinFlechettes, Data.MaxFlechettes) + Flechettes:SetDataVar("Flechettes", "OnValueChanged") + Flechettes:SetValueFunction(function(Panel) + ToolData.Flechettes = math.floor(ACF.ReadNumber("Flechettes")) - return Data.FlechetteSpread - end) + Ammo:UpdateRoundData(ToolData, Data) - local Tracer = Menu:AddCheckBox("Tracer") - Tracer:SetDataVar("Tracer", "OnChange") - Tracer:SetValueFunction(function(Panel) - ToolData.Tracer = ACF.ReadBool("Tracer") + Panel:SetValue(Data.Flechettes) - self:UpdateRoundData(ToolData, Data) + return Data.Flechettes + end) - ACF.WriteValue("Projectile", Data.ProjLength) - ACF.WriteValue("Propellant", Data.PropLength) + local Spread = Menu:AddSlider("Flechette Spread", Data.MinSpread, Data.MaxSpread, 2) + Spread:SetDataVar("Spread", "OnValueChanged") + Spread:SetValueFunction(function(Panel) + ToolData.Spread = ACF.ReadNumber("Spread") - Panel:SetText("Tracer : " .. Data.Tracer .. " cm") - Panel:SetValue(ToolData.Tracer) + Ammo:UpdateRoundData(ToolData, Data) - return ToolData.Tracer - end) + Panel:SetValue(Data.FlechetteSpread) - local RoundStats = Menu:AddLabel() - RoundStats:TrackDataVar("Projectile", "SetText") - RoundStats:TrackDataVar("Propellant") - RoundStats:TrackDataVar("Flechettes") - RoundStats:SetValueFunction(function() - self:UpdateRoundData(ToolData, Data) + return Data.FlechetteSpread + end) - local Text = "Muzzle Velocity : %s m/s\nProjectile Mass : %s\nPropellant Mass : %s\nFlechette Mass : %s" - local MuzzleVel = math.Round(Data.MuzzleVel * ACF.Scale, 2) - local ProjMass = ACF.GetProperMass(Data.ProjMass) - local PropMass = ACF.GetProperMass(Data.PropMass) - local FLMass = ACF.GetProperMass(Data.FlechetteMass) + local Tracer = Menu:AddCheckBox("Tracer") + Tracer:SetDataVar("Tracer", "OnChange") + Tracer:SetValueFunction(function(Panel) + ToolData.Tracer = ACF.ReadBool("Tracer") - return Text:format(MuzzleVel, ProjMass, PropMass, FLMass) - end) + self:UpdateRoundData(ToolData, Data) - local PenStats = Menu:AddLabel() - PenStats:TrackDataVar("Projectile", "SetText") - PenStats:TrackDataVar("Propellant") - PenStats:TrackDataVar("Flechettes") - PenStats:SetValueFunction(function() - self:UpdateRoundData(ToolData, Data) + ACF.WriteValue("Projectile", Data.ProjLength) + ACF.WriteValue("Propellant", Data.PropLength) - local Text = "Penetration : %s mm RHA\nAt 300m : %s mm RHA @ %s m/s\nAt 800m : %s mm RHA @ %s m/s" - local MaxPen = math.Round(Data.MaxPen, 2) - local R1V, R1P = ACF.PenRanging(Data.MuzzleVel, Data.FlechetteDragCoef, Data.FlechetteMass, Data.FlechettePenArea, Data.LimitVel, 300) - local R2V, R2P = ACF.PenRanging(Data.MuzzleVel, Data.FlechetteDragCoef, Data.FlechetteMass, Data.FlechettePenArea, Data.LimitVel, 800) + Panel:SetText("Tracer : " .. Data.Tracer .. " cm") + Panel:SetValue(ToolData.Tracer) - return Text:format(MaxPen, R1P, R1V, R2P, R2V) - end) + return ToolData.Tracer + end) - Menu:AddLabel("Note: The penetration range data is an approximation and may not be entirely accurate.") -end + local RoundStats = Menu:AddLabel() + RoundStats:TrackDataVar("Projectile", "SetText") + RoundStats:TrackDataVar("Propellant") + RoundStats:TrackDataVar("Flechettes") + RoundStats:SetValueFunction(function() + self:UpdateRoundData(ToolData, Data) + + local Text = "Muzzle Velocity : %s m/s\nProjectile Mass : %s\nPropellant Mass : %s\nFlechette Mass : %s" + local MuzzleVel = math.Round(Data.MuzzleVel * ACF.Scale, 2) + local ProjMass = ACF.GetProperMass(Data.ProjMass) + local PropMass = ACF.GetProperMass(Data.PropMass) + local FLMass = ACF.GetProperMass(Data.FlechetteMass) -ACF.RegisterAmmoDecal("FL", "damage/ap_pen", "damage/ap_rico") \ No newline at end of file + return Text:format(MuzzleVel, ProjMass, PropMass, FLMass) + end) + + local PenStats = Menu:AddLabel() + PenStats:TrackDataVar("Projectile", "SetText") + PenStats:TrackDataVar("Propellant") + PenStats:TrackDataVar("Flechettes") + PenStats:SetValueFunction(function() + self:UpdateRoundData(ToolData, Data) + + local Text = "Penetration : %s mm RHA\nAt 300m : %s mm RHA @ %s m/s\nAt 800m : %s mm RHA @ %s m/s" + local MaxPen = math.Round(Data.MaxPen, 2) + local R1V, R1P = ACF.PenRanging(Data.MuzzleVel, Data.FlechetteDragCoef, Data.FlechetteMass, Data.FlechettePenArea, Data.LimitVel, 300) + local R2V, R2P = ACF.PenRanging(Data.MuzzleVel, Data.FlechetteDragCoef, Data.FlechetteMass, Data.FlechettePenArea, Data.LimitVel, 800) + + return Text:format(MaxPen, R1P, R1V, R2P, R2V) + end) + + Menu:AddLabel("Note: The penetration range data is an approximation and may not be entirely accurate.") + end +end \ No newline at end of file diff --git a/lua/acf/shared/ammo_types/he.lua b/lua/acf/shared/ammo_types/he.lua index f73bfc954..6007fd7e9 100644 --- a/lua/acf/shared/ammo_types/he.lua +++ b/lua/acf/shared/ammo_types/he.lua @@ -11,6 +11,18 @@ function Ammo:OnLoaded() } end +function Ammo:GetDisplayData(Data) + local FragMass = Data.ProjMass - Data.FillerMass + local Fragments = math.max(math.floor((Data.FillerMass / FragMass) * ACF.HEFrag), 2) + + return { + BlastRadius = Data.FillerMass ^ 0.33 * 8, + Fragments = Fragments, + FragMass = FragMass / Fragments, + FragVel = (Data.FillerMass * ACF.HEPower * 1000 / FragMass / Fragments / Fragments) ^ 0.5, + } +end + function Ammo:UpdateRoundData(ToolData, Data, GUIData) GUIData = GUIData or Data @@ -37,11 +49,7 @@ function Ammo:UpdateRoundData(ToolData, Data, GUIData) end end -function Ammo:BaseConvert(_, ToolData) - if not ToolData.Projectile then ToolData.Projectile = 0 end - if not ToolData.Propellant then ToolData.Propellant = 0 end - if not ToolData.FillerMass then ToolData.FillerMass = 0 end - +function Ammo:BaseConvert(ToolData) local Data, GUIData = ACF.RoundBaseGunpowder(ToolData, {}) GUIData.MinFillerVol = 0 @@ -59,112 +67,96 @@ function Ammo:BaseConvert(_, ToolData) return Data, GUIData end -function Ammo:Network(Crate, BulletData) - Crate:SetNW2String("AmmoType", "HE") - Crate:SetNW2String("AmmoID", BulletData.Id) - Crate:SetNW2Float("Caliber", BulletData.Caliber) - Crate:SetNW2Float("ProjMass", BulletData.ProjMass) - Crate:SetNW2Float("FillerMass", BulletData.FillerMass) - Crate:SetNW2Float("PropMass", BulletData.PropMass) - Crate:SetNW2Float("DragCoef", BulletData.DragCoef) - Crate:SetNW2Float("MuzzleVel", BulletData.MuzzleVel) - Crate:SetNW2Float("Tracer", BulletData.Tracer) -end +if SERVER then + function Ammo:Network(Entity, BulletData) + Ammo.BaseClass.Network(self, Entity, BulletData) -function Ammo:GetDisplayData(Data) - local FragMass = Data.ProjMass - Data.FillerMass - local Fragments = math.max(math.floor((Data.FillerMass / FragMass) * ACF.HEFrag), 2) + Entity:SetNW2String("AmmoType", "HE") + end - return { - BlastRadius = Data.FillerMass ^ 0.33 * 8, - Fragments = Fragments, - FragMass = FragMass / Fragments, - FragVel = (Data.FillerMass * ACF.HEPower * 1000 / FragMass / Fragments / Fragments) ^ 0.5, - } -end + function Ammo:GetCrateText(BulletData) + local Text = "Muzzle Velocity: %s m/s\nBlast Radius: %s m\nBlast Energy: %s KJ" + local Data = self:GetDisplayData(BulletData) -function Ammo:GetCrateText(BulletData) - local Text = "Muzzle Velocity: %s m/s\nBlast Radius: %s m\nBlast Energy: %s KJ" - local Data = self:GetDisplayData(BulletData) + return Text:format(math.Round(BulletData.MuzzleVel, 2), math.Round(Data.BlastRadius, 2), math.Round(BulletData.FillerMass * ACF.HEPower, 2)) + end - return Text:format(math.Round(BulletData.MuzzleVel, 2), math.Round(Data.BlastRadius, 2), math.Round(BulletData.FillerMass * ACF.HEPower, 2)) -end + function Ammo:PropImpact(_, Bullet, Target, HitNormal, HitPos, Bone) + if ACF_Check(Target) then + local Speed = Bullet.Flight:Length() / ACF.Scale + local Energy = ACF_Kinetic(Speed, Bullet.ProjMass - Bullet.FillerMass, Bullet.LimitVel) + local HitRes = ACF_RoundImpact(Bullet, Speed, Energy, Target, HitPos, HitNormal, Bone) -function Ammo:PropImpact(_, Bullet, Target, HitNormal, HitPos, Bone) - if ACF_Check(Target) then - local Speed = Bullet.Flight:Length() / ACF.Scale - local Energy = ACF_Kinetic(Speed, Bullet.ProjMass - Bullet.FillerMass, Bullet.LimitVel) - local HitRes = ACF_RoundImpact(Bullet, Speed, Energy, Target, HitPos, HitNormal, Bone) + if HitRes.Ricochet then return "Ricochet" end + end - if HitRes.Ricochet then return "Ricochet" end + return false end - return false -end - -function Ammo:WorldImpact() - return false -end - -function Ammo:MenuAction(Menu, ToolData, Data) - local FillerMass = Menu:AddSlider("Filler Volume", 0, Data.MaxFillerVol, 2) - FillerMass:SetDataVar("FillerMass", "OnValueChanged") - FillerMass:TrackDataVar("Projectile") - FillerMass:SetValueFunction(function(Panel) - ToolData.FillerMass = math.Round(ACF.ReadNumber("FillerMass"), 2) + function Ammo:WorldImpact() + return false + end +else + ACF.RegisterAmmoDecal("HE", "damage/he_pen", "damage/he_rico") - self:UpdateRoundData(ToolData, Data) + function Ammo:MenuAction(Menu, ToolData, Data) + local FillerMass = Menu:AddSlider("Filler Volume", 0, Data.MaxFillerVol, 2) + FillerMass:SetDataVar("FillerMass", "OnValueChanged") + FillerMass:TrackDataVar("Projectile") + FillerMass:SetValueFunction(function(Panel) + ToolData.FillerMass = math.Round(ACF.ReadNumber("FillerMass"), 2) - Panel:SetMax(Data.MaxFillerVol) - Panel:SetValue(Data.FillerVol) + self:UpdateRoundData(ToolData, Data) - return Data.FillerVol - end) + Panel:SetMax(Data.MaxFillerVol) + Panel:SetValue(Data.FillerVol) - local Tracer = Menu:AddCheckBox("Tracer") - Tracer:SetDataVar("Tracer", "OnChange") - Tracer:SetValueFunction(function(Panel) - ToolData.Tracer = ACF.ReadBool("Tracer") + return Data.FillerVol + end) - self:UpdateRoundData(ToolData, Data) + local Tracer = Menu:AddCheckBox("Tracer") + Tracer:SetDataVar("Tracer", "OnChange") + Tracer:SetValueFunction(function(Panel) + ToolData.Tracer = ACF.ReadBool("Tracer") - ACF.WriteValue("Projectile", Data.ProjLength) - ACF.WriteValue("Propellant", Data.PropLength) + self:UpdateRoundData(ToolData, Data) - Panel:SetText("Tracer : " .. Data.Tracer .. " cm") - Panel:SetValue(ToolData.Tracer) + ACF.WriteValue("Projectile", Data.ProjLength) + ACF.WriteValue("Propellant", Data.PropLength) - return ToolData.Tracer - end) + Panel:SetText("Tracer : " .. Data.Tracer .. " cm") + Panel:SetValue(ToolData.Tracer) - local RoundStats = Menu:AddLabel() - RoundStats:TrackDataVar("Projectile", "SetText") - RoundStats:TrackDataVar("Propellant") - RoundStats:TrackDataVar("FillerMass") - RoundStats:SetValueFunction(function() - self:UpdateRoundData(ToolData, Data) + return ToolData.Tracer + end) - local Text = "Muzzle Velocity : %s m/s\nProjectile Mass : %s\nPropellant Mass : %s\nExplosive Mass : %s" - local MuzzleVel = math.Round(Data.MuzzleVel * ACF.Scale, 2) - local ProjMass = ACF.GetProperMass(Data.ProjMass) - local PropMass = ACF.GetProperMass(Data.PropMass) - local Filler = ACF.GetProperMass(Data.FillerMass) + local RoundStats = Menu:AddLabel() + RoundStats:TrackDataVar("Projectile", "SetText") + RoundStats:TrackDataVar("Propellant") + RoundStats:TrackDataVar("FillerMass") + RoundStats:SetValueFunction(function() + self:UpdateRoundData(ToolData, Data) - return Text:format(MuzzleVel, ProjMass, PropMass, Filler) - end) + local Text = "Muzzle Velocity : %s m/s\nProjectile Mass : %s\nPropellant Mass : %s\nExplosive Mass : %s" + local MuzzleVel = math.Round(Data.MuzzleVel * ACF.Scale, 2) + local ProjMass = ACF.GetProperMass(Data.ProjMass) + local PropMass = ACF.GetProperMass(Data.PropMass) + local Filler = ACF.GetProperMass(Data.FillerMass) - local FillerStats = Menu:AddLabel() - FillerStats:TrackDataVar("FillerMass", "SetText") - FillerStats:SetValueFunction(function() - self:UpdateRoundData(ToolData, Data) + return Text:format(MuzzleVel, ProjMass, PropMass, Filler) + end) - local Text = "Blast Radius : %s m\nFragments : %s\nFragment Mass : %s\nFragment Velocity : %s m/s" - local Blast = math.Round(Data.BlastRadius, 2) - local FragMass = ACF.GetProperMass(Data.FragMass) - local FragVel = math.Round(Data.FragVel, 2) + local FillerStats = Menu:AddLabel() + FillerStats:TrackDataVar("FillerMass", "SetText") + FillerStats:SetValueFunction(function() + self:UpdateRoundData(ToolData, Data) - return Text:format(Blast, Data.Fragments, FragMass, FragVel) - end) -end + local Text = "Blast Radius : %s m\nFragments : %s\nFragment Mass : %s\nFragment Velocity : %s m/s" + local Blast = math.Round(Data.BlastRadius, 2) + local FragMass = ACF.GetProperMass(Data.FragMass) + local FragVel = math.Round(Data.FragVel, 2) -ACF.RegisterAmmoDecal("HE", "damage/he_pen", "damage/he_rico") + return Text:format(Blast, Data.Fragments, FragMass, FragVel) + end) + end +end \ No newline at end of file diff --git a/lua/acf/shared/ammo_types/heat.lua b/lua/acf/shared/ammo_types/heat.lua index b0ebef0fb..15972021a 100644 --- a/lua/acf/shared/ammo_types/heat.lua +++ b/lua/acf/shared/ammo_types/heat.lua @@ -1,5 +1,4 @@ local Ammo = ACF.RegisterAmmoType("HEAT", "AP") -local DecalIndex = ACF.GetAmmoDecalIndex function Ammo:OnLoaded() Ammo.BaseClass.OnLoaded(self) @@ -41,19 +40,42 @@ function Ammo:CalcSlugMV(Data, HEATFillerMass) return (HEATFillerMass * 0.5 * ACF.HEPower * math.sin(math.rad(10 + (Data.ConeAng or 55)) * 0.5) / Data.SlugMass) ^ ACF.HEATMVScale end +function Ammo:GetDisplayData(Data) + local Crushed, HEATFiller, BoomFiller = self:CrushCalc(Data.MuzzleVel, Data.FillerMass) + local SlugMV = self:CalcSlugMV(Data, HEATFiller) * (Data.SlugPenMul or 1) + local MassUsed = Data.SlugMass * (1 - Crushed) + local Energy = ACF_Kinetic(Data.MuzzleVel * 39.37 + SlugMV * 39.37, MassUsed, 999999) + local FragMass = Data.CasingMass + Data.SlugMass * Crushed + local Fragments = math.max(math.floor((BoomFiller / FragMass) * ACF.HEFrag), 2) + + return { + Crushed = Crushed, + HEATFillerMass = HEATFiller, + BoomFillerMass = BoomFiller, + SlugMV = SlugMV, + SlugMassUsed = MassUsed, + MaxPen = (Energy.Penetration / Data.SlugPenArea) * ACF.KEtoRHA, + TotalFragMass = FragMass, + BlastRadius = BoomFiller ^ 0.33 * 8, + Fragments = Fragments, + FragMass = FragMass / Fragments, + FragVel = (BoomFiller * ACF.HEPower * 1000 / FragMass) ^ 0.5, + } +end + function Ammo:UpdateRoundData(ToolData, Data, GUIData) GUIData = GUIData or Data ACF.UpdateRoundSpecs(ToolData, Data, GUIData) - local MaxConeAng = math.deg(math.atan((Data.ProjLength - Data.Caliber * 0.002) / (Data.Caliber * 0.05))) + local MaxConeAng = math.deg(math.atan((Data.ProjLength - Data.Caliber * 0.02) / (Data.Caliber * 0.5))) local LinerAngle = math.Clamp(ToolData.LinerAngle, GUIData.MinConeAng, MaxConeAng) - local _, ConeArea, AirVol = self:ConeCalc(LinerAngle, Data.Caliber * 0.05) + local _, ConeArea, AirVol = self:ConeCalc(LinerAngle, Data.Caliber * 0.5) local LinerRad = math.rad(LinerAngle * 0.5) - local SlugCaliber = Data.Caliber * 0.1 - Data.Caliber * (math.sin(LinerRad) * 0.5 + math.cos(LinerRad) * 1.5) * 0.05 + local SlugCaliber = Data.Caliber - Data.Caliber * (math.sin(LinerRad) * 0.5 + math.cos(LinerRad) * 1.5) / 2 local SlugFrArea = 3.1416 * (SlugCaliber * 0.5) ^ 2 - local ConeVol = ConeArea * Data.Caliber * 0.002 + local ConeVol = ConeArea * Data.Caliber * 0.02 local ProjMass = math.max(GUIData.ProjVolume - ToolData.FillerMass, 0) * 0.0079 + math.min(ToolData.FillerMass, GUIData.ProjVolume) * ACF.HEDensity * 0.001 + ConeVol * 0.0079 --Volume of the projectile as a cylinder - Volume of the filler - Volume of the crush cone * density of steel + Volume of the filler * density of TNT + Area of the cone * thickness * density of steel local MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, ProjMass) local Energy = ACF_Kinetic(MuzzleVel * 39.37, ProjMass, Data.LimitVel) @@ -85,12 +107,7 @@ function Ammo:UpdateRoundData(ToolData, Data, GUIData) end end -function Ammo:BaseConvert(_, ToolData) - if not ToolData.Projectile then ToolData.Projectile = 0 end - if not ToolData.Propellant then ToolData.Propellant = 0 end - if not ToolData.FillerMass then ToolData.FillerMass = 0 end - if not ToolData.LinerAngle then ToolData.LinerAngle = 0 end - +function Ammo:BaseConvert(ToolData) local Data, GUIData = ACF.RoundBaseGunpowder(ToolData, {}) GUIData.MinConeAng = 0 @@ -112,289 +129,292 @@ function Ammo:BaseConvert(_, ToolData) return Data, GUIData end -function Ammo:Network(Crate, BulletData) - Crate:SetNW2String("AmmoType", "HEAT") - Crate:SetNW2String("AmmoID", BulletData.Id) - Crate:SetNW2Float("Caliber", BulletData.Caliber) - Crate:SetNW2Float("ProjMass", BulletData.ProjMass) - Crate:SetNW2Float("FillerMass", BulletData.FillerMass) - Crate:SetNW2Float("PropMass", BulletData.PropMass) - Crate:SetNW2Float("DragCoef", BulletData.DragCoef) - Crate:SetNW2Float("SlugMass", BulletData.SlugMass) - Crate:SetNW2Float("SlugCaliber", BulletData.SlugCaliber) - Crate:SetNW2Float("SlugDragCoef", BulletData.SlugDragCoef) - Crate:SetNW2Float("MuzzleVel", BulletData.MuzzleVel) - Crate:SetNW2Float("Tracer", BulletData.Tracer) -end +function Ammo:VerifyData(ToolData) + Ammo.BaseClass.VerifyData(self, ToolData) -function Ammo:GetDisplayData(Data) - local Crushed, HEATFiller, BoomFiller = self:CrushCalc(Data.MuzzleVel, Data.FillerMass) - local SlugMV = self:CalcSlugMV(Data, HEATFiller) * (Data.SlugPenMul or 1) - local MassUsed = Data.SlugMass * (1 - Crushed) - local Energy = ACF_Kinetic(Data.MuzzleVel * 39.37 + SlugMV * 39.37, MassUsed, 999999) - local FragMass = Data.CasingMass + Data.SlugMass * Crushed - local Fragments = math.max(math.floor((BoomFiller / FragMass) * ACF.HEFrag), 2) + if not ToolData.FillerMass then + local Data5 = ToolData.RoundData5 - return { - Crushed = Crushed, - HEATFillerMass = HEATFiller, - BoomFillerMass = BoomFiller, - SlugMV = SlugMV, - SlugMassUsed = MassUsed, - MaxPen = (Energy.Penetration / Data.SlugPenArea) * ACF.KEtoRHA, - TotalFragMass = FragMass, - BlastRadius = BoomFiller ^ 0.33 * 8, - Fragments = Fragments, - FragMass = FragMass / Fragments, - FragVel = (BoomFiller * ACF.HEPower * 1000 / FragMass) ^ 0.5, - } -end + ToolData.FillerMass = Data5 and tonumber(Data5) or 0 + end -function Ammo:GetCrateText(BulletData) - local Text = "Muzzle Velocity: %s m/s\nMax Penetration: %s mm\nBlast Radius: %s m\n", "Blast Energy: %s KJ" - local Data = self:GetDisplayData(BulletData) + if not ToolData.LinerAngle then + local Data6 = ToolData.RoundData6 - return Text:format(math.Round(BulletData.MuzzleVel, 2), math.Round(Data.MaxPen, 2), math.Round(Data.BlastRadius, 2), math.Round(Data.BoomFillerMass * ACF.HEPower, 2)) + ToolData.LinerAngle = Data6 and tonumber(Data6) or 0 + end end -function Ammo:Detonate(Bullet, HitPos) - local Crushed, HEATFillerMass, BoomFillerMass = self:CrushCalc(Bullet.Flight:Length() * 0.0254, Bullet.FillerMass) +if SERVER then + ACF.AddEntityArguments("acf_ammo", "LinerAngle") -- Adding extra info to ammo crates - ACF_HE(HitPos - Bullet.Flight:GetNormalized() * 3, BoomFillerMass, Bullet.CasingMass + Bullet.SlugMass * Crushed, Bullet.Owner, nil, Bullet.Gun) + function Ammo:OnLast(Entity) + Ammo.BaseClass.OnLast(self, Entity) - if Crushed == 1 then return false end -- no HEAT jet to fire off, it was all converted to HE + Entity.FillerMass = nil + Entity.LinerAngle = nil - local DeltaTime = ACF.CurTime - Bullet.LastThink + -- Cleanup the leftovers aswell + Entity.RoundData5 = nil + Entity.RoundData6 = nil - Bullet.Detonated = true - Bullet.InitTime = ACF.CurTime - Bullet.Flight = Bullet.Flight + Bullet.Flight:GetNormalized() * self:CalcSlugMV(Bullet, HEATFillerMass) * 39.37 - Bullet.FuseLength = 0.005 + 40 / (Bullet.Flight:Length() * 0.0254) - Bullet.Pos = HitPos - Bullet.DragCoef = Bullet.SlugDragCoef - Bullet.ProjMass = Bullet.SlugMass * (1 - Crushed) - Bullet.Caliber = Bullet.SlugCaliber - Bullet.PenArea = Bullet.SlugPenArea - Bullet.Ricochet = Bullet.SlugRicochet - Bullet.StartTrace = Bullet.Pos - Bullet.Flight:GetNormalized() * math.min(ACF.PhysMaxVel * DeltaTime, Bullet.FlightTime * Bullet.Flight:Length()) - Bullet.NextPos = Bullet.Pos + (Bullet.Flight * ACF.Scale * DeltaTime) --Calculates the next shell position + Entity:SetNW2Float("FillerMass", 0) + end - return true -end + function Ammo:Network(Entity, BulletData) + Ammo.BaseClass.Network(self, Entity, BulletData) -function Ammo:PropImpact(_, Bullet, Target, HitNormal, HitPos, Bone) - if ACF_Check(Target) then - local Speed = Bullet.Flight:Length() / ACF.Scale + Entity:SetNW2String("AmmoType", "HEAT") + Entity:SetNW2Float("FillerMass", BulletData.FillerMass) + end - if Bullet.Detonated then - Bullet.NotFirstPen = true + function Ammo:GetCrateText(BulletData) + local Text = "Muzzle Velocity: %s m/s\nMax Penetration: %s mm\nBlast Radius: %s m\n", "Blast Energy: %s KJ" + local Data = self:GetDisplayData(BulletData) - local Energy = ACF_Kinetic(Speed, Bullet.ProjMass, 999999) - local HitRes = ACF_RoundImpact(Bullet, Speed, Energy, Target, HitPos, HitNormal, Bone) + return Text:format(math.Round(BulletData.MuzzleVel, 2), math.Round(Data.MaxPen, 2), math.Round(Data.BlastRadius, 2), math.Round(Data.BoomFillerMass * ACF.HEPower, 2)) + end - if HitRes.Overkill > 0 then - table.insert(Bullet.Filter, Target) --"Penetrate" (Ingoring the prop for the retry trace) + function Ammo:Detonate(Bullet, HitPos) + local Crushed, HEATFillerMass, BoomFillerMass = self:CrushCalc(Bullet.Flight:Length() * 0.0254, Bullet.FillerMass) - Bullet.Flight = Bullet.Flight:GetNormalized() * math.sqrt(Energy.Kinetic * (1 - HitRes.Loss) * ((Bullet.NotFirstPen and ACF.HEATPenLayerMul) or 1) * 2000 / Bullet.ProjMass) * 39.37 + ACF_HE(HitPos, BoomFillerMass, Bullet.CasingMass + Bullet.SlugMass * Crushed, Bullet.Owner, nil, Bullet.Gun) - return "Penetrated" - else - return false - end - else - local Energy = ACF_Kinetic(Speed, Bullet.ProjMass - Bullet.FillerMass, Bullet.LimitVel) - local HitRes = ACF_RoundImpact(Bullet, Speed, Energy, Target, HitPos, HitNormal, Bone) + if Crushed == 1 then return false end -- no HEAT jet to fire off, it was all converted to HE + + local DeltaTime = ACF.CurTime - Bullet.LastThink + + Bullet.Detonated = true + Bullet.InitTime = ACF.CurTime + Bullet.Flight = Bullet.Flight + Bullet.Flight:GetNormalized() * self:CalcSlugMV(Bullet, HEATFillerMass) * 39.37 + Bullet.Pos = HitPos + Bullet.DragCoef = Bullet.SlugDragCoef + Bullet.ProjMass = Bullet.SlugMass * (1 - Crushed) + Bullet.Caliber = Bullet.SlugCaliber + Bullet.PenArea = Bullet.SlugPenArea + Bullet.Ricochet = Bullet.SlugRicochet + Bullet.StartTrace = Bullet.Pos - Bullet.Flight:GetNormalized() * math.min(ACF.PhysMaxVel * DeltaTime, Bullet.FlightTime * Bullet.Flight:Length()) + Bullet.NextPos = Bullet.Pos + (Bullet.Flight * ACF.Scale * DeltaTime) --Calculates the next shell position + + return true + end + + function Ammo:PropImpact(_, Bullet, Target, HitNormal, HitPos, Bone) + if ACF_Check(Target) then + local Speed = Bullet.Flight:Length() / ACF.Scale + + if Bullet.Detonated then + Bullet.NotFirstPen = true + + local Energy = ACF_Kinetic(Speed, Bullet.ProjMass, 999999) + local HitRes = ACF_RoundImpact(Bullet, Speed, Energy, Target, HitPos, HitNormal, Bone) + + if HitRes.Overkill > 0 then + table.insert(Bullet.Filter, Target) --"Penetrate" (Ingoring the prop for the retry trace) + + Bullet.Flight = Bullet.Flight:GetNormalized() * math.sqrt(Energy.Kinetic * (1 - HitRes.Loss) * ((Bullet.NotFirstPen and ACF.HEATPenLayerMul) or 1) * 2000 / Bullet.ProjMass) * 39.37 - if HitRes.Ricochet then - return "Ricochet" - else - if self:Detonate(Bullet, HitPos, HitNormal) then return "Penetrated" else return false end + else + local Energy = ACF_Kinetic(Speed, Bullet.ProjMass - Bullet.FillerMass, Bullet.LimitVel) + local HitRes = ACF_RoundImpact(Bullet, Speed, Energy, Target, HitPos, HitNormal, Bone) + + if HitRes.Ricochet then + return "Ricochet" + else + if self:Detonate(Bullet, HitPos, HitNormal) then + return "Penetrated" + else + return false + end + end end + else + table.insert(Bullet.Filter, Target) + + return "Penetrated" end - else - table.insert(Bullet.Filter, Target) - return "Penetrated" + return false end - return false -end + function Ammo:WorldImpact(_, Bullet, HitPos, HitNormal) + if not Bullet.Detonated then + if self:Detonate(Bullet, HitPos, HitNormal) then + return "Penetrated" + else + return false + end + end -function Ammo:WorldImpact(_, Bullet, HitPos, HitNormal) - if not Bullet.Detonated then - if self:Detonate(Bullet, HitPos, HitNormal) then + local Energy = ACF_Kinetic(Bullet.Flight:Length() / ACF.Scale, Bullet.ProjMass, 999999) + local HitRes = ACF_PenetrateGround(Bullet, Energy, HitPos, HitNormal) + + if HitRes.Penetrated then return "Penetrated" else return false end end +else + ACF.RegisterAmmoDecal("HEAT", "damage/heat_pen", "damage/heat_rico", function(Caliber) return Caliber * 0.1667 end) - local Energy = ACF_Kinetic(Bullet.Flight:Length() / ACF.Scale, Bullet.ProjMass, 999999) - local HitRes = ACF_PenetrateGround(Bullet, Energy, HitPos, HitNormal) + local DecalIndex = ACF.GetAmmoDecalIndex - if HitRes.Penetrated then - return "Penetrated" - else - return false - end -end + function Ammo:PenetrationEffect(Effect, Bullet) + if Bullet.Detonated then + local Data = EffectData() + Data:SetOrigin(Bullet.SimPos) + Data:SetNormal(Bullet.SimFlight:GetNormalized()) + Data:SetScale(Bullet.SimFlight:Length()) + Data:SetMagnitude(Bullet.RoundMass) + Data:SetRadius(Bullet.Caliber) + Data:SetDamageType(DecalIndex(Bullet.AmmoType)) + + util.Effect("ACF_Penetration", Data) + else + local _, _, BoomFillerMass = self:CrushCalc(Bullet.SimFlight:Length() * 0.0254, Bullet.FillerMass) + local Data = EffectData() + Data:SetOrigin(Bullet.SimPos) + Data:SetNormal(Bullet.SimFlight:GetNormalized()) + Data:SetRadius(math.max(BoomFillerMass ^ 0.33 * 8 * 39.37, 1)) -function Ammo:PenetrationEffect(Effect, Bullet) - if Bullet.Detonated then - local Data = EffectData() - Data:SetOrigin(Bullet.SimPos) - Data:SetNormal(Bullet.SimFlight:GetNormalized()) - Data:SetScale(Bullet.SimFlight:Length()) - Data:SetMagnitude(Bullet.RoundMass) - Data:SetRadius(Bullet.Caliber) - Data:SetDamageType(DecalIndex(Bullet.AmmoType)) - - util.Effect("ACF_Penetration", Data) - else - local _, _, BoomFillerMass = self:CrushCalc(Bullet.SimFlight:Length() * 0.0254, Bullet.FillerMass) - local Data = EffectData() - Data:SetOrigin(Bullet.SimPos) - Data:SetNormal(Bullet.SimFlight:GetNormalized()) - Data:SetRadius(math.max(BoomFillerMass ^ 0.33 * 8 * 39.37, 1)) - - util.Effect("ACF_HEAT_Explosion", Data) - - Bullet.Detonated = true - - Effect:SetModel("models/Gibs/wood_gib01e.mdl") - end -end + util.Effect("ACF_HEAT_Explosion", Data) -function Ammo:RicochetEffect(_, Bullet) - local Detonated = Bullet.Detonated - local Effect = EffectData() - Effect:SetOrigin(Bullet.SimPos) - Effect:SetNormal(Bullet.SimFlight:GetNormalized()) - Effect:SetScale(Bullet.SimFlight:Length()) - Effect:SetMagnitude(Bullet.RoundMass) - Effect:SetRadius(Bullet.Caliber) - Effect:SetDamageType(DecalIndex(Detonated and Bullet.AmmoType or "AP")) - - util.Effect("ACF_Ricochet", Effect) -end + Bullet.Detonated = true -function Ammo:MenuAction(Menu, ToolData, Data) - local LinerAngle = Menu:AddSlider("Liner Angle", Data.MinConeAng, Data.MaxConeAng, 2) - LinerAngle:SetDataVar("LinerAngle", "OnValueChanged") - LinerAngle:TrackDataVar("Projectile") - LinerAngle:SetValueFunction(function(Panel) - ToolData.LinerAngle = math.Round(ACF.ReadNumber("LinerAngle"), 2) - - self:UpdateRoundData(ToolData, Data) - - Panel:SetMax(Data.MaxConeAng) - Panel:SetValue(Data.ConeAng) - - return Data.ConeAng - end) - - local FillerMass = Menu:AddSlider("Filler Volume", 0, Data.MaxFillerVol, 2) - FillerMass:SetDataVar("FillerMass", "OnValueChanged") - FillerMass:TrackDataVar("Projectile") - FillerMass:TrackDataVar("LinerAngle") - FillerMass:SetValueFunction(function(Panel) - ToolData.FillerMass = math.Round(ACF.ReadNumber("FillerMass"), 2) - - self:UpdateRoundData(ToolData, Data) - - Panel:SetMax(Data.MaxFillerVol) - Panel:SetValue(Data.FillerVol) - - return Data.FillerVol - end) - - local Tracer = Menu:AddCheckBox("Tracer") - Tracer:SetDataVar("Tracer", "OnChange") - Tracer:SetValueFunction(function(Panel) - ToolData.Tracer = ACF.ReadBool("Tracer") - - self:UpdateRoundData(ToolData, Data) - - ACF.WriteValue("Projectile", Data.ProjLength) - ACF.WriteValue("Propellant", Data.PropLength) - - Panel:SetText("Tracer : " .. Data.Tracer .. " cm") - Panel:SetValue(ToolData.Tracer) - - return ToolData.Tracer - end) - - local RoundStats = Menu:AddLabel() - RoundStats:TrackDataVar("Projectile", "SetText") - RoundStats:TrackDataVar("Propellant") - RoundStats:TrackDataVar("FillerMass") - RoundStats:TrackDataVar("LinerAngle") - RoundStats:SetValueFunction(function() - self:UpdateRoundData(ToolData, Data) - - local Text = "Muzzle Velocity : %s m/s\nProjectile Mass : %s\nPropellant Mass : %s\nExplosive Mass : %s" - local MuzzleVel = math.Round(Data.MuzzleVel * ACF.Scale, 2) - local ProjMass = ACF.GetProperMass(Data.ProjMass) - local PropMass = ACF.GetProperMass(Data.PropMass) - local Filler = ACF.GetProperMass(Data.FillerMass) - - return Text:format(MuzzleVel, ProjMass, PropMass, Filler) - end) - - local FillerStats = Menu:AddLabel() - FillerStats:TrackDataVar("FillerMass", "SetText") - FillerStats:TrackDataVar("LinerAngle") - FillerStats:SetValueFunction(function() - self:UpdateRoundData(ToolData, Data) - - local Text = "Blast Radius : %s m\nFragments : %s\nFragment Mass : %s\nFragment Velocity : %s m/s" - local Blast = math.Round(Data.BlastRadius, 2) - local FragMass = ACF.GetProperMass(Data.FragMass) - local FragVel = math.Round(Data.FragVel, 2) - - return Text:format(Blast, Data.Fragments, FragMass, FragVel) - end) - - local Penetrator = Menu:AddLabel() - Penetrator:TrackDataVar("Projectile", "SetText") - Penetrator:TrackDataVar("Propellant") - Penetrator:TrackDataVar("FillerMass") - Penetrator:TrackDataVar("LinerAngle") - Penetrator:SetValueFunction(function() - self:UpdateRoundData(ToolData, Data) - - local Text = "Penetrator Caliber : %s mm\nPenetrator Mass : %s\nPenetrator Velocity : %s m/s" - local Caliber = math.Round(Data.SlugCaliber * 10, 2) - local Mass = ACF.GetProperMass(Data.SlugMassUsed) - local Velocity = math.Round(Data.MuzzleVel + Data.SlugMV, 2) - - return Text:format(Caliber, Mass, Velocity) - end) - - local PenStats = Menu:AddLabel() - PenStats:TrackDataVar("Projectile", "SetText") - PenStats:TrackDataVar("Propellant") - PenStats:TrackDataVar("FillerMass") - PenStats:TrackDataVar("LinerAngle") - PenStats:SetValueFunction(function() - self:UpdateRoundData(ToolData, Data) - - local Text = "Penetration : %s mm RHA\nAt 300m : %s mm RHA @ %s m/s\nAt 800m : %s mm RHA @ %s m/s" - local MaxPen = math.Round(Data.MaxPen, 2) - local R1V, R1P = ACF.PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 300) - local R2V, R2P = ACF.PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 800) - - R1P = math.Round((ACF_Kinetic((R1V + Data.SlugMV) * 39.37, Data.SlugMassUsed, 999999).Penetration / Data.SlugPenArea) * ACF.KEtoRHA, 2) - R2P = math.Round((ACF_Kinetic((R2V + Data.SlugMV) * 39.37, Data.SlugMassUsed, 999999).Penetration / Data.SlugPenArea) * ACF.KEtoRHA, 2) - - return Text:format(MaxPen, R1P, R1V, R2P, R2V) - end) - - Menu:AddLabel("Note: The penetration range data is an approximation and may not be entirely accurate.") -end + Effect:SetModel("models/Gibs/wood_gib01e.mdl") + end + end -ACF.RegisterAmmoDecal("HEAT", "damage/heat_pen", "damage/heat_rico", function(Caliber) return Caliber * 0.1667 end) + function Ammo:RicochetEffect(_, Bullet) + local Detonated = Bullet.Detonated + local Effect = EffectData() + Effect:SetOrigin(Bullet.SimPos) + Effect:SetNormal(Bullet.SimFlight:GetNormalized()) + Effect:SetScale(Bullet.SimFlight:Length()) + Effect:SetMagnitude(Bullet.RoundMass) + Effect:SetRadius(Bullet.Caliber) + Effect:SetDamageType(DecalIndex(Detonated and Bullet.AmmoType or "AP")) + + util.Effect("ACF_Ricochet", Effect) + end + + function Ammo:MenuAction(Menu, ToolData, Data) + local LinerAngle = Menu:AddSlider("Liner Angle", Data.MinConeAng, Data.MaxConeAng, 2) + LinerAngle:SetDataVar("LinerAngle", "OnValueChanged") + LinerAngle:TrackDataVar("Projectile") + LinerAngle:SetValueFunction(function(Panel) + ToolData.LinerAngle = math.Round(ACF.ReadNumber("LinerAngle"), 2) + + self:UpdateRoundData(ToolData, Data) + + Panel:SetMax(Data.MaxConeAng) + Panel:SetValue(Data.ConeAng) + + return Data.ConeAng + end) + + local FillerMass = Menu:AddSlider("Filler Volume", 0, Data.MaxFillerVol, 2) + FillerMass:SetDataVar("FillerMass", "OnValueChanged") + FillerMass:TrackDataVar("Projectile") + FillerMass:TrackDataVar("LinerAngle") + FillerMass:SetValueFunction(function(Panel) + ToolData.FillerMass = math.Round(ACF.ReadNumber("FillerMass"), 2) + + self:UpdateRoundData(ToolData, Data) + + Panel:SetMax(Data.MaxFillerVol) + Panel:SetValue(Data.FillerVol) + + return Data.FillerVol + end) + + local Tracer = Menu:AddCheckBox("Tracer") + Tracer:SetDataVar("Tracer", "OnChange") + Tracer:SetValueFunction(function(Panel) + ToolData.Tracer = ACF.ReadBool("Tracer") + + self:UpdateRoundData(ToolData, Data) + + ACF.WriteValue("Projectile", Data.ProjLength) + ACF.WriteValue("Propellant", Data.PropLength) + + Panel:SetText("Tracer : " .. Data.Tracer .. " cm") + Panel:SetValue(ToolData.Tracer) + + return ToolData.Tracer + end) + + local RoundStats = Menu:AddLabel() + RoundStats:TrackDataVar("Projectile", "SetText") + RoundStats:TrackDataVar("Propellant") + RoundStats:TrackDataVar("FillerMass") + RoundStats:TrackDataVar("LinerAngle") + RoundStats:SetValueFunction(function() + self:UpdateRoundData(ToolData, Data) + + local Text = "Muzzle Velocity : %s m/s\nProjectile Mass : %s\nPropellant Mass : %s\nExplosive Mass : %s" + local MuzzleVel = math.Round(Data.MuzzleVel * ACF.Scale, 2) + local ProjMass = ACF.GetProperMass(Data.ProjMass) + local PropMass = ACF.GetProperMass(Data.PropMass) + local Filler = ACF.GetProperMass(Data.FillerMass) + + return Text:format(MuzzleVel, ProjMass, PropMass, Filler) + end) + + local FillerStats = Menu:AddLabel() + FillerStats:TrackDataVar("FillerMass", "SetText") + FillerStats:TrackDataVar("LinerAngle") + FillerStats:SetValueFunction(function() + self:UpdateRoundData(ToolData, Data) + + local Text = "Blast Radius : %s m\nFragments : %s\nFragment Mass : %s\nFragment Velocity : %s m/s" + local Blast = math.Round(Data.BlastRadius, 2) + local FragMass = ACF.GetProperMass(Data.FragMass) + local FragVel = math.Round(Data.FragVel, 2) + + return Text:format(Blast, Data.Fragments, FragMass, FragVel) + end) + + local Penetrator = Menu:AddLabel() + Penetrator:TrackDataVar("Projectile", "SetText") + Penetrator:TrackDataVar("Propellant") + Penetrator:TrackDataVar("FillerMass") + Penetrator:TrackDataVar("LinerAngle") + Penetrator:SetValueFunction(function() + self:UpdateRoundData(ToolData, Data) + + local Text = "Penetrator Caliber : %s mm\nPenetrator Mass : %s\nPenetrator Velocity : %s m/s" + local Caliber = math.Round(Data.SlugCaliber * 10, 2) + local Mass = ACF.GetProperMass(Data.SlugMassUsed) + local Velocity = math.Round(Data.MuzzleVel + Data.SlugMV, 2) + + return Text:format(Caliber, Mass, Velocity) + end) + + local PenStats = Menu:AddLabel() + PenStats:TrackDataVar("Projectile", "SetText") + PenStats:TrackDataVar("Propellant") + PenStats:TrackDataVar("FillerMass") + PenStats:TrackDataVar("LinerAngle") + PenStats:SetValueFunction(function() + self:UpdateRoundData(ToolData, Data) + + local Text = "Penetration : %s mm RHA\nAt 300m : %s mm RHA @ %s m/s\nAt 800m : %s mm RHA @ %s m/s" + local MaxPen = math.Round(Data.MaxPen, 2) + local R1V, R1P = ACF.PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 300) + local R2V, R2P = ACF.PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 800) + + R1P = math.Round((ACF_Kinetic((R1V + Data.SlugMV) * 39.37, Data.SlugMassUsed, 999999).Penetration / Data.SlugPenArea) * ACF.KEtoRHA, 2) + R2P = math.Round((ACF_Kinetic((R2V + Data.SlugMV) * 39.37, Data.SlugMassUsed, 999999).Penetration / Data.SlugPenArea) * ACF.KEtoRHA, 2) + + return Text:format(MaxPen, R1P, R1V, R2P, R2V) + end) + + Menu:AddLabel("Note: The penetration range data is an approximation and may not be entirely accurate.") + end +end \ No newline at end of file diff --git a/lua/acf/shared/ammo_types/heatfs.lua b/lua/acf/shared/ammo_types/heatfs.lua index 67b3f6849..187d886cb 100644 --- a/lua/acf/shared/ammo_types/heatfs.lua +++ b/lua/acf/shared/ammo_types/heatfs.lua @@ -15,14 +15,14 @@ function Ammo:UpdateRoundData(ToolData, Data, GUIData) ACF.UpdateRoundSpecs(ToolData, Data, GUIData) - local MaxConeAng = math.deg(math.atan((Data.ProjLength - Data.Caliber * 0.002) / (Data.Caliber * 0.05))) + local MaxConeAng = math.deg(math.atan((Data.ProjLength - Data.Caliber * 0.02) / (Data.Caliber * 0.5))) local LinerAngle = math.Clamp(ToolData.LinerAngle, GUIData.MinConeAng, MaxConeAng) local _, ConeArea, AirVol = self:ConeCalc(LinerAngle, Data.Caliber * 0.05) local LinerRad = math.rad(LinerAngle * 0.5) - local SlugCaliber = Data.Caliber * 0.1 - Data.Caliber * (math.sin(LinerRad) * 0.5 + math.cos(LinerRad) * 1.5) * 0.05 + local SlugCaliber = Data.Caliber - Data.Caliber * (math.sin(LinerRad) * 0.5 + math.cos(LinerRad) * 1.5) * 0.5 local SlugFrArea = 3.1416 * (SlugCaliber * 0.5) ^ 2 - local ConeVol = ConeArea * Data.Caliber * 0.002 + local ConeVol = ConeArea * Data.Caliber * 0.02 local ProjMass = math.max(GUIData.ProjVolume - ToolData.FillerMass, 0) * 0.0079 + math.min(ToolData.FillerMass, GUIData.ProjVolume) * ACF.HEDensity * 0.001 + ConeVol * 0.0079 --Volume of the projectile as a cylinder - Volume of the filler - Volume of the crush cone * density of steel + Volume of the filler * density of TNT + Area of the cone * thickness * density of steel local MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, ProjMass) local Energy = ACF_Kinetic(MuzzleVel * 39.37, ProjMass, Data.LimitVel) @@ -54,10 +54,12 @@ function Ammo:UpdateRoundData(ToolData, Data, GUIData) end end -function Ammo:Network(Crate, BulletData) - Ammo.BaseClass.Network(self, Crate, BulletData) +if SERVER then + function Ammo:Network(Entity, BulletData) + Ammo.BaseClass.Network(self, Entity, BulletData) - Crate:SetNW2String("AmmoType", "HEATFS") + Entity:SetNW2String("AmmoType", "HEATFS") + end +else + ACF.RegisterAmmoDecal("HEATFS", "damage/heat_pen", "damage/heat_rico", function(Caliber) return Caliber * 0.1667 end) end - -ACF.RegisterAmmoDecal("HEATFS", "damage/heat_pen", "damage/heat_rico", function(Caliber) return Caliber * 0.1667 end) diff --git a/lua/acf/shared/ammo_types/hp.lua b/lua/acf/shared/ammo_types/hp.lua index 8ca6a1d25..b68126dda 100644 --- a/lua/acf/shared/ammo_types/hp.lua +++ b/lua/acf/shared/ammo_types/hp.lua @@ -7,6 +7,15 @@ function Ammo:OnLoaded() self.Description = "A round with a hollow cavity, meant to flatten against surfaces on impact." end +function Ammo:GetDisplayData(BulletData) + local Data = Ammo.BaseClass.GetDisplayData(self, BulletData) + local Energy = ACF_Kinetic(BulletData.MuzzleVel * 39.37, BulletData.ProjMass, BulletData.LimitVel) + + Data.MaxKETransfert = Energy.Kinetic * BulletData.ShovePower + + return Data +end + function Ammo:UpdateRoundData(ToolData, Data, GUIData) GUIData = GUIData or Data @@ -26,7 +35,7 @@ function Ammo:UpdateRoundData(ToolData, Data, GUIData) Data.ProjMass = (Data.FrArea * Data.ProjLength - HollowCavity) * 0.0079 --Volume of the projectile as a cylinder * fraction missing due to hollow point (Data5) * density of steel Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass) Data.ShovePower = 0.2 + ExpRatio * 0.5 - Data.ExpCaliber = Data.Caliber * 0.1 + ExpRatio * Data.ProjLength + Data.ExpCaliber = Data.Caliber + ExpRatio * Data.ProjLength Data.PenArea = (3.1416 * Data.ExpCaliber * 0.5) ^ 2 ^ ACF.PenAreaMod Data.DragCoef = Data.FrArea * 0.0001 / Data.ProjMass Data.CartMass = Data.PropMass + Data.ProjMass @@ -36,11 +45,7 @@ function Ammo:UpdateRoundData(ToolData, Data, GUIData) end end -function Ammo:BaseConvert(_, ToolData) - if not ToolData.Projectile then ToolData.Projectile = 0 end - if not ToolData.Propellant then ToolData.Propellant = 0 end - if not ToolData.HollowCavity then ToolData.HollowCavity = 0 end - +function Ammo:BaseConvert(ToolData) local Data, GUIData = ACF.RoundBaseGunpowder(ToolData, {}) GUIData.MinCavVol = 0 @@ -54,111 +59,119 @@ function Ammo:BaseConvert(_, ToolData) return Data, GUIData end -function Ammo:Network(Crate, BulletData) - Crate:SetNW2String("AmmoType", "HP") - Crate:SetNW2String("AmmoID", BulletData.Id) - Crate:SetNW2Float("Caliber", BulletData.Caliber) - Crate:SetNW2Float("ProjMass", BulletData.ProjMass) - Crate:SetNW2Float("PropMass", BulletData.PropMass) - Crate:SetNW2Float("ExpCaliber", BulletData.ExpCaliber) - Crate:SetNW2Float("DragCoef", BulletData.DragCoef) - Crate:SetNW2Float("MuzzleVel", BulletData.MuzzleVel) - Crate:SetNW2Float("Tracer", BulletData.Tracer) +function Ammo:VerifyData(ToolData) + Ammo.BaseClass.VerifyData(self, ToolData) + + if not ToolData.HollowCavity then + local Data5 = ToolData.RoundData5 + + ToolData.HollowCavity = Data5 and tonumber(Data5) or 0 + end end -function Ammo:GetDisplayData(BulletData) - local Data = Ammo.BaseClass.GetDisplayData(self, BulletData) - local Energy = ACF_Kinetic(BulletData.MuzzleVel * 39.37, BulletData.ProjMass, BulletData.LimitVel) +if SERVER then + ACF.AddEntityArguments("acf_ammo", "HollowCavity") -- Adding extra info to ammo crates - Data.MaxKETransfert = Energy.Kinetic * BulletData.ShovePower + function Ammo:OnLast(Entity) + Ammo.BaseClass.OnLast(self, Entity) - return Data -end + Entity.HollowCavity = nil -function Ammo:GetCrateText(BulletData) - local BaseText = Ammo.BaseClass.GetCrateText(self, BulletData) - local Data = self:GetDisplayData(BulletData) - local Text = BaseText .. "\nExpanded Caliber: %s mm\nImparted Energy: %s KJ" + -- Cleanup the leftovers aswell + Entity.RoundData5 = nil + end - return Text:format(math.Round(BulletData.ExpCaliber * 10, 2), math.Round(Data.MaxKETransfert, 2)) -end + function Ammo:Network(Entity, BulletData) + Ammo.BaseClass.Network(self, Entity, BulletData) -function Ammo:MenuAction(Menu, ToolData, Data) - local HollowCavity = Menu:AddSlider("Cavity Volume", Data.MinCavVol, Data.MaxCavVol, 2) - HollowCavity:SetDataVar("HollowCavity", "OnValueChanged") - HollowCavity:TrackDataVar("Projectile") - HollowCavity:SetValueFunction(function(Panel) - ToolData.HollowCavity = math.Round(ACF.ReadNumber("HollowCavity"), 2) + Entity:SetNW2String("AmmoType", "HP") + end - self:UpdateRoundData(ToolData, Data) + function Ammo:GetCrateText(BulletData) + local BaseText = Ammo.BaseClass.GetCrateText(self, BulletData) + local Data = self:GetDisplayData(BulletData) + local Text = BaseText .. "\nExpanded Caliber: %s mm\nImparted Energy: %s KJ" - Panel:SetMax(Data.MaxCavVol) - Panel:SetValue(Data.CavVol) + return Text:format(math.Round(BulletData.ExpCaliber * 10, 2), math.Round(Data.MaxKETransfert, 2)) + end +else + ACF.RegisterAmmoDecal("HP", "damage/ap_pen", "damage/ap_rico") - return Data.CavVol - end) + function Ammo:MenuAction(Menu, ToolData, Data) + local HollowCavity = Menu:AddSlider("Cavity Volume", Data.MinCavVol, Data.MaxCavVol, 2) + HollowCavity:SetDataVar("HollowCavity", "OnValueChanged") + HollowCavity:TrackDataVar("Projectile") + HollowCavity:SetValueFunction(function(Panel) + ToolData.HollowCavity = math.Round(ACF.ReadNumber("HollowCavity"), 2) - local Tracer = Menu:AddCheckBox("Tracer") - Tracer:SetDataVar("Tracer", "OnChange") - Tracer:SetValueFunction(function(Panel) - ToolData.Tracer = ACF.ReadBool("Tracer") + self:UpdateRoundData(ToolData, Data) - self:UpdateRoundData(ToolData, Data) + Panel:SetMax(Data.MaxCavVol) + Panel:SetValue(Data.CavVol) - ACF.WriteValue("Projectile", Data.ProjLength) - ACF.WriteValue("Propellant", Data.PropLength) + return Data.CavVol + end) - Panel:SetText("Tracer : " .. Data.Tracer .. " cm") - Panel:SetValue(ToolData.Tracer) + local Tracer = Menu:AddCheckBox("Tracer") + Tracer:SetDataVar("Tracer", "OnChange") + Tracer:SetValueFunction(function(Panel) + ToolData.Tracer = ACF.ReadBool("Tracer") - return ToolData.Tracer - end) + self:UpdateRoundData(ToolData, Data) - local RoundStats = Menu:AddLabel() - RoundStats:TrackDataVar("Projectile", "SetText") - RoundStats:TrackDataVar("Propellant") - RoundStats:TrackDataVar("HollowCavity") - RoundStats:SetValueFunction(function() - self:UpdateRoundData(ToolData, Data) + ACF.WriteValue("Projectile", Data.ProjLength) + ACF.WriteValue("Propellant", Data.PropLength) - local Text = "Muzzle Velocity : %s m/s\nProjectile Mass : %s\nPropellant Mass : %s" - local MuzzleVel = math.Round(Data.MuzzleVel * ACF.Scale, 2) - local ProjMass = ACF.GetProperMass(Data.ProjMass) - local PropMass = ACF.GetProperMass(Data.PropMass) + Panel:SetText("Tracer : " .. Data.Tracer .. " cm") + Panel:SetValue(ToolData.Tracer) - return Text:format(MuzzleVel, ProjMass, PropMass) - end) + return ToolData.Tracer + end) - local HollowStats = Menu:AddLabel() - HollowStats:TrackDataVar("Projectile", "SetText") - HollowStats:TrackDataVar("Propellant") - HollowStats:TrackDataVar("HollowCavity") - HollowStats:SetValueFunction(function() - self:UpdateRoundData(ToolData, Data) + local RoundStats = Menu:AddLabel() + RoundStats:TrackDataVar("Projectile", "SetText") + RoundStats:TrackDataVar("Propellant") + RoundStats:TrackDataVar("HollowCavity") + RoundStats:SetValueFunction(function() + self:UpdateRoundData(ToolData, Data) - local Text = "Expanded Caliber : %s mm\nTransfered Energy : %s KJ" - local Caliber = math.Round(Data.ExpCaliber * 10, 2) - local Energy = math.Round(Data.MaxKETransfert, 2) + local Text = "Muzzle Velocity : %s m/s\nProjectile Mass : %s\nPropellant Mass : %s" + local MuzzleVel = math.Round(Data.MuzzleVel * ACF.Scale, 2) + local ProjMass = ACF.GetProperMass(Data.ProjMass) + local PropMass = ACF.GetProperMass(Data.PropMass) - return Text:format(Caliber, Energy) - end) + return Text:format(MuzzleVel, ProjMass, PropMass) + end) - local PenStats = Menu:AddLabel() - PenStats:TrackDataVar("Projectile", "SetText") - PenStats:TrackDataVar("Propellant") - PenStats:TrackDataVar("HollowCavity") - PenStats:SetValueFunction(function() - self:UpdateRoundData(ToolData, Data) + local HollowStats = Menu:AddLabel() + HollowStats:TrackDataVar("Projectile", "SetText") + HollowStats:TrackDataVar("Propellant") + HollowStats:TrackDataVar("HollowCavity") + HollowStats:SetValueFunction(function() + self:UpdateRoundData(ToolData, Data) - local Text = "Penetration : %s mm RHA\nAt 300m : %s mm RHA @ %s m/s\nAt 800m : %s mm RHA @ %s m/s" - local MaxPen = math.Round(Data.MaxPen, 2) - local R1V, R1P = ACF.PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 300) - local R2V, R2P = ACF.PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 800) + local Text = "Expanded Caliber : %s mm\nTransfered Energy : %s KJ" + local Caliber = math.Round(Data.ExpCaliber * 10, 2) + local Energy = math.Round(Data.MaxKETransfert, 2) - return Text:format(MaxPen, R1P, R1V, R2P, R2V) - end) + return Text:format(Caliber, Energy) + end) - Menu:AddLabel("Note: The penetration range data is an approximation and may not be entirely accurate.") -end + local PenStats = Menu:AddLabel() + PenStats:TrackDataVar("Projectile", "SetText") + PenStats:TrackDataVar("Propellant") + PenStats:TrackDataVar("HollowCavity") + PenStats:SetValueFunction(function() + self:UpdateRoundData(ToolData, Data) -ACF.RegisterAmmoDecal("HP", "damage/ap_pen", "damage/ap_rico") + local Text = "Penetration : %s mm RHA\nAt 300m : %s mm RHA @ %s m/s\nAt 800m : %s mm RHA @ %s m/s" + local MaxPen = math.Round(Data.MaxPen, 2) + local R1V, R1P = ACF.PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 300) + local R2V, R2P = ACF.PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 800) + + return Text:format(MaxPen, R1P, R1V, R2P, R2V) + end) + + Menu:AddLabel("Note: The penetration range data is an approximation and may not be entirely accurate.") + end +end \ No newline at end of file diff --git a/lua/acf/shared/ammo_types/refill.lua b/lua/acf/shared/ammo_types/refill.lua index 94592a0a9..56ff00213 100644 --- a/lua/acf/shared/ammo_types/refill.lua +++ b/lua/acf/shared/ammo_types/refill.lua @@ -7,17 +7,22 @@ function Ammo:OnLoaded() self.SupressDefaultMenu = true end -function Ammo:BaseConvert(_, ToolData) - local Class = ACF.Classes.Weapons[ToolData.WeaponClass] - local Weapon = Class and Class.Items[ToolData.Weapon] +function Ammo:GetDisplayData() + return {} +end + +function Ammo:BaseConvert(ToolData) + local ProjMass = 5.5 * 0.079 --Volume of the projectile as a cylinder * streamline factor (Data5) * density of steel + local PropMass = 0.001 --Volume of the case as a cylinder * Powder density converted from g to kg return { - Id = ToolData.Weapon, - Type = ToolData.Ammo, - Caliber = Weapon and Weapon.Caliber or 12.7, - ProjMass = 5.5 * 0.079, --Volume of the projectile as a cylinder * streamline factor (Data5) * density of steel - PropMass = 5.5 * ACF.PDensity * 0.001, --Volume of the case as a cylinder * Powder density converted from g to kg - FillerMass = 0, + Id = "12.7mmMG", + Type = ToolData.AmmoType, + Caliber = 12.7, + ProjMass = ProjMass, + PropMass = PropMass, + CartMass = ProjMass + PropMass, + FillerMass = 0.001, DragCoef = 0, Tracer = 0, MuzzleVel = 0, @@ -25,25 +30,127 @@ function Ammo:BaseConvert(_, ToolData) } end -function Ammo:Network(Crate, BulletData) - Crate:SetNW2String("AmmoType", "Refill") - Crate:SetNW2String("AmmoID", BulletData.Id) - Crate:SetNW2Float("Caliber", BulletData.Caliber) - Crate:SetNW2Float("ProjMass", BulletData.ProjMass) - Crate:SetNW2Float("FillerMass", BulletData.FillerMass) - Crate:SetNW2Float("PropMass", BulletData.PropMass) - Crate:SetNW2Float("DragCoef", BulletData.DragCoef) - Crate:SetNW2Float("MuzzleVel", BulletData.MuzzleVel) - Crate:SetNW2Float("Tracer", BulletData.Tracer) +function Ammo:VerifyData() end -function Ammo:GetDisplayData() - return {} -end +if SERVER then + util.AddNetworkString("ACF_RefillEffect") + util.AddNetworkString("ACF_StopRefillEffect") -function Ammo:GetCrateText() - return "" -end + local MaxDistance = ACF.RefillDistance * ACF.RefillDistance + local ActiveCrates = ACF.AmmoCrates + + local function CanRefillCrate(Refill, Crate, Distance) + if Refill == Crate then return false end + if not Refill:CanConsume() then return false end + if Crate.IsRefill then return false end + if Crate.Ammo >= Crate.Capacity then return false end + if Crate.Disabled then return false end + if Crate.Damaged then return false end + + return Distance <= MaxDistance + end + + local function RefillEffect(Entity) + net.Start("ACF_RefillEffect") + net.WriteEntity(Entity) + net.Broadcast() + end + + local function StopRefillEffect(Entity) + net.Start("ACF_StopRefillEffect") + net.WriteEntity(Entity) + net.Broadcast() + end + + local function RefillCrates(Refill) + local Position = Refill:GetPos() + + for Crate in pairs(ActiveCrates) do + local Distance = Position:DistToSqr(Crate:GetPos()) + + if CanRefillCrate(Refill, Crate, Distance) then + local Supply = math.ceil(ACF.RefillSpeed / Crate.BulletData.CartMass / Distance ^ 0.5) + local Transfer = math.min(Supply, Refill.Ammo, Crate.Capacity - Crate.Ammo) + + if hook.Run("ACF_CanRefill", Refill, Crate, Transfer) == false then continue end + + if not next(Refill.SupplyingTo) then + RefillEffect(Refill) + end + + if not Refill.SupplyingTo[Crate] then + Refill.SupplyingTo[Crate] = true + + Crate:CallOnRemove("ACF Refill " .. Refill:EntIndex(), function() + Refill.SupplyingTo[Crate] = nil + end) + end + + Crate:Consume(-Transfer) + Refill:Consume(Transfer) + + Crate:EmitSound("items/ammo_pickup.wav", 350, 100, 0.5) + Refill:EmitSound("items/ammo_pickup.wav", 350, 100, 0.5) + + elseif Refill.SupplyingTo[Crate] then + Refill.SupplyingTo[Crate] = nil + + Crate:RemoveCallOnRemove("ACF Refill " .. Refill:EntIndex()) + + if not next(Refill.SupplyingTo) then + StopRefillEffect(Refill) + end + end + end + end + + function Ammo:OnFirst(Entity) + if not Entity.SupplyingTo then + Entity.SupplyingTo = {} + end + + Entity.IsRefill = true + + timer.Create("ACF Refill " .. Entity:EntIndex(), 1, 0, function() + if not IsValid(Entity) then return end + + RefillCrates(Entity) + end) + end + + function Ammo:OnLast(Entity) + local CallName = "ACF Refill " .. Entity:EntIndex() + + for Crate in pairs(Entity.SupplyingTo) do + Crate:RemoveCallOnRemove(CallName) + end + + Entity.SupplyingTo = nil + Entity.IsRefill = nil + + Entity:SetNW2Float("FillerMass", 0) + + StopRefillEffect(Refill) + + timer.Remove(CallName) + end + + function Ammo:Network(Entity, BulletData) + Ammo.BaseClass.Network(self, Entity, BulletData) + + Entity:SetNW2String("AmmoType", "Refill") + Entity:SetNW2Float("FillerMass", BulletData.FillerMass) + end + + function Ammo:GetCrateName() + return "Ammo Refill", "Refill", "Ammo Refill Crate" + end -function Ammo:MenuAction() + function Ammo:GetCrateText() + return "" + end +else + function Ammo:MenuAction() + end end diff --git a/lua/acf/shared/ammo_types/smoke.lua b/lua/acf/shared/ammo_types/smoke.lua index a7afa348b..52bfb73e3 100644 --- a/lua/acf/shared/ammo_types/smoke.lua +++ b/lua/acf/shared/ammo_types/smoke.lua @@ -16,6 +16,22 @@ function Ammo:OnLoaded() } end +function Ammo:GetDisplayData(Data) + local SMFiller = math.min(math.log(1 + Data.FillerMass * 8 * 39.37) * 43.4216, 350) + local WPFiller = math.min(math.log(1 + Data.WPMass * 8 * 39.37) * 43.4216, 350) + + return { + SMFiller = SMFiller, + SMLife = math.Round(20 + SMFiller * 0.25, 2), + SMRadiusMin = math.Round(SMFiller * 1.25 * 0.15 * 0.0254, 2), + SMRadiusMax = math.Round(SMFiller * 1.25 * 2 * 0.0254, 2), + WPFiller = WPFiller, + WPLife = math.Round(6 + WPFiller * 0.1, 2), + WPRadiusMin = math.Round(WPFiller * 1.25 * 0.0254, 2), + WPRadiusMax = math.Round(WPFiller * 1.25 * 2 * 0.0254, 2), + } +end + function Ammo:UpdateRoundData(ToolData, Data, GUIData) GUIData = GUIData or Data @@ -42,7 +58,6 @@ function Ammo:UpdateRoundData(ToolData, Data, GUIData) GUIData.FillerVol = math.Round(SmokeFiller, 2) GUIData.WPVol = math.Round(WPFiller, 2) - Data.FuseLength = math.Clamp(ToolData.FuzeLength, GUIData.MinFuzeTime, GUIData.MaxFuzeTime) Data.FillerMass = GUIData.FillerVol * ACF.HEDensity * 0.0005 Data.WPMass = GUIData.WPVol * ACF.HEDensity * 0.0005 Data.ProjMass = math.max(GUIData.ProjVolume - (GUIData.FillerVol + GUIData.WPVol), 0) * 0.0079 + Data.FillerMass + Data.WPMass @@ -55,17 +70,9 @@ function Ammo:UpdateRoundData(ToolData, Data, GUIData) end end -function Ammo:BaseConvert(_, ToolData) - if not ToolData.Projectile then ToolData.Projectile = 0 end - if not ToolData.Propellant then ToolData.Propellant = 0 end - if not ToolData.SmokeFiller then ToolData.SmokeFiller = 0 end - if not ToolData.WPFiller then ToolData.WPFiller = 0 end - if not ToolData.FuzeLength then ToolData.FuzeLength = 0 end - +function Ammo:BaseConvert(ToolData) local Data, GUIData = ACF.RoundBaseGunpowder(ToolData, {}) - GUIData.MinFuzeTime = 0 - GUIData.MaxFuzeTime = 1 GUIData.MinFillerVol = 0 Data.ShovePower = 0.1 @@ -81,196 +88,197 @@ function Ammo:BaseConvert(_, ToolData) return Data, GUIData end -function Ammo:Network(Crate, BulletData) - Crate:SetNW2String("AmmoType", "SM") - Crate:SetNW2String("AmmoID", BulletData.Id) - Crate:SetNW2Float("Caliber", BulletData.Caliber) - Crate:SetNW2Float("ProjMass", BulletData.ProjMass) - Crate:SetNW2Float("FillerMass", BulletData.FillerMass) - Crate:SetNW2Float("WPMass", BulletData.WPMass) - Crate:SetNW2Float("PropMass", BulletData.PropMass) - Crate:SetNW2Float("DragCoef", BulletData.DragCoef) - Crate:SetNW2Float("MuzzleVel", BulletData.MuzzleVel) - Crate:SetNW2Float("Tracer", BulletData.Tracer) -end +function Ammo:VerifyData(ToolData) + Ammo.BaseClass.VerifyData(self, ToolData) -function Ammo:GetDisplayData(Data) - local SMFiller = math.min(math.log(1 + Data.FillerMass * 8 * 39.37) * 43.4216, 350) - local WPFiller = math.min(math.log(1 + Data.WPMass * 8 * 39.37) * 43.4216, 350) + if not ToolData.SmokeFiller then + local Data5 = ToolData.RoundData5 - return { - SMFiller = SMFiller, - SMLife = math.Round(20 + SMFiller * 0.25, 2), - SMRadiusMin = math.Round(SMFiller * 1.25 * 0.15 * 0.0254, 2), - SMRadiusMax = math.Round(SMFiller * 1.25 * 2 * 0.0254, 2), - WPFiller = WPFiller, - WPLife = math.Round(6 + WPFiller * 0.1, 2), - WPRadiusMin = math.Round(WPFiller * 1.25 * 0.0254, 2), - WPRadiusMax = math.Round(WPFiller * 1.25 * 2 * 0.0254, 2), - } + ToolData.SmokeFiller = Data5 and tonumber(Data5) or 0 + end + + if not ToolData.WPFiller then + local Data6 = ToolData.RoundData6 + + ToolData.WPFiller = Data6 and tonumber(Data6) or 0 + end end -function Ammo:GetCrateText(BulletData) - local Text = "Muzzle Velocity: %s m/s%s%s" - local Data = self:GetDisplayData(BulletData) - local WPText, SMText = "", "" +if SERVER then + ACF.AddEntityArguments("acf_ammo", "SmokeFiller", "WPFiller") -- Adding extra info to ammo crates + + function Ammo:OnLast(Entity) + Ammo.BaseClass.OnLast(self, Entity) + Entity.SmokeFiller = nil + Entity.WPFiller = nil - if Data.WPFiller > 0 then - local Template = "\nWP Radius: %s m to %s m\nWP Lifetime: %s s" + -- Cleanup the leftovers aswell + Entity.RoundData5 = nil + Entity.RoundData6 = nil - WPText = Template:format(Data.WPRadiusMin, Data.WPRadiusMax, Data.WPLife) + Entity:SetNW2Float("FillerMass", 0) + Entity:SetNW2Float("WPMass", 0) end - if Data.SMFiller > 0 then - local Template = "\nSM Radius: %s m to %s m\nSM Lifetime: %s s" + function Ammo:Network(Entity, BulletData) + Ammo.BaseClass.Network(self, Entity, BulletData) - SMText = Template:format(Data.SMRadiusMin, Data.SMRadiusMax, Data.SMLife) + Entity:SetNW2String("AmmoType", "SM") + Entity:SetNW2Float("FillerMass", BulletData.FillerMass) + Entity:SetNW2Float("WPMass", BulletData.WPMass) end - return Text:format(math.Round(BulletData.MuzzleVel, 2), WPText, SMText) -end - -function Ammo:PropImpact(_, Bullet, Target, HitNormal, HitPos, Bone) - if ACF_Check(Target) then - local Speed = Bullet.Flight:Length() / ACF.Scale - local Energy = ACF_Kinetic(Speed, Bullet.ProjMass - (Bullet.FillerMass + Bullet.WPMass), Bullet.LimitVel) - local HitRes = ACF_RoundImpact(Bullet, Speed, Energy, Target, HitPos, HitNormal, Bone) + function Ammo:GetCrateText(BulletData) + local Text = "Muzzle Velocity: %s m/s%s%s" + local Data = self:GetDisplayData(BulletData) + local WPText, SMText = "", "" - if HitRes.Ricochet then return "Ricochet" end - end - return false -end + if Data.WPFiller > 0 then + local Template = "\nWP Radius: %s m to %s m\nWP Lifetime: %s s" -function Ammo:WorldImpact() - return false -end + WPText = Template:format(Data.WPRadiusMin, Data.WPRadiusMax, Data.WPLife) + end -function Ammo:ImpactEffect(_, Bullet) - local Crate = Bullet.Crate - local Color = IsValid(Crate) and Crate:GetColor() or Color(255, 255, 255) + if Data.SMFiller > 0 then + local Template = "\nSM Radius: %s m to %s m\nSM Lifetime: %s s" - local Effect = EffectData() - Effect:SetOrigin(Bullet.SimPos) - Effect:SetNormal(Bullet.SimFlight:GetNormalized()) - Effect:SetScale(math.max(Bullet.FillerMass * 8 * 39.37, 0)) - Effect:SetMagnitude(math.max(Bullet.WPMass * 8 * 39.37, 0)) - Effect:SetStart(Vector(Color.r, Color.g, Color.b)) - Effect:SetRadius(Bullet.Caliber) + SMText = Template:format(Data.SMRadiusMin, Data.SMRadiusMax, Data.SMLife) + end - util.Effect("ACF_Smoke", Effect) -end + return Text:format(math.Round(BulletData.MuzzleVel, 2), WPText, SMText) + end -function Ammo:MenuAction(Menu, ToolData, Data) - local SmokeFiller = Menu:AddSlider("Smoke Filler", Data.MinFillerVol, Data.MaxFillerVol, 2) - SmokeFiller:SetDataVar("SmokeFiller", "OnValueChanged") - SmokeFiller:TrackDataVar("Projectile") - SmokeFiller:TrackDataVar("WPFiller") - SmokeFiller:SetValueFunction(function(Panel, IsTracked) - ToolData.SmokeFiller = math.Round(ACF.ReadNumber("SmokeFiller"), 2) + function Ammo:PropImpact(_, Bullet, Target, HitNormal, HitPos, Bone) + if ACF_Check(Target) then + local Speed = Bullet.Flight:Length() / ACF.Scale + local Energy = ACF_Kinetic(Speed, Bullet.ProjMass - (Bullet.FillerMass + Bullet.WPMass), Bullet.LimitVel) + local HitRes = ACF_RoundImpact(Bullet, Speed, Energy, Target, HitPos, HitNormal, Bone) - if not IsTracked then - Data.FillerPriority = "Smoke" + if HitRes.Ricochet then return "Ricochet" end end - self:UpdateRoundData(ToolData, Data) + return false + end - Panel:SetMax(Data.MaxFillerVol) - Panel:SetValue(Data.FillerVol) + function Ammo:WorldImpact() + return false + end +else + ACF.RegisterAmmoDecal("SM", "damage/he_pen", "damage/he_rico") + + function Ammo:ImpactEffect(_, Bullet) + local Crate = Bullet.Crate + local Color = IsValid(Crate) and Crate:GetColor() or Color(255, 255, 255) + + local Effect = EffectData() + Effect:SetOrigin(Bullet.SimPos) + Effect:SetNormal(Bullet.SimFlight:GetNormalized()) + Effect:SetScale(math.max(Bullet.FillerMass * 8 * 39.37, 0)) + Effect:SetMagnitude(math.max(Bullet.WPMass * 8 * 39.37, 0)) + Effect:SetStart(Vector(Color.r, Color.g, Color.b)) + Effect:SetRadius(Bullet.Caliber) + + util.Effect("ACF_Smoke", Effect) + end - return Data.FillerVol - end) + function Ammo:MenuAction(Menu, ToolData, Data) + local SmokeFiller = Menu:AddSlider("Smoke Filler", Data.MinFillerVol, Data.MaxFillerVol, 2) + SmokeFiller:SetDataVar("SmokeFiller", "OnValueChanged") + SmokeFiller:TrackDataVar("Projectile") + SmokeFiller:TrackDataVar("WPFiller") + SmokeFiller:SetValueFunction(function(Panel, IsTracked) + ToolData.SmokeFiller = math.Round(ACF.ReadNumber("SmokeFiller"), 2) - local WPFiller = Menu:AddSlider("WP Filler", Data.MinFillerVol, Data.MaxFillerVol, 2) - WPFiller:SetDataVar("WPFiller", "OnValueChanged") - WPFiller:TrackDataVar("SmokeFiller") - WPFiller:TrackDataVar("Projectile") - WPFiller:SetValueFunction(function(Panel, IsTracked) - ToolData.WPFiller = math.Round(ACF.ReadNumber("WPFiller"), 2) + if not IsTracked then + Data.FillerPriority = "Smoke" + end - if not IsTracked then - Data.FillerPriority = "WP" - end + self:UpdateRoundData(ToolData, Data) - self:UpdateRoundData(ToolData, Data) + Panel:SetMax(Data.MaxFillerVol) + Panel:SetValue(Data.FillerVol) - Panel:SetMax(Data.MaxFillerVol) - Panel:SetValue(Data.WPVol) + return Data.FillerVol + end) - return Data.WPVol - end) + local WPFiller = Menu:AddSlider("WP Filler", Data.MinFillerVol, Data.MaxFillerVol, 2) + WPFiller:SetDataVar("WPFiller", "OnValueChanged") + WPFiller:TrackDataVar("SmokeFiller") + WPFiller:TrackDataVar("Projectile") + WPFiller:SetValueFunction(function(Panel, IsTracked) + ToolData.WPFiller = math.Round(ACF.ReadNumber("WPFiller"), 2) - local FuzeLength = Menu:AddSlider("Fuze Delay", Data.MinFuzeTime, Data.MaxFuzeTime, 2) - FuzeLength:SetDataVar("FuzeLength", "OnValueChanged") - FuzeLength:SetValueFunction(function(Panel) - ToolData.FuzeLength = math.Round(ACF.ReadNumber("FuzeLength"), 2) + if not IsTracked then + Data.FillerPriority = "WP" + end - self:UpdateRoundData(ToolData, Data) + self:UpdateRoundData(ToolData, Data) - Panel:SetValue(Data.FuseLength) + Panel:SetMax(Data.MaxFillerVol) + Panel:SetValue(Data.WPVol) - return Data.FuseLength - end) + return Data.WPVol + end) - local Tracer = Menu:AddCheckBox("Tracer") - Tracer:SetDataVar("Tracer", "OnChange") - Tracer:SetValueFunction(function(Panel) - ToolData.Tracer = ACF.ReadBool("Tracer") + local Tracer = Menu:AddCheckBox("Tracer") + Tracer:SetDataVar("Tracer", "OnChange") + Tracer:SetValueFunction(function(Panel) + ToolData.Tracer = ACF.ReadBool("Tracer") - self:UpdateRoundData(ToolData, Data) + self:UpdateRoundData(ToolData, Data) - ACF.WriteValue("Projectile", Data.ProjLength) - ACF.WriteValue("Propellant", Data.PropLength) + ACF.WriteValue("Projectile", Data.ProjLength) + ACF.WriteValue("Propellant", Data.PropLength) - Panel:SetText("Tracer : " .. Data.Tracer .. " cm") - Panel:SetValue(ToolData.Tracer) + Panel:SetText("Tracer : " .. Data.Tracer .. " cm") + Panel:SetValue(ToolData.Tracer) - return ToolData.Tracer - end) + return ToolData.Tracer + end) - local RoundStats = Menu:AddLabel() - RoundStats:TrackDataVar("Projectile", "SetText") - RoundStats:TrackDataVar("Propellant") - RoundStats:TrackDataVar("SmokeFiller") - RoundStats:TrackDataVar("WPFiller") - RoundStats:SetValueFunction(function() - self:UpdateRoundData(ToolData, Data) + local RoundStats = Menu:AddLabel() + RoundStats:TrackDataVar("Projectile", "SetText") + RoundStats:TrackDataVar("Propellant") + RoundStats:TrackDataVar("SmokeFiller") + RoundStats:TrackDataVar("WPFiller") + RoundStats:SetValueFunction(function() + self:UpdateRoundData(ToolData, Data) - local Text = "Muzzle Velocity : %s m/s\nProjectile Mass : %s\nPropellant Mass : %s" - local MuzzleVel = math.Round(Data.MuzzleVel * ACF.Scale, 2) - local ProjMass = ACF.GetProperMass(Data.ProjMass) - local PropMass = ACF.GetProperMass(Data.PropMass) + local Text = "Muzzle Velocity : %s m/s\nProjectile Mass : %s\nPropellant Mass : %s" + local MuzzleVel = math.Round(Data.MuzzleVel * ACF.Scale, 2) + local ProjMass = ACF.GetProperMass(Data.ProjMass) + local PropMass = ACF.GetProperMass(Data.PropMass) - return Text:format(MuzzleVel, ProjMass, PropMass) - end) + return Text:format(MuzzleVel, ProjMass, PropMass) + end) - local SmokeStats = Menu:AddLabel() - SmokeStats:TrackDataVar("SmokeFiller", "SetText") - SmokeStats:TrackDataVar("WPFiller") - SmokeStats:SetValueFunction(function() - self:UpdateRoundData(ToolData, Data) + local SmokeStats = Menu:AddLabel() + SmokeStats:TrackDataVar("SmokeFiller", "SetText") + SmokeStats:TrackDataVar("WPFiller") + SmokeStats:SetValueFunction(function() + self:UpdateRoundData(ToolData, Data) - local SMText, WPText = "", "" + local SMText, WPText = "", "" - if Data.FillerMass > 0 then - local Text = "Smoke Filler Mass : %s\nSmoke Filler Radius : %s m\nSmoke Filler Life : %s s\n" - local SmokeMass = ACF.GetProperMass(Data.FillerMass) - local SmokeRadius = (Data.SMRadiusMin + Data.SMRadiusMax) * 0.5 + if Data.FillerMass > 0 then + local Text = "Smoke Filler Mass : %s\nSmoke Filler Radius : %s m\nSmoke Filler Life : %s s\n" + local SmokeMass = ACF.GetProperMass(Data.FillerMass) + local SmokeRadius = (Data.SMRadiusMin + Data.SMRadiusMax) * 0.5 - SMText = Text:format(SmokeMass, SmokeRadius, Data.SMLife) - end + SMText = Text:format(SmokeMass, SmokeRadius, Data.SMLife) + end - if Data.WPMass > 0 then - local Text = "WP Filler Mass : %s\nWP Filler Radius : %s m\nWP Filler Life : %s s" - local WPMass = ACF.GetProperMass(Data.WPMass) - local WPRadius = (Data.WPRadiusMin + Data.WPRadiusMax) * 0.5 + if Data.WPMass > 0 then + local Text = "WP Filler Mass : %s\nWP Filler Radius : %s m\nWP Filler Life : %s s" + local WPMass = ACF.GetProperMass(Data.WPMass) + local WPRadius = (Data.WPRadiusMin + Data.WPRadiusMax) * 0.5 - WPText = Text:format(WPMass, WPRadius, Data.WPLife) - end + WPText = Text:format(WPMass, WPRadius, Data.WPLife) + end - return SMText .. WPText - end) + return SMText .. WPText + end) + end end - -ACF.RegisterAmmoDecal("SM", "damage/he_pen", "damage/he_rico") diff --git a/lua/acf/shared/guns/grenadelauncher.lua b/lua/acf/shared/guns/grenadelauncher.lua index 78102de28..b2cc0e331 100644 --- a/lua/acf/shared/guns/grenadelauncher.lua +++ b/lua/acf/shared/guns/grenadelauncher.lua @@ -22,6 +22,7 @@ ACF_defineGun("40mmGL", { --id magreload = 7.5, year = 1970, Cyclic = 200, + IsBoxed = true, round = { maxlength = 7.5, propweight = 0.01 @@ -34,6 +35,7 @@ ACF.RegisterWeaponClass("GL", { MuzzleFlash = "gl_muzzleflash_noscale", Spread = 0.28, Sound = "acf_base/weapons/grenadelauncher.mp3", + IsBoxed = true, Caliber = { Min = 25, Max = 40, diff --git a/lua/acf/shared/guns/heavymachinegun.lua b/lua/acf/shared/guns/heavymachinegun.lua index 2fba203f6..805af9332 100644 --- a/lua/acf/shared/guns/heavymachinegun.lua +++ b/lua/acf/shared/guns/heavymachinegun.lua @@ -28,6 +28,7 @@ ACF_defineGun("13mmHMG", { magsize = 35, magreload = 6, Cyclic = 550, + IsBoxed = true, round = { maxlength = 22, propweight = 0.09 @@ -46,6 +47,7 @@ ACF_defineGun("20mmHMG", { magsize = 30, magreload = 6, Cyclic = 525, + IsBoxed = true, round = { maxlength = 30, propweight = 0.12 @@ -64,6 +66,7 @@ ACF_defineGun("30mmHMG", { magsize = 25, magreload = 6, Cyclic = 500, + IsBoxed = true, round = { maxlength = 37, propweight = 0.35 @@ -82,6 +85,7 @@ ACF_defineGun("40mmHMG", { magsize = 20, magreload = 8, Cyclic = 475, + IsBoxed = true, round = { maxlength = 42, propweight = 0.9 diff --git a/lua/acf/shared/guns/machinegun.lua b/lua/acf/shared/guns/machinegun.lua index 181862cb7..e14ce475f 100644 --- a/lua/acf/shared/guns/machinegun.lua +++ b/lua/acf/shared/guns/machinegun.lua @@ -24,6 +24,7 @@ ACF_defineGun("7.62mmMG", { magsize = 250, magreload = 6, -- Time to reload in seconds Cyclic = 700, -- Rounds per minute + IsBoxed = true, round = { maxlength = 13, propweight = 0.04 @@ -42,6 +43,7 @@ ACF_defineGun("12.7mmMG", { magsize = 150, magreload = 6, Cyclic = 600, + IsBoxed = true, round = { maxlength = 15.8, propweight = 0.03 @@ -60,6 +62,7 @@ ACF_defineGun("14.5mmMG", { magsize = 90, magreload = 5, Cyclic = 500, + IsBoxed = true, round = { maxlength = 19.5, propweight = 0.04 @@ -72,6 +75,7 @@ ACF.RegisterWeaponClass("MG", { MuzzleFlash = "mg_muzzleflash_noscale", Spread = 0.16, Sound = "acf_base/weapons/mg_fire4.mp3", + IsBoxed = true, Caliber = { Min = 5.56, Max = 14.5, diff --git a/lua/acf/shared/guns/mortar.lua b/lua/acf/shared/guns/mortar.lua index bb4a689c0..67e081217 100644 --- a/lua/acf/shared/guns/mortar.lua +++ b/lua/acf/shared/guns/mortar.lua @@ -107,7 +107,7 @@ ACF.RegisterWeaponClass("MO", { Sound = "acf_base/weapons/mortar_new.mp3", Caliber = { Min = 37, - Max = 150, + Max = 280, }, }) diff --git a/lua/acf/shared/guns/rotaryautocannon.lua b/lua/acf/shared/guns/rotaryautocannon.lua index 3655428b9..a84a53910 100644 --- a/lua/acf/shared/guns/rotaryautocannon.lua +++ b/lua/acf/shared/guns/rotaryautocannon.lua @@ -73,7 +73,7 @@ ACF.RegisterWeaponClass("RAC", { Sound = "acf_base/weapons/mg_fire3.mp3", Caliber = { Min = 7.62, - Max = 30, + Max = 37, }, }) diff --git a/lua/acf/shared/guns/semiauto.lua b/lua/acf/shared/guns/semiauto.lua index 8fceb0aca..fe328c287 100644 --- a/lua/acf/shared/guns/semiauto.lua +++ b/lua/acf/shared/guns/semiauto.lua @@ -24,6 +24,7 @@ ACF_defineGun("25mmSA", { magsize = 5, magreload = 2.5, Cyclic = 300, + IsBoxed = true, round = { maxlength = 39, propweight = 0.5 @@ -42,6 +43,7 @@ ACF_defineGun("37mmSA", { magsize = 5, magreload = 3.7, Cyclic = 250, + IsBoxed = true, round = { maxlength = 42, propweight = 1.125 @@ -60,6 +62,7 @@ ACF_defineGun("45mmSA", { magsize = 5, magreload = 4.5, Cyclic = 225, + IsBoxed = true, round = { maxlength = 52, propweight = 1.8 @@ -78,6 +81,7 @@ ACF_defineGun("57mmSA", { magsize = 5, magreload = 5.7, Cyclic = 200, + IsBoxed = true, round = { maxlength = 62, propweight = 2 @@ -96,6 +100,7 @@ ACF_defineGun("76mmSA", { magsize = 5, magreload = 7.6, Cyclic = 150, + IsBoxed = true, round = { maxlength = 70, propweight = 4.75 @@ -108,6 +113,7 @@ ACF.RegisterWeaponClass("SA", { MuzzleFlash = "semi_muzzleflash_noscale", Spread = 0.12, Sound = "acf_base/weapons/sa_fire1.mp3", + IsBoxed = true, Caliber = { Min = 20, Max = 76, diff --git a/lua/acf/shared/guns/smokelauncher.lua b/lua/acf/shared/guns/smokelauncher.lua index d196dcc77..d0c1d5fba 100644 --- a/lua/acf/shared/guns/smokelauncher.lua +++ b/lua/acf/shared/guns/smokelauncher.lua @@ -24,6 +24,7 @@ ACF_defineGun("40mmSL", { magsize = 1, magreload = 30, Cyclic = 1, + IsBoxed = true, round = { maxlength = 17.5, propweight = 0.000075 @@ -45,6 +46,7 @@ ACF_defineGun("40mmCL", { magreload = 40, Cyclic = 200, year = 1950, + IsBoxed = true, round = { maxlength = 12, propweight = 0.001 @@ -57,6 +59,7 @@ ACF.RegisterWeaponClass("SL", { MuzzleFlash = "gl_muzzleflash_noscale", Spread = 0.32, Sound = "acf_base/weapons/smoke_launch.mp3", + IsBoxed = true, LimitConVar = { Name = "_acf_smokelauncher", Amount = 10, diff --git a/lua/acf/shared/hitboxes.lua b/lua/acf/shared/hitboxes.lua index ce96977c7..f6675a5b9 100644 --- a/lua/acf/shared/hitboxes.lua +++ b/lua/acf/shared/hitboxes.lua @@ -151,7 +151,6 @@ local AnimLookup = { -- defaults to Passenger, catchall for any wierd fucking an ["default"] = "Passenger" } -local function switch(cases,arg) local Var = (cases[arg] or cases["default"]) return Var end hook.Add("PlayerEnteredVehicle","ACF_HitboxUpdate",function(ply,ent) timer.Simple(3,function() -- 3 seconds is a safe amount of time for all of the seats (including those stupid fucking PHX ones that take 3 years to move the camera) to get the camera into position if IsValid(ply) and IsValid(ent) and ply:GetVehicle() == ent then diff --git a/lua/acf/shared/rounds/acf_roundfunctions.lua b/lua/acf/shared/rounds/acf_roundfunctions.lua index e810432b0..24eac7d26 100644 --- a/lua/acf/shared/rounds/acf_roundfunctions.lua +++ b/lua/acf/shared/rounds/acf_roundfunctions.lua @@ -21,8 +21,8 @@ function ACF_RoundBaseGunpowder(PlayerData, Data, ServerData, GUIData) Data.ProjLength = math.Clamp(PlayerData.ProjLength * Ratio, GUIData.MinProjLength, GUIData.MaxProjLength) Data.PropLength = math.Clamp(PlayerData.PropLength * Ratio, GUIData.MinPropLength, GUIData.MaxPropLength) - Data.PropMass = Data.FrArea * (Data.PropLength * ACF.PDensity / 1000) --Volume of the case as a cylinder * Powder density converted from g to kg - Data.RoundVolume = Data.FrArea * (Data.ProjLength + Data.PropLength) + Data.PropMass = Data.FrArea * (ACF.AmmoCaseScale ^ 2) * (Data.PropLength * ACF.PDensity / 1000) --Volume of the case as a cylinder * Powder density converted from g to kg + Data.RoundVolume = Data.FrArea * ACF.AmmoCaseScale ^ 2 * (Data.ProjLength + Data.PropLength) GUIData.ProjVolume = Data.FrArea * Data.ProjLength diff --git a/lua/acf/shared/rounds/heat.lua b/lua/acf/shared/rounds/heat.lua index c186e0464..ec08386b2 100644 --- a/lua/acf/shared/rounds/heat.lua +++ b/lua/acf/shared/rounds/heat.lua @@ -181,7 +181,6 @@ function Round.detonate(_, Bullet, HitPos) Bullet.Detonated = true Bullet.InitTime = SysTime() Bullet.Flight = Bullet.Flight + Bullet.Flight:GetNormalized() * Round.CalcSlugMV(Bullet, HEATFillerMass) * 39.37 - Bullet.FuseLength = 0.005 + 40 / (Bullet.Flight:Length() * 0.0254) Bullet.Pos = HitPos Bullet.DragCoef = Bullet.SlugDragCoef Bullet.ProjMass = Bullet.SlugMass * (1 - Crushed) diff --git a/lua/acf/shared/rounds/heatfs.lua b/lua/acf/shared/rounds/heatfs.lua index 6293698d6..44d7483b3 100644 --- a/lua/acf/shared/rounds/heatfs.lua +++ b/lua/acf/shared/rounds/heatfs.lua @@ -201,7 +201,6 @@ function Round.detonate(_, Bullet, HitPos) Bullet.Detonated = true Bullet.InitTime = SysTime() Bullet.Flight = Bullet.Flight + Bullet.Flight:GetNormalized() * Round.CalcSlugMV(Bullet, HEATFillerMass) * 39.37 - Bullet.FuseLength = 0.005 + 40 / (Bullet.Flight:Length() * 0.0254) Bullet.Pos = HitPos Bullet.DragCoef = Bullet.SlugDragCoef Bullet.ProjMass = Bullet.SlugMass * (1 - Crushed) diff --git a/lua/acf/shared/rounds/refill.lua b/lua/acf/shared/rounds/refill.lua index 293bf69fb..8994f0b19 100644 --- a/lua/acf/shared/rounds/refill.lua +++ b/lua/acf/shared/rounds/refill.lua @@ -19,6 +19,8 @@ function Round.convert(_, PlayerData) RoundVolume = 35, } + BulletData.CartMass = BulletData.ProjMass + BulletData.PropMass + return BulletData end @@ -42,6 +44,30 @@ function Round.cratetxt() return "" end +function Round.OnFirst(Entity) + if not Entity.SupplyingTo then + Entity.SupplyingTo = {} + end + + timer.Create("ACF Refill " .. Entity:EntIndex(), 1, 0, function() + if not IsValid(Entity) then return end + + RefillCrates(Entity) + end) +end + +function Round.OnLast(Entity) + local CallName = "ACF Refill " .. Entity:EntIndex() + + for Crate in pairs(Entity.SupplyingTo) do + Crate:RemoveCallOnRemove(CallName) + end + + Entity.SupplyingTo = nil + + timer.Remove(CallName) +end + function Round.guicreate(Panel, Table) acfmenupanel:AmmoSelect() acfmenupanel:CPanelText("Desc", "") --Description (Name, Desc) diff --git a/lua/effects/acf_bullet_effect.lua b/lua/effects/acf_bullet_effect.lua index 953c95293..121887f72 100644 --- a/lua/effects/acf_bullet_effect.lua +++ b/lua/effects/acf_bullet_effect.lua @@ -11,7 +11,7 @@ function EFFECT:Init(Data) return end - self.CreateTime = CurTime() + self.CreateTime = ACF.CurTime local Bullet = Bullets[self.Index] local Flight = Data:GetStart() * 10 @@ -51,22 +51,22 @@ function EFFECT:Init(Data) return end - local Tracer = Crate:GetNWFloat("Tracer") > 0 + local Tracer = Crate:GetNW2Float("Tracer") > 0 local BulletData = { Crate = Crate, SimFlight = Flight, SimPos = Origin, SimPosLast = Origin, - Caliber = Crate:GetNWFloat("Caliber", 10), - RoundMass = Crate:GetNWFloat("ProjMass", 10), - FillerMass = Crate:GetNWFloat("FillerMass"), - WPMass = Crate:GetNWFloat("WPMass"), - DragCoef = Crate:GetNWFloat("DragCoef", 1), - AmmoType = Crate:GetNWString("AmmoType", "AP"), + Caliber = Crate:GetNW2Float("Caliber", 10), + RoundMass = Crate:GetNW2Float("ProjMass", 10), + FillerMass = Crate:GetNW2Float("FillerMass"), + WPMass = Crate:GetNW2Float("WPMass"), + DragCoef = Crate:GetNW2Float("DragCoef", 1), + AmmoType = Crate:GetNW2String("AmmoType", "AP"), Tracer = Tracer and ParticleEmitter(Origin) or nil, TracerColour = Tracer and Crate:GetColor() or nil, - Accel = Crate:GetNWVector("Accel", Vector(0, 0, -600)), - LastThink = CurTime(), + Accel = Crate:GetNW2Vector("Accel", Vector(0, 0, -600)), + LastThink = ACF.CurTime, Effect = self, } @@ -88,7 +88,7 @@ end function EFFECT:Think() local Bullet = Bullets[self.Index] - if Bullet and not self.Kill and self.CreateTime > CurTime() - 30 then return true end + if Bullet and not self.Kill and self.CreateTime > ACF.CurTime - 30 then return true end if Bullet then if IsValid(Bullet.Tracer) then diff --git a/lua/entities/acf_ammo/cl_init.lua b/lua/entities/acf_ammo/cl_init.lua index fcf20e259..a4ba054ee 100644 --- a/lua/entities/acf_ammo/cl_init.lua +++ b/lua/entities/acf_ammo/cl_init.lua @@ -1,5 +1,8 @@ include("shared.lua") +language.Add("Undone_acf_ammo", "Undone ACF Ammo Crate") +language.Add("SBoxLimit__acf_ammo", "You've reached the ACF Ammo Crates limit!") + local MaxRounds = GetConVar("acf_maxroundsdisplay") local HideInfo = ACF.HideInfoBubble local Refills = {} @@ -37,8 +40,8 @@ net.Receive("ACF_RequestAmmoData", function() Entity.LocalAng = Data.LocalAng Entity.FitPerAxis = Data.FitPerAxis Entity.Spacing = Data.Spacing - Entity.MagSize = Data.MGS - Entity.HasBoxedAmmo = Data.MGS > 0 + Entity.MagSize = Data.MagSize + Entity.HasBoxedAmmo = Data.MagSize > 0 end if Queued[Entity] then diff --git a/lua/entities/acf_ammo/init.lua b/lua/entities/acf_ammo/init.lua index 4183be93e..eea2735b3 100644 --- a/lua/entities/acf_ammo/init.lua +++ b/lua/entities/acf_ammo/init.lua @@ -3,533 +3,394 @@ AddCSLuaFile("shared.lua") include("shared.lua") -util.AddNetworkString("ACF_RefillEffect") -util.AddNetworkString("ACF_StopRefillEffect") -util.AddNetworkString("ACF_RequestAmmoData") - -- Local Vars ----------------------------------- -local CheckLegal = ACF_CheckLegal -local ClassLink = ACF.GetClassLink -local ClassUnlink = ACF.GetClassUnlink -local Inputs = ACF.GetInputActions("acf_ammo") -local RefillDist = ACF.RefillDistance * ACF.RefillDistance + local ActiveCrates = ACF.AmmoCrates -local TimerCreate = timer.Create -local TimerExists = timer.Exists - -local function CanRefillCrate(Refill, Crate, Distance) - if Refill == Crate then return false end - if not Refill:CanConsume() then return false end - if Crate.Ammo >= Crate.Capacity then return false end - if Crate.RoundType == "Refill" then return false end - if Crate.Disabled then return false end - if Crate.Damaged then return false end - - return Distance <= RefillDist -end - -local function RefillEffect(Entity) - net.Start("ACF_RefillEffect") - net.WriteEntity(Entity) - net.Broadcast() -end - -local function StopRefillEffect(Entity) - net.Start("ACF_StopRefillEffect") - net.WriteEntity(Entity) - net.Broadcast() -end - --- Whenever a player requests ammo data, we'll send it to them -net.Receive("ACF_RequestAmmoData", function(_, Player) - local Entity = net.ReadEntity() - - if IsValid(Entity) and Entity.CrateData then - net.Start("ACF_RequestAmmoData") - net.WriteEntity(Entity) - net.WriteString(Entity.CrateData) - net.Send(Player) +local TimerCreate = timer.Create +local TimerExists = timer.Exists +local HookRun = hook.Run + +do -- Spawning and Updating -------------------- + local CheckLegal = ACF_CheckLegal + local Axises = { + x = { Y = "y", Z = "z", Ang = Angle() }, + y = { Y = "x", Z = "z", Ang = Angle(0, 90) }, + z = { Y = "x", Z = "y", Ang = Angle(90, 90) } + } + + local function GetBoxDimensions(Axis, Size) + local AxisInfo = Axises[Axis] + local Y = Size[AxisInfo.Y] + local Z = Size[AxisInfo.Z] + + return Size[Axis], Y, Z, AxisInfo.Ang end -end) -local function RefillCrates(Refill) - local Position = Refill:GetPos() + local function GetRoundsPerAxis(SizeX, SizeY, SizeZ, Length, Width, Height, Spacing) + -- Omitting spacing for the axises with just one round + if math.floor(SizeX / Length) > 1 then Length = Length + Spacing end + if math.floor(SizeY / Width) > 1 then Width = Width + Spacing end + if math.floor(SizeZ / Height) > 1 then Height = Height + Spacing end - for Crate in pairs(ActiveCrates) do - local Distance = Position:DistToSqr(Crate:GetPos()) + local RoundsX = math.floor(SizeX / Length) + local RoundsY = math.floor(SizeY / Width) + local RoundsZ = math.floor(SizeZ / Height) - if CanRefillCrate(Refill, Crate, Distance) then - local Supply = math.ceil(ACF.RefillSpeed / Crate.BulletData.CartMass / Distance ^ 0.5) - local Transfer = math.min(Supply, Refill.Ammo, Crate.Capacity - Crate.Ammo) + return RoundsX, RoundsY, RoundsZ + end - if hook.Run("ACF_CanRefill", Refill, Crate, Transfer) == false then continue end + -- Split this off from the original function, + -- All this does is compare a distance against a table of distances with string indexes for the shortest fitting size + -- It returns the string index of the dimension, or nil if it fails to fit + local function ShortestSize(Length, Width, Height, Spacing, Dimensions, ExtraData, IsIrregular) + local BestCount = 0 + local BestAxis - if not next(Refill.SupplyingTo) then - RefillEffect(Refill) - end + for Axis in pairs(Axises) do + local X, Y, Z = GetBoxDimensions(Axis, Dimensions) + local Multiplier = 1 - if not Refill.SupplyingTo[Crate] then - Refill.SupplyingTo[Crate] = true + if not IsIrregular then + local MagSize = ExtraData.MagSize - Crate:CallOnRemove("ACF Refill " .. Refill:EntIndex(), function() - Refill.SupplyingTo[Crate] = nil - end) + if MagSize and MagSize > 0 then + Multiplier = MagSize + end end - Crate:Consume(-Transfer) - Refill:Consume(Transfer) - - Crate:EmitSound("items/ammo_pickup.wav", 350, 100, 0.5) - Refill:EmitSound("items/ammo_pickup.wav", 350, 100, 0.5) - - elseif Refill.SupplyingTo[Crate] then - Refill.SupplyingTo[Crate] = nil + local RoundsX, RoundsY, RoundsZ = GetRoundsPerAxis(X, Y, Z, Length, Width, Height, Spacing) + local Count = RoundsX * RoundsY * RoundsZ * Multiplier - Crate:RemoveCallOnRemove("ACF Refill " .. Refill:EntIndex()) - - if not next(Refill.SupplyingTo) then - StopRefillEffect(Refill) + if Count > BestCount then + BestAxis = Axis + BestCount = Count end end + + return BestAxis, BestCount end -end - --- Split this off from the original function, --- All this does is compare a distance against a table of distances with string indexes for the shortest fitting size --- It returns the string index of the dimension, or nil if it fails to fit -local function ShortestSize(Size,Spacing,DimTable,ExtraData,IsIrregular) - local ReturnDimension = nil - local X = 0 - local Y = 0 - local TestRoundCount = 0 - local BestCount = 0 - - --local FullSize = {x = Size.x + Spacing, y = Size.y + Spacing, z = Size.z + Spacing} -- size of the round with the padding - local ConvLength = Size.x - - for K,_ in pairs(DimTable) do - if K == "x" then - X = DimTable["y"] - Y = DimTable["z"] - elseif K == "y" then - X = DimTable["x"] - Y = DimTable["z"] - else -- z - X = DimTable["x"] - Y = DimTable["y"] - end - - if not IsIrregular then - local ModifiedRoundLength = ConvLength + Spacing - local ModifiedRoundSize = Size.y + Spacing - if (math.floor(DimTable[K] / ConvLength) == 1) then ModifiedRoundLength = ConvLength end - - local RoundsX = math.floor(DimTable[K] / ModifiedRoundLength) - local RoundsY = math.floor(X / ModifiedRoundSize) - local RoundsZ = math.floor(Y / ModifiedRoundSize) - - if ExtraData.MagSize or 0 > 0 then - TestRoundCount = RoundsX * RoundsY * RoundsZ * ExtraData.MagSize + + -- BoxSize is just OBBMaxs-OBBMins + -- Removed caliber and round length inputs, uses GunData and BulletData now + -- AddSpacing is just extra spacing (directly reduces storage, but can later make it harder to detonate) + -- AddArmor is literally just extra armor on the ammo crate, but inside (also directly reduces storage) + -- For missiles/bombs, they MUST have ActualLength and ActualWidth (of the model in cm, and in the round table) to use this, otherwise it will fall back to the original calculations + -- Made by LiddulBOFH :) + local function CalcAmmo(BoxSize, GunData, BulletData, AddSpacing, AddArmor) + -- gives a nice number of rounds per refill box + if BulletData.Type == "Refill" then return math.ceil(BoxSize.x * BoxSize.y * BoxSize.z * 0.01) end + + local GunCaliber = GunData.Caliber * 0.1 -- mm to cm + local RoundCaliber = GunCaliber * ACF.AmmoCaseScale + local RoundLength = BulletData.PropLength + BulletData.ProjLength + (BulletData.Tracer or 0) + + local ExtraData = {} + + -- Filters for missiles, and sets up data + if GunData.Round.ActualWidth then + RoundCaliber = GunData.Round.ActualWidth + RoundLength = GunData.Round.ActualLength + ExtraData.isRacked = true + elseif GunData.Class.Entity == "acf_rack" then return -1 end -- Fallback to old capacity + + local Rounds = 0 + local Spacing = math.max(AddSpacing, 0) + 0.125 + local MagSize = GunData.MagSize or 1 + local IsBoxed = GunData.Class.IsBoxed + local Rotate + + -- Converting everything to source units + local Length = RoundLength * 0.3937 -- cm to inches + local Width = RoundCaliber * 0.3937 -- cm to inches + local Height = Width + + ExtraData.Spacing = Spacing + + -- This block alters the stored round size, making it more like a container of the rounds + -- This cuts a little bit of ammo storage out + if MagSize > 1 then + if IsBoxed and not ExtraData.isRacked then + -- Makes certain automatic ammo stored by boxes + Width = Width * math.sqrt(MagSize) + Height = Width + + ExtraData.MagSize = MagSize + ExtraData.isBoxed = true else - TestRoundCount = RoundsX * RoundsY * RoundsZ + MagSize = 1 end - else - local ModifiedRoundLength = ConvLength + Spacing - local RoundWidth = Size.y + Spacing - local RoundHeight = Size.z + Spacing - -- Doesn't use round spacing for length wise if its just 1, because edge cases are fun - if (math.floor(DimTable[K] / ConvLength) == 1) then ModifiedRoundLength = ConvLength end - - local RoundsX = math.floor(DimTable[K] / ModifiedRoundLength) - local RoundsY = math.floor(X / (RoundWidth + Spacing)) - local RoundsZ = math.floor(Y / (RoundHeight + Spacing)) - - TestRoundCount = RoundsX * RoundsY * RoundsZ end - if ReturnDimension == nil then - if TestRoundCount > BestCount then ReturnDimension = K BestCount = TestRoundCount end -- It fits, it sits - else - if TestRoundCount > BestCount then ReturnDimension = K BestCount = TestRoundCount end -- It fits, it sits in an even small spot + if AddArmor then + -- Converting millimeters to inches then multiplying by two since the armor is on both sides + local BoxArmor = AddArmor * 0.039 * 2 + local X = math.max(BoxSize.x - BoxArmor, 0) + local Y = math.max(BoxSize.y - BoxArmor, 0) + local Z = math.max(BoxSize.z - BoxArmor, 0) + + BoxSize = Vector(X, Y, Z) end - end - return ReturnDimension, BestCount -end - --- BoxSize is just OBBMaxs-OBBMins --- Removed caliber and round length inputs, uses GunData and BulletData now --- AddSpacing is just extra spacing (directly reduces storage, but can later make it harder to detonate) --- AddArmor is literally just extra armor on the ammo crate, but inside (also directly reduces storage) --- For missiles/bombs, they MUST have ActualLength and ActualWidth (of the model in cm, and in the round table) to use this, otherwise it will fall back to the original calculations --- Made by LiddulBOFH :) -local function CalcAmmo(BoxSize,GunData,BulletData,AddSpacing,AddArmor) - local RoundCaliber = GunData.caliber * ACF.AmmoCaseScale or 0 - local TotalRoundLength = (BulletData.PropLength or 0) + (BulletData.ProjLength or 0) + (BulletData.Tracer or 0) - local ExtraData = {} - - -- gives a nice number of rounds per refill box - if BulletData.Type == "Refill" then return math.ceil((BoxSize.x / 2) * (BoxSize.y / 2) * (BoxSize.z / 2)) end - - -- Filters for missiles, and sets up data - if (GunData.round.ActualWidth or nil) ~= nil then - RoundCaliber = GunData.round.ActualWidth - TotalRoundLength = GunData.round.ActualLength - ExtraData.isRacked = true - elseif GunData.ent == "acf_rack" then return -1 end -- Fallback to old capacity - -- Instantly invalidate garbage rounds - if RoundCaliber == 0 then return 0 end - if TotalRoundLength == 0 then return 0 end - - local Rounds = 0 - -- Converting everything to source units - local ConvCaliber = RoundCaliber * 0.3937 -- cm to inches - local ConvLength = TotalRoundLength * 0.3937 - local Spacing = math.max(math.abs(AddSpacing) + 0.125,0.125) - ExtraData.Spacing = Spacing - - local MagSize = 0 - local MagBoxSize = 0 - local Class = GunData.gunclass - - -- This block alters the stored round size, making it more like a container of the rounds - -- This cuts a little bit of ammo storage out - -- Anything that may potentially be belt-fed (RACs, ACs despite having the weirdass revolver design) is exempt - -- Anything with a sensible magazine is forced to use this - -- Autoloading cannons are exempt because of rounds being inserted into the stored drums - - -- a much needed enmasse comparing function - -- through some light digging, I couldn't find one, so I made one - local Force = switch({ - ["SA"] = true, - ["SL"] = true, - ["HMG"] = true, - ["GL"] = true, - ["MG"] = true, - ["default"] = false - }, - Class) - - local ForceSkip = switch({ - ["RAC"] = true, - ["AC"] = true, - ["AL"] = true, - ["default"] = false - }, - Class) - - if ((GunData.magsize or 0) > 0) and ((GunData.caliber <= 2) or (Force and (not (ExtraData.isRacked or false)))) and (not ForceSkip) then - MagSize = GunData.magsize - MagBoxSize = ConvCaliber * math.sqrt(MagSize) - -- Makes certain automatic ammo stored by boxes - ConvCaliber = MagBoxSize - ExtraData.MagSize = MagSize - ExtraData.isBoxed = true - end - if AddArmor then - local ConvArmor = AddArmor * 0.039 * 2 -- Converting millimeters to inches then multiplying by two since the armor is on both sides - BoxSize = { - x = math.max(BoxSize.x-ConvArmor, 0), - y = math.max(BoxSize.y-ConvArmor, 0), - z = math.max(BoxSize.z-ConvArmor, 0) - } - end + local ShortestFit = ShortestSize(Length, Width, Height, Spacing, BoxSize, ExtraData) - local D = {["x"] = BoxSize.x, ["y"] = BoxSize.y, ["z"] = BoxSize.z} - local ShortestFit = ShortestSize({x = ConvLength,y = ConvCaliber,z = ConvCaliber},Spacing,D,ExtraData,false) - - if ShortestFit ~= nil then -- From here we know the round can sorta fit in the box - local X = 0 - local Y = 0 - -- Creating the 'plane' to do the basic bitch math with - if ShortestFit == "x" then - X = D["y"] - Y = D["z"] - ExtraData.LocalAng = Angle(0,0,0) - elseif ShortestFit == "y" then - X = D["x"] - Y = D["z"] - ExtraData.LocalAng = Angle(0,90,0) - else -- z - X = D["x"] - Y = D["y"] - ExtraData.LocalAng = Angle(90,90,0) - end - - local ModifiedRoundLength = ConvLength + Spacing - local ModifiedRoundSize = ConvCaliber + Spacing - -- Doesn't use round spacing for length wise if its just 1, because edge cases are fun - if (math.floor(D[ShortestFit] / ConvLength) == 1) then ModifiedRoundLength = ConvLength end - -- That basic bitch math - ExtraData.RoundSize = Vector(ConvLength,ConvCaliber,ConvCaliber) - local RoundsX = math.floor(D[ShortestFit] / ModifiedRoundLength) - local RoundsY = math.floor(X / ModifiedRoundSize) - local RoundsZ = math.floor(Y / ModifiedRoundSize) - ExtraData.FitPerAxis = Vector(RoundsX,RoundsY,RoundsZ) - if MagSize > 0 then - Rounds = RoundsX * RoundsY * RoundsZ * MagSize - else - Rounds = RoundsX * RoundsY * RoundsZ - end - elseif ShortestFit == nil and ((ConvCaliber >= ((10 / 0.75) / 2.54)) or ((ExtraData.isRacked or false) == true)) and not (ExtraData.isBoxed or false) then -- If ShortestFit is nil, that means the round isn't able to fit at all in the box -- If its a racked munition that doesn't fit, it will go ahead and try to fit 2-pice -- Otherwise, checks if the caliber is over 100mm before trying 2-piece ammunition -- It will flatout not do anything if its boxed and not fitting + if not ShortestFit and not ExtraData.isBoxed and (GunCaliber >= 10 or ExtraData.isRacked) then + Length = Length * 0.5 -- Not exactly accurate, but cuts the round in two + Width = Width * 2 -- two pieces wide - -- Not exactly accurate, but cuts the round in two - ConvLength = ConvLength / 2 - -- Then makes a shape made of the now two pieces of ammunition - local RoundWidth = ConvCaliber * 2 -- two pieces wide - local RoundHeight = ConvCaliber -- one piece tall - - local ShortestFit1, ShortestFit2 - local Count1, Count2 - ShortestFit1,Count1 = ShortestSize({x = ConvLength,y = RoundWidth,z = RoundHeight},Spacing,D,ExtraData,true) - ShortestFit2,Count2 = ShortestSize({x = ConvLength,y = RoundHeight,z = RoundWidth},Spacing,D,ExtraData,true) - if Count1 > Count2 then ShortestFit = ShortestFit1 ShortestWidth = "x" else ShortestFit = ShortestFit2 ShortestWidth = "y" end - - -- Retrying the length fit - if ShortestFit ~= nil then - local X = 0 - local Y = 0 - -- Creating the 'plane' to do the basic bitch math with - if ShortestFit == "x" then - X = D["y"] - Y = D["z"] - ExtraData.LocalAng = Angle(0,0,0) - elseif ShortestFit == "y" then - X = D["x"] - Y = D["z"] - ExtraData.LocalAng = Angle(0,90,0) - else -- z - X = D["x"] - Y = D["y"] - ExtraData.LocalAng = Angle(90,90,0) - end + ExtraData.isTwoPiece = true - -- Now we have to check which side will fit the new width of the round, in the shortest space possible - local D2 = {["x"] = X, ["y"] = Y} - - local FreeSpace = 0 - if ShortestWidth ~= nil then - if ShortestWidth == "x" then - FreeSpace = D2["y"] - ExtraData.LocalAng = ExtraData.LocalAng + Angle(0,0,0) - else -- y - FreeSpace = D2["x"] - ExtraData.LocalAng = ExtraData.LocalAng + Angle(0,0,90) - end + local ShortestFit1, Count1 = ShortestSize(Length, Width, Height, Spacing, BoxSize, ExtraData, true) + local ShortestFit2, Count2 = ShortestSize(Length, Height, Width, Spacing, BoxSize, ExtraData, true) - local ModifiedRoundLength = ConvLength + Spacing - -- Doesn't use round spacing for length wise if its just 1, because edge cases are fun - if (math.floor(D[ShortestFit] / ConvLength) == 1) then ModifiedRoundLength = ConvLength end - ExtraData.RoundSize = Vector(ConvLength,RoundWidth,RoundHeight) - local RoundsX = math.floor(D[ShortestFit] / ModifiedRoundLength) - local RoundsY = math.floor(D2[ShortestWidth] / (RoundWidth + Spacing)) - local RoundsZ = math.floor(FreeSpace / (RoundHeight + Spacing)) - ExtraData.FitPerAxis = Vector(RoundsX,RoundsY,RoundsZ) - Rounds = RoundsX * RoundsY * RoundsZ + if Count1 > Count2 then + ShortestFit = ShortestFit1 + else + ShortestFit = ShortestFit2 + Rotate = true end end - -- If it still doesn't fit the box, then the box is just too small - ExtraData.isTwoPiece = true - end + -- If it still doesn't fit the box, then it's just too small + if ShortestFit then + local SizeX, SizeY, SizeZ, LocalAng = GetBoxDimensions(ShortestFit, BoxSize) + + ExtraData.LocalAng = LocalAng + ExtraData.RoundSize = Vector(Length, Width, Height) - return Rounds,ExtraData -end + -- In case the round was cut and needs to be rotated, then we do some minor changes + if Rotate then + local OldY = SizeY -local function UpdateAmmoData(Entity, Data1, Data2, Data3, Data4, Data5, Data6, Data7, Data8, Data9, Data10, Data11, Data12, Data13, Data) - local GunData = ACF.Weapons.Guns[Data1] - local Percentage = Entity.Capacity and Entity.Ammo / math.max(Entity.Capacity, 1) or 1 + SizeY = SizeZ + SizeZ = OldY - do -- Sanity checks - if not GunData then - Entity:Remove() - return + ExtraData.LocalAng = ExtraData.LocalAng + Angle(0, 0, 90) + end + + local RoundsX, RoundsY, RoundsZ = GetRoundsPerAxis(SizeX, SizeY, SizeZ, Length, Width, Height, Spacing) + + ExtraData.FitPerAxis = Vector(RoundsX, RoundsY, RoundsZ) + + Rounds = RoundsX * RoundsY * RoundsZ * MagSize end - if next(Entity.Weapons) then - local Unloaded + return Rounds, ExtraData + end - for Weapon in pairs(Entity.Weapons) do - if Weapon.CurrentCrate == Entity then - Unloaded = true + local Classes = ACF.Classes + local Crates = Classes.Crates + local AmmoTypes = Classes.AmmoTypes + local GetClassGroup = ACF.GetClassGroup + local Updated = { + ["20mmHRAC"] = "20mmRAC", + ["30mmHRAC"] = "30mmRAC", + } + + local function VerifyData(Data) + if Data.RoundId then -- Updating old crates + Data.Weapon = Updated[Data.RoundId] or Data.RoundId + Data.AmmoType = Data.RoundType or "AP" + + if Data.Id and Crates[Data.Id] then -- Pre scalable crate remnants + local Crate = Crates[Data.Id] + + Data.Offset = Crate.Offset + Data.Size = Crate.Size + else + local X = Data.RoundData11 or 24 + local Y = Data.RoundData12 or 24 + local Z = Data.RoundData13 or 24 - Weapon:Unload() - end + Data.Size = Vector(X, Y, Z) end + end - if Unloaded then - ACF_SendNotify(Entity.Owner, false, "Crate updated while weapons were loaded with it's ammo. Weapons unloaded.") + do -- Clamping size + local Size = Data.Size + + if isvector(Size) then + Size.x = math.Clamp(Size.x, 6, 96) + Size.y = math.Clamp(Size.y, 6, 96) + Size.z = math.Clamp(Size.z, 6, 96) + else + Data.Size = Vector(24, 24, 24) end end - end - do -- Mass entity mod removal - local EntMods = Data and Data.EntityMods + if not Data.Destiny then + Data.Destiny = ACF.FindWeaponrySource(Data.Weapon) or "Weapons" + end + + local Source = Classes[Data.Destiny] + local Class = GetClassGroup(Source, Data.Weapon) - if EntMods and EntMods.mass then - EntMods.mass = nil + if not Class then + Class = GetClassGroup(Classes.Weapons, "50mmC") + + Data.Destiny = "Weapons" + Data.Weapon = "50mmC" end - end - local RoundData = ACF.RoundTypes[Data2] + local Ammo = AmmoTypes[Data.AmmoType] - do -- Backwards compatibility - local AmmoData = Data and Data.Id and ACF.Weapons.Ammo[Data.Id] + -- Making sure our ammo type exists and it's not blacklisted by the weapon + if not Ammo or Ammo.Blacklist[Class.ID] then + Data.AmmoType = Class.DefaultAmmo or "AP" - if AmmoData and not (Data11 or Data12 or Data13) then - local NewPos = Entity:LocalToWorld(AmmoData.Offset) - local Size = AmmoData.Size + Ammo = AmmoTypes[Data.AmmoType] + end - Entity:SetPos(NewPos) + do -- External verifications + Ammo:VerifyData(Data, Class) -- All ammo types should come with this function - -- Updating the dupe position - -- TODO: Update constraints on the entity if it gets moved - if Data.BuildDupeInfo then - Data.BuildDupeInfo.PosReset = NewPos + if Class.VerifyData then + Class.VerifyData(Data, Class, Ammo) end - Data11 = Size.x - Data12 = Size.y - Data13 = Size.z + HookRun("ACF_VerifyData", "acf_ammo", Data, Class, Ammo) end end - do -- Update RoundData - --Data 1 to 4 are should always be Round ID, Round Type, Propellant lenght, Projectile lenght - Entity.RoundId = Data1 --Weapon this round loads into, ie 140mmC, 105mmH ... - Entity.RoundType = RoundData and Data2 or "AP" --Type of round, IE AP, HE, HEAT ... - Entity.RoundPropellant = Data3 --Length of propellant - Entity.RoundProjectile = Data4 --Length of the projectile - Entity.RoundData5 = Data5 or 0 - Entity.RoundData6 = Data6 or 0 - Entity.RoundData7 = Data7 or 0 - Entity.RoundData8 = Data8 or 0 - Entity.RoundData9 = Data9 or 0 - Entity.RoundData10 = Data10 or 0 - Entity.RoundData11 = Data11 or Entity.RoundData11 or 24 -- Scale X - Entity.RoundData12 = Data12 or Entity.RoundData12 or 24 -- Scale Y - Entity.RoundData13 = Data13 or Entity.RoundData13 or 24 -- Scale Z - - Entity.Name = (Entity.RoundType ~= "Refill" and (Data1 .. " ") or "") .. Entity.RoundType - Entity.ShortName = Data1 - Entity.EntType = Entity.RoundType - Entity.RoundData = RoundData or ACF.RoundTypes.AP - - local PlayerData = { - Id = Entity.RoundId, - Type = Entity.RoundType, - PropLength = Entity.RoundPropellant, - ProjLength = Entity.RoundProjectile, - Data5 = Entity.RoundData5, - Data6 = Entity.RoundData6, - Data7 = Entity.RoundData7, - Data8 = Entity.RoundData8, - Data9 = Entity.RoundData9, - Data10 = Entity.RoundData10 - } + local function UpdateCrate(Entity, Data, Class, Weapon, Ammo) + local Name, ShortName, WireName = Ammo:GetCrateName() - Entity.BulletData = Entity.RoundData.convert(Entity, PlayerData) - Entity.BulletData.Crate = Entity:EntIndex() + Entity.Name = Name or Weapon.Name .. " " .. Ammo.Name + Entity.ShortName = ShortName or Weapon.ID .. " " .. Ammo.ID + Entity.EntType = "Ammo Crate" + Entity.ClassData = Class + Entity.Caliber = Weapon.Caliber + Entity.Class = Class.ID - if Entity.RoundType == "Refill" then - Entity.SupplyingTo = Entity.SupplyingTo or {} + Entity:SetNWString("WireName", "ACF " .. (WireName or Weapon.Name .. " Ammo Crate")) + Entity:SetSize(Data.Size) - TimerCreate("ACF Refill " .. Entity:EntIndex(), 1, 0, function() - if not IsValid(Entity) then return end + do -- Updating round data + local OldAmmo = Entity.RoundData - RefillCrates(Entity) - end) - else - if Entity.SupplyingTo then - StopRefillEffect(Entity) + if OldAmmo then + if OldAmmo.OnLast then + OldAmmo:OnLast(Entity) + end - Entity.SupplyingTo = nil + HookRun("ACF_OnAmmoLast", Entity, OldAmmo) end - timer.Remove("ACF Refill " .. Entity:EntIndex()) - end - end + Entity.RoundData = Ammo + Entity.BulletData = Ammo:ServerConvert(Data) + Entity.BulletData.Crate = Entity:EntIndex() - local Size - do -- Resizing - local X = math.Clamp(Entity.RoundData11, 6, 96) - local Y = math.Clamp(Entity.RoundData12, 6, 96) - local Z = math.Clamp(Entity.RoundData13, 6, 96) + if Ammo.OnFirst then + Ammo:OnFirst(Entity) + end - Size = Vector(X, Y, Z) + HookRun("ACF_OnAmmoFirst", Entity, Ammo, Class, Weapon) - if Size ~= Entity:GetSize() then - Entity:SetSize(Size) + Ammo:Network(Entity, Entity.BulletData) end - end - -- CalcAmmo function is just above - local Rounds, ExtraData = CalcAmmo(Size, GunData, Entity.BulletData, GunData.caliber * 0.039, ACF.AmmoArmor) + -- Storing all the relevant information on the entity for duping + for _, V in ipairs(Entity.DataStore) do + Entity[V] = Data[V] + end - if Rounds ~= -1 then - Entity.Capacity = Rounds - else - --print("Fallback (Rackable munition missing ActualLength/ActualWidth)") + do -- Ammo count calculation + local Size = Entity:GetSize() + local Spacing = Weapon.Caliber * 0.0039 + local Rounds, ExtraData = CalcAmmo(Size, Weapon, Entity.BulletData, Spacing, ACF.AmmoArmor) + local Percentage = Entity.Capacity and Entity.Ammo / math.max(Entity.Capacity, 1) or 1 - local Efficiency = 0.1576 * ACF.AmmoMod - local Volume = math.floor(Entity:GetPhysicsObject():GetVolume()) * Efficiency - local CapMul = (Volume > 40250) and ((math.log(Volume * 0.00066) / math.log(2) - 4) * 0.15 + 1) or 1 + if Rounds ~= -1 then + Entity.Capacity = Rounds + else + local Efficiency = 0.1576 * ACF.AmmoMod + local Volume = math.floor(Entity:GetPhysicsObject():GetVolume()) * Efficiency + local CapMul = (Volume > 40250) and ((math.log(Volume * 0.00066) / math.log(2) - 4) * 0.15 + 1) or 1 - Entity.Capacity = math.floor(CapMul * Volume * 16.38 / Entity.BulletData.RoundVolume) - end + Entity.Capacity = math.floor(CapMul * Volume * 16.38 / Entity.BulletData.RoundVolume) + end - Entity.AmmoMassMax = math.floor((Entity.BulletData.ProjMass + Entity.BulletData.PropMass) * Entity.Capacity) - Entity.Caliber = GunData.caliber - Entity.Ammo = math.floor(Entity.Capacity * Percentage) + Entity.AmmoMassMax = math.floor(Entity.BulletData.CartMass * Entity.Capacity) + Entity.Ammo = math.floor(Entity.Capacity * Percentage) - Entity:SetNWInt("Ammo", Entity.Ammo) + WireLib.TriggerOutput(Entity, "Ammo", Entity.Ammo) - WireLib.TriggerOutput(Entity, "Ammo", Entity.Ammo) + Entity:SetNWInt("Ammo", Entity.Ammo) - if ExtraData then - local MGS = 0 - if ((GunData.magsize or 0) > 0) and (ExtraData.isBoxed or false) then MGS = (GunData.magsize or 0) end - ExtraData.MGS = MGS - ExtraData.IsRound = not (ExtraData.isBoxed or ExtraData.isTwoPiece or ExtraData.isRacked) + if ExtraData then + local MagSize = Weapon.MagSize - -- for future use in reloading - --if (ExtraData.isBoxed or false) then Entity.isBoxed = true end -- Ammunition is boxed - --if (ExtraData.isTwoPiece or false) then Entity.isTwoPiece = true end -- Ammunition is broken down to two pieces + -- for future use in reloading + --Entity.isBoxed = ExtraData.isBoxed -- Ammunition is boxed + --Entity.isTwoPiece = ExtraData.isTwoPiece -- Ammunition is broken down to two pieces - ExtraData.Capacity = Entity.Capacity - ExtraData.Enabled = true - else - ExtraData = { Enabled = false } - end + ExtraData.MagSize = ExtraData.isBoxed and MagSize or 0 + ExtraData.IsRound = not (ExtraData.isBoxed or ExtraData.isTwoPiece or ExtraData.isRacked) + ExtraData.Capacity = Entity.Capacity + ExtraData.Enabled = true + else + ExtraData = { Enabled = false } + end - Entity.CrateData = util.TableToJSON(ExtraData) + Entity.CrateData = util.TableToJSON(ExtraData) - -- TODO: Figure out a way to not rely on this delay. - timer.Simple(0.1, function() - net.Start("ACF_RequestAmmoData") - net.WriteEntity(Entity) - net.WriteString(Entity.CrateData) - net.Broadcast() - end) + net.Start("ACF_RequestAmmoData") + net.WriteEntity(Entity) + net.WriteString(Entity.CrateData) + net.Broadcast() + end + + -- Linked weapon unloading + if next(Entity.Weapons) then + local Unloaded + + for K in pairs(Entity.Weapons) do + if K.CurrentCrate == Entity then + Unloaded = true + + K:Unload() + end + end + + if Unloaded then + ACF_SendNotify(Entity.Owner, false, "Crate updated while weapons were loaded with it's ammo. Weapons unloaded.") + end + end - Entity:SetNWString("WireName", "ACF " .. (Entity.RoundType == "Refill" and "Ammo Refill Crate" or GunData.name .. " Ammo")) + ACF_Activate(Entity, true) -- Makes Crate.ACF table - Entity.RoundData.network(Entity, Entity.BulletData) + Entity.ACF.Model = Entity:GetModel() - ACF_Activate(Entity, true) -- Makes Crate.ACF table + Entity:UpdateMass(true) + end + + util.AddNetworkString("ACF_RequestAmmoData") + + -- Whenever a player requests ammo data, we'll send it to them + net.Receive("ACF_RequestAmmoData", function(_, Player) + local Entity = net.ReadEntity() + + if IsValid(Entity) and Entity.CrateData then + net.Start("ACF_RequestAmmoData") + net.WriteEntity(Entity) + net.WriteString(Entity.CrateData) + net.Send(Player) + end + end) + + ------------------------------------------------------------------------------- - Entity.ACF.Model = Entity:GetModel() + function MakeACF_Ammo(Player, Pos, Ang, Data) + VerifyData(Data) - Entity:UpdateMass(true) - Entity:UpdateOverlay(true) -end + local Source = Classes[Data.Destiny] + local Class = GetClassGroup(Source, Data.Weapon) + local Weapon = Class.Lookup[Data.Weapon] + local Ammo = AmmoTypes[Data.AmmoType] -do -- Spawn Func -------------------------------- - function MakeACF_Ammo(Player, Pos, Ang, ...) if not Player:CheckLimit("_acf_ammo") then return end local Crate = ents.Create("acf_ammo") @@ -539,416 +400,486 @@ do -- Spawn Func -------------------------------- Player:AddCount("_acf_ammo", Crate) Player:AddCleanup("acfmenu", Crate) - Crate:SetPos(Pos) - Crate:SetAngles(Ang) - Crate:SetPlayer(Player) Crate:SetModel("models/holograms/rcube_thin.mdl") Crate:SetMaterial("phoenix_storms/Future_vents") + Crate:SetPlayer(Player) + Crate:SetAngles(Ang) + Crate:SetPos(Pos) Crate:Spawn() - Crate.IsExplosive = true - Crate.Owner = Player - Crate.Weapons = {} - Crate.Inputs = WireLib.CreateInputs(Crate, { "Load" }) - Crate.Outputs = WireLib.CreateOutputs(Crate, { "Entity [ENTITY]", "Ammo", "Loading" }) - Crate.CanUpdate = true - - UpdateAmmoData(Crate, ...) + Crate.Owner = Player -- MUST be stored on ent for PP + Crate.IsExplosive = true + Crate.Weapons = {} + Crate.Inputs = WireLib.CreateInputs(Crate, { "Load" }) + Crate.Outputs = WireLib.CreateOutputs(Crate, { "Entity [ENTITY]", "Ammo", "Loading" }) + Crate.DataStore = ACF.GetEntityArguments("acf_ammo") WireLib.TriggerOutput(Crate, "Entity", Crate) + UpdateCrate(Crate, Data, Class, Weapon, Ammo) + + if Class.OnSpawn then + Class.OnSpawn(Crate, Data, Class, Weapon, Ammo) + end + + HookRun("ACF_OnEntitySpawn", "acf_ammo", Crate, Data, Class, Weapon, Ammo) + + Crate:UpdateOverlay(true) + + -- Backwards compatibility with old crates + -- TODO: Update constraints on the entity if it gets moved + if Data.Offset then + local Position = Crate:LocalToWorld(Data.Offset) + + Crate:SetPos(Position) + + -- Updating the dupe position + if Data.BuildDupeInfo then + Data.BuildDupeInfo.PosReset = Position + end + end + + do -- Mass entity mod removal + local EntMods = Data.EntityMods + + if EntMods and EntMods.mass then + EntMods.mass = nil + end + end + -- Crates should be ready to load by default Crate:TriggerInput("Load", 1) - ACF.AmmoCrates[Crate] = true + ActiveCrates[Crate] = true CheckLegal(Crate) return Crate end - list.Set("ACFCvars", "acf_ammo", { "data1", "data2", "data3", "data4", "data5", "data6", "data7", "data8", "data9", "data10", "data11", "data12", "data13" }) - duplicator.RegisterEntityClass("acf_ammo", MakeACF_Ammo, "Pos", "Angle", "RoundId", "RoundType", "RoundPropellant", "RoundProjectile", "RoundData5", "RoundData6", "RoundData7", "RoundData8", "RoundData9", "RoundData10", "RoundData11", "RoundData12", "RoundData13", "Data") + ACF.RegisterEntityClass("acf_ammo", MakeACF_Ammo, "Weapon", "AmmoType", "Size") ACF.RegisterLinkSource("acf_ammo", "Weapons") -end -do -- Metamethods ------------------------------- - do -- Inputs/Outputs/Linking ---------------- - WireLib.AddInputAlias("Active", "Load") - WireLib.AddOutputAlias("Munitions", "Ammo") + ------------------- Updating --------------------- - ACF.AddInputAction("acf_ammo", "Load", function(Entity, Value) - Entity.Load = tobool(Value) + function ENT:Update(Data) + VerifyData(Data) - WireLib.TriggerOutput(Entity, "Loading", Entity:CanConsume() and 1 or 0) - end) + local Source = Classes[Data.Destiny] + local Class = GetClassGroup(Source, Data.Weapon) + local Weapon = Class.Lookup[Data.Weapon] + local Ammo = AmmoTypes[Data.AmmoType] + local Blacklist = Ammo.Blacklist + local OldClass = self.ClassData + local Extra = "" - function ENT:TriggerInput(Name, Value) - if self.Disabled then return end -- Ignore input if disabled - - local Action = Inputs[Name] + if Data.Weapon ~= self.Weapon then + for Entity in pairs(self.Weapons) do + self:Unlink(Entity) + end - if Action then - Action(self, Value) + Extra = " All weapons have been unlinked." + else + local Count = 0 - self:UpdateOverlay() - end - end + for Entity in pairs(self.Weapons) do + if Blacklist[Entity.Class] then + self:Unlink(Entity) - function ENT:Link(Target) - if not IsValid(Target) then return false, "Attempted to link an invalid entity." end - if self == Target then return false, "Can't link a crate to itself." end + Entity:Unload() - local Function = ClassLink(self:GetClass(), Target:GetClass()) + Count = Count + 1 + end + end - if Function then - return Function(self, Target) + -- Note: Wouldn't this just unlink all weapons anyway? + if Count > 0 then + Extra = " Unlinked " .. Count .. " weapons from this crate." end + end - return false, "Crates can't be linked to '" .. Target:GetClass() .. "'." + if OldClass.OnLast then + OldClass.OnLast(self, OldClass) end - function ENT:Unlink(Target) - if not IsValid(Target) then return false, "Attempted to unlink an invalid entity." end - if self == Target then return false, "Can't unlink a crate from itself." end + HookRun("ACF_OnEntityLast", "acf_ammo", self, OldClass) - local Function = ClassUnlink(self:GetClass(), Target:GetClass()) + ACF.SaveEntity(self) - if Function then - return Function(self, Target) - end + UpdateCrate(self, Data, Class, Weapon, Ammo) - return false, "Crates can't be unlinked from '" .. Target:GetClass() .. "'." - end - end + ACF.RestoreEntity(self) - do -- Overlay ------------------------------- - local Text = "%s\n\nSize: %sx%sx%s\n\nContents: %s ( %s / %s )%s%s" - local BulletText = "\nCartridge Mass: %s kg\nProjectile Mass: %s kg\nPropellant Mass: %s kg" + if Class.OnUpdate then + Class.OnUpdate(self, Data, Class, Weapon, Ammo) + end - local function Overlay(Ent) - if Ent.Disabled then - Ent:SetOverlayText("Disabled: " .. Ent.DisableReason .. "\n" .. Ent.DisableDescription) - else - local Tracer = Ent.BulletData.Tracer ~= 0 and "-T" or "" - local X, Y, Z = Ent:GetSize():Unpack() - local AmmoInfo = Ent.RoundData.cratetxt and Ent.RoundData.cratetxt(Ent.BulletData) - local BulletInfo = "" - local Status - - if next(Ent.Weapons) or Ent.BulletData.Type == "Refill" then - Status = Ent:CanConsume() and "Providing Ammo" or (Ent.Ammo ~= 0 and "Idle" or "Empty") - else - Status = "Not linked to a weapon!" - end + HookRun("ACF_OnEntityUpdate", "acf_ammo", self, Data, Class, Weapon, Ammo) - X = math.Round(X, 2) - Y = math.Round(Y, 2) - Z = math.Round(Z, 2) + self:UpdateOverlay(true) - if Ent.BulletData.Type ~= "Refill" then - local ProjectileMass = math.Round(Ent.BulletData.ProjMass, 2) - local PropellantMass = math.Round(Ent.BulletData.PropMass, 2) - local CartridgeMass = math.Round(Ent.BulletData.CartMass, 2) + net.Start("ACF_UpdateEntity") + net.WriteEntity(self) + net.Broadcast() - BulletInfo = BulletText:format(CartridgeMass, ProjectileMass, PropellantMass) - end + return true, "Crate updated successfully." .. Extra + end +end --------------------------------------------- - if AmmoInfo and AmmoInfo ~= "" then - AmmoInfo = "\n\n" .. AmmoInfo - end +do -- ACF Activation and Damage ----------------- + local function CookoffCrate(Entity) + if Entity.Ammo <= 1 or Entity.Damaged < ACF.CurTime then -- Detonate when time is up or crate is out of ammo + Entity:Detonate() + elseif Entity.BulletData.Type ~= "Refill" and Entity.RoundData then -- Spew bullets out everywhere + local VolumeRoll = math.Rand(0, 150) > Entity.BulletData.RoundVolume ^ 0.5 + local AmmoRoll = math.Rand(0, 1) < Entity.Ammo / math.max(Entity.Capacity, 1) - Ent:SetOverlayText(Text:format(Status, X, Y, Z, Ent.BulletData.Type .. Tracer, Ent.Ammo, Ent.Capacity, BulletInfo, AmmoInfo)) - end - end + if VolumeRoll and AmmoRoll then + local Speed = ACF_MuzzleVelocity(Entity.BulletData.PropMass, Entity.BulletData.ProjMass / 2) - function ENT:UpdateOverlay(Instant) - if Instant then - return Overlay(self) - end + Entity:EmitSound("ambient/explosions/explode_4.wav", 350, math.max(255 - Entity.BulletData.PropMass * 100,60)) - if TimerExists("ACF Overlay Buffer" .. self:EntIndex()) then -- This entity has been updated too recently - self.OverlayBuffer = true -- Mark it to update when buffer time has expired - else - TimerCreate("ACF Overlay Buffer" .. self:EntIndex(), 1, 1, function() - if IsValid(self) and self.OverlayBuffer then - self.OverlayBuffer = nil + Entity.BulletData.Pos = Entity:LocalToWorld(Entity:OBBCenter() + VectorRand() * Entity:GetSize() * 0.5) + Entity.BulletData.Flight = VectorRand():GetNormalized() * Speed * 39.37 + ACF_GetAncestor(Entity):GetVelocity() + Entity.BulletData.Owner = Entity.Inflictor or Entity.Owner + Entity.BulletData.Gun = Entity + Entity.BulletData.Crate = Entity:EntIndex() - Overlay(self) - end - end) + Entity.RoundData:Create(Entity, Entity.BulletData) - Overlay(self) + Entity:Consume() end end end - do -- Legal Checks -------------------------- - function ENT:Enable() - WireLib.TriggerOutput(self, "Loading", self:CanConsume() and 1 or 0) + ------------------------------------------------------------------------------- + + function ENT:ACF_Activate(Recalc) + local PhysObj = self.ACF.PhysObj - self:UpdateOverlay(true) - self:UpdateMass(true) + if not self.ACF.Area then + self.ACF.Area = PhysObj:GetSurfaceArea() * 6.45 end - function ENT:Disable() - WireLib.TriggerOutput(self, "Loading", 0) + local Volume = PhysObj:GetVolume() + + local Armour = ACF.AmmoArmor + local Health = Volume / ACF.Threshold --Setting the threshold of the prop Area gone + local Percent = 1 - self:UpdateOverlay(true) - self:UpdateMass(true) + if Recalc and self.ACF.Health and self.ACF.MaxHealth then + Percent = self.ACF.Health / self.ACF.MaxHealth end + + self.ACF.Health = Health * Percent + self.ACF.MaxHealth = Health + self.ACF.Armour = Armour * (0.5 + Percent / 2) + self.ACF.MaxArmour = Armour + self.ACF.Type = "Prop" end - do -- Consuming ammo, updating mass -------- - function ENT:CanConsume() - if self.Disabled then return false end - if not self.Load then return false end - if self.Damaged then return false end + function ENT:ACF_OnDamage(Entity, Energy, FrArea, Ang, Inflictor, _, Type) + local Mul = (Type == "HEAT" and ACF.HEATMulAmmo) or 1 --Heat penetrators deal bonus damage to ammo + local HitRes = ACF.PropDamage(Entity, Energy, FrArea * Mul, Ang, Inflictor) --Calling the standard damage prop function + + if self.Exploding or not self.IsExplosive then return HitRes end + + if HitRes.Kill then + if HookRun("ACF_AmmoExplode", self, self.BulletData) == false then return HitRes end + + if IsValid(Inflictor) and Inflictor:IsPlayer() then + self.Inflictor = Inflictor + end + + if self.Ammo > 0 then + self:Detonate() + end - return self.Ammo > 0 + return HitRes end - function ENT:Consume(Num) - self.Ammo = math.Clamp(self.Ammo - (Num or 1), 0, self.Capacity) + -- Cookoff chance + if self.Damaged then return HitRes end -- Already cooking off - self:UpdateOverlay() - self:UpdateMass() + local Ratio = (HitRes.Damage / self.BulletData.RoundVolume) ^ 0.2 - WireLib.TriggerOutput(self, "Ammo", self.Ammo) - WireLib.TriggerOutput(self, "Loading", self:CanConsume() and 1 or 0) + if (Ratio * self.Capacity / self.Ammo) > math.Rand(0, 1) then + self.Inflictor = Inflictor + self.Damaged = ACF.CurTime + (5 - Ratio * 3) - if TimerExists("ACF Network Ammo " .. self:EntIndex()) then return end + local Interval = 0.01 + self.BulletData.RoundVolume ^ 0.5 / 100 - TimerCreate("ACF Network Ammo " .. self:EntIndex(), 0.5, 1, function() + TimerCreate("ACF Crate Cookoff " .. self:EntIndex(), Interval, 0, function() if not IsValid(self) then return end - self:SetNWInt("Ammo", self.Ammo) + CookoffCrate(self) end) end - local function UpdateMass(Ent) - Ent.ACF.LegalMass = math.floor(Ent.EmptyMass + (Ent.AmmoMassMax * (Ent.Ammo / math.max(Ent.Capacity, 0)))) + return HitRes + end - local Phys = Ent:GetPhysicsObject() + function ENT:Detonate() + if not self.Damaged then return end - if IsValid(Phys) then - Phys:SetMass(Ent.ACF.LegalMass) - end - end + self.Exploding = true + self.Damaged = nil -- Prevent multiple explosions - function ENT:UpdateMass(Instant) - if Instant then - return UpdateMass(self) - end + timer.Remove("ACF Crate Cookoff " .. self:EntIndex()) -- Prevent multiple explosions - if TimerExists("ACF Mass Buffer" .. self:EntIndex()) then return end + local Pos = self:LocalToWorld(self:OBBCenter() + VectorRand() * self:GetSize() * 0.5) + local Filler = self.BulletData.FillerMass or 0 + local Propellant = self.BulletData.PropMass or 0 + local ExplosiveMass = (Filler + Propellant * (ACF.PBase / ACF.HEPower)) * self.Ammo + local FragMass = self.BulletData.ProjMass or ExplosiveMass * 0.5 - TimerCreate("ACF Mass Buffer" .. self:EntIndex(), 5, 1, function() - if not IsValid(self) then return end + ACF_KillChildProps(self, Pos, ExplosiveMass) + ACF_HE(Pos, ExplosiveMass, FragMass, self.Inflictor, {self}, self) - UpdateMass(self) - end) - end - end + local Effect = EffectData() + Effect:SetOrigin(Pos) + Effect:SetNormal(Vector(0, 0, -1)) + Effect:SetScale(math.max(ExplosiveMass ^ 0.33 * 8 * 39.37, 1)) + Effect:SetRadius(0) - do -- Misc ---------------------------------- - local function CookoffCrate(Entity) - if Entity.Ammo <= 1 or Entity.Damaged < ACF.CurTime then -- Detonate when time is up or crate is out of ammo - Entity:Detonate() - elseif Entity.BulletData.Type ~= "Refill" and Entity.RoundData then -- Spew bullets out everywhere - local VolumeRoll = math.Rand(0, 150) > Entity.BulletData.RoundVolume ^ 0.5 - local AmmoRoll = math.Rand(0, 1) < Entity.Ammo / math.max(Entity.Capacity, 1) + util.Effect("ACF_Explosion", Effect) - if VolumeRoll and AmmoRoll then - local Speed = ACF_MuzzleVelocity(Entity.BulletData.PropMass, Entity.BulletData.ProjMass / 2) + constraint.RemoveAll(self) + self:Remove() + end +end --------------------------------------------- - Entity:EmitSound("ambient/explosions/explode_4.wav", 350, math.max(255 - Entity.BulletData.PropMass * 100,60)) +do -- Entity Link/Unlink ------------------------ + local ClassLink = ACF.GetClassLink + local ClassUnlink = ACF.GetClassUnlink - Entity.BulletData.Pos = Entity:LocalToWorld(Entity:OBBCenter() + VectorRand() * (Entity:OBBMaxs() - Entity:OBBMins()) / 2) - Entity.BulletData.Flight = VectorRand():GetNormalized() * Speed * 39.37 + ACF_GetAncestor(Entity):GetVelocity() - Entity.BulletData.Owner = Entity.Inflictor or Entity.Owner - Entity.BulletData.Gun = Entity - Entity.BulletData.Crate = Entity:EntIndex() + function ENT:Link(Target) + if not IsValid(Target) then return false, "Attempted to link an invalid entity." end + if self == Target then return false, "Can't link a crate to itself." end - Entity.RoundData.create(Entity, Entity.BulletData) + local Function = ClassLink(self:GetClass(), Target:GetClass()) - Entity:Consume() - end - end + if Function then + return Function(self, Target) end - function ENT:ACF_Activate(Recalc) - local PhysObj = self.ACF.PhysObj + return false, "Crates can't be linked to '" .. Target:GetClass() .. "'." + end - if not self.ACF.Area then - self.ACF.Area = PhysObj:GetSurfaceArea() * 6.45 - end + function ENT:Unlink(Target) + if not IsValid(Target) then return false, "Attempted to unlink an invalid entity." end + if self == Target then return false, "Can't unlink a crate from itself." end - local Volume = PhysObj:GetVolume() + local Function = ClassUnlink(self:GetClass(), Target:GetClass()) - local Armour = ACF.AmmoArmor - local Health = Volume / ACF.Threshold --Setting the threshold of the prop Area gone - local Percent = 1 + if Function then + return Function(self, Target) + end - if Recalc and self.ACF.Health and self.ACF.MaxHealth then - Percent = self.ACF.Health / self.ACF.MaxHealth - end + return false, "Crates can't be unlinked from '" .. Target:GetClass() .. "'." + end +end --------------------------------------------- - self.ACF.Health = Health * Percent - self.ACF.MaxHealth = Health - self.ACF.Armour = Armour * (0.5 + Percent / 2) - self.ACF.MaxArmour = Armour - self.ACF.Type = "Prop" - end +do -- Entity Inputs ----------------------------- + local Inputs = ACF.GetInputActions("acf_ammo") - function ENT:ACF_OnDamage(Entity, Energy, FrArea, Ang, Inflictor, _, Type) - local Mul = (Type == "HEAT" and ACF.HEATMulAmmo) or 1 --Heat penetrators deal bonus damage to ammo - local HitRes = ACF.PropDamage(Entity, Energy, FrArea * Mul, Ang, Inflictor) --Calling the standard damage prop function + WireLib.AddInputAlias("Active", "Load") + WireLib.AddOutputAlias("Munitions", "Ammo") - if self.Exploding or not self.IsExplosive then return HitRes end + ACF.AddInputAction("acf_ammo", "Load", function(Entity, Value) + Entity.Load = tobool(Value) - if HitRes.Kill then - if hook.Run("ACF_AmmoExplode", self, self.BulletData) == false then return HitRes end + WireLib.TriggerOutput(Entity, "Loading", Entity:CanConsume() and 1 or 0) + end) - self.Exploding = true + function ENT:TriggerInput(Name, Value) + if self.Disabled then return end -- Ignore input if disabled - if IsValid(Inflictor) and Inflictor:IsPlayer() then - self.Inflictor = Inflictor - end + local Action = Inputs[Name] - if self.Ammo > 0 then - self:Detonate() - end + if Action then + Action(self, Value) - return HitRes - end + self:UpdateOverlay() + end + end +end --------------------------------------------- - -- Cookoff chance - if self.Damaged then return HitRes end -- Already cooking off +do -- Entity Overlay ---------------------------- + local Text = "%s\n\nSize: %sx%sx%s\n\nContents: %s ( %s / %s )%s%s%s" + local BulletText = "\nCartridge Mass: %s kg\nProjectile Mass: %s kg\nPropellant Mass: %s kg" - local Ratio = (HitRes.Damage / self.BulletData.RoundVolume) ^ 0.2 + local function Overlay(Ent) + if Ent.Disabled then + Ent:SetOverlayText("Disabled: " .. Ent.DisableReason .. "\n" .. Ent.DisableDescription) + else + local Tracer = Ent.BulletData.Tracer ~= 0 and "-T" or "" + local AmmoType = Ent.BulletData.Type .. Tracer + local X, Y, Z = Ent:GetSize():Unpack() + local AmmoInfo = Ent.RoundData:GetCrateText(Ent.BulletData) + local ExtraInfo = ACF.GetOverlayText(Ent) + local BulletInfo = "" + local Status + + if next(Ent.Weapons) or Ent.IsRefill then + Status = Ent:CanConsume() and "Providing Ammo" or (Ent.Ammo ~= 0 and "Idle" or "Empty") + else + Status = "Not linked to a weapon!" + end - if (Ratio * self.Capacity / self.Ammo) > math.Rand(0, 1) then - self.Inflictor = Inflictor - self.Damaged = ACF.CurTime + (5 - Ratio * 3) + X = math.Round(X, 2) + Y = math.Round(Y, 2) + Z = math.Round(Z, 2) - local Interval = 0.01 + self.BulletData.RoundVolume ^ 0.5 / 100 + if Ent.BulletData.Type ~= "Refill" then + local ProjectileMass = math.Round(Ent.BulletData.ProjMass, 2) + local PropellantMass = math.Round(Ent.BulletData.PropMass, 2) + local CartridgeMass = math.Round(Ent.BulletData.CartMass, 2) - TimerCreate("ACF Crate Cookoff " .. self:EntIndex(), Interval, 0, function() - if not IsValid(self) then return end + BulletInfo = BulletText:format(CartridgeMass, ProjectileMass, PropellantMass) + end - CookoffCrate(self) - end) + if AmmoInfo and AmmoInfo ~= "" then + AmmoInfo = "\n\n" .. AmmoInfo end - return HitRes + Ent:SetOverlayText(Text:format(Status, X, Y, Z, AmmoType, Ent.Ammo, Ent.Capacity, BulletInfo, AmmoInfo, ExtraInfo)) end + end + + ------------------------------------------------------------------------------- - function ENT:Update(ArgsTable) - -- That table is the player data, as sorted in the ACFCvars above, with player who shot, - -- and pos and angle of the tool trace inserted at the start - local Message = "Ammo crate updated successfully!" + function ENT:UpdateOverlay(Instant) + if Instant then + return Overlay(self) + end - if ArgsTable[1] ~= self.Owner then return false, "You don't own that ammo crate!" end -- Argtable[1] is the player that shot the tool - if ArgsTable[5] == "Refill" then return false, "Refill ammo type is only avaliable for new crates!" end -- Argtable[5] is the round type. If it's refill it shouldn't be loaded into guns, so we refuse to change to it + if TimerExists("ACF Overlay Buffer" .. self:EntIndex()) then -- This entity has been updated too recently + self.OverlayBuffer = true -- Mark it to update when buffer time has expired + else + TimerCreate("ACF Overlay Buffer" .. self:EntIndex(), 1, 1, function() + if IsValid(self) and self.OverlayBuffer then + self.OverlayBuffer = nil - -- Argtable[4] is the weapon ID the new ammo loads into - if ArgsTable[4] ~= self.RoundId then - for Gun in pairs(self.Weapons) do - self:Unlink(Gun) + Overlay(self) end + end) - Message = "New ammo type loaded, crate unlinked." - else -- ammotype wasn't changed, but let's check if new roundtype is blacklisted - local Blacklist = ACF.AmmoBlacklist[ArgsTable[5]] + Overlay(self) + end + end +end --------------------------------------------- - for Gun in pairs(self.Weapons) do - if table.HasValue(Blacklist, Gun.Class) then - self:Unlink(Gun) +do -- Mass Update ------------------------------- + local function UpdateMass(Ent) + Ent.ACF.LegalMass = math.floor(Ent.EmptyMass + (Ent.AmmoMassMax * (Ent.Ammo / math.max(Ent.Capacity, 0)))) - Gun:Unload() + local Phys = Ent:GetPhysicsObject() - Message = "New round type cannot be used with linked gun, crate unlinked and gun unloaded." - end - end - end + if IsValid(Phys) then + Phys:SetMass(Ent.ACF.LegalMass) + end + end - UpdateAmmoData(self, unpack(ArgsTable, 4)) + ------------------------------------------------------------------------------- - return true, Message + function ENT:UpdateMass(Instant) + if Instant then + return UpdateMass(self) end - function ENT:OnResized(Size) - do -- Calculate new empty mass - local A = ACF.AmmoArmor * 0.039 -- Millimeters to inches - local ExteriorVolume = Size.x * Size.y * Size.z - local InteriorVolume = (Size.x - A) * (Size.y - A) * (Size.z - A) -- Math degree + if TimerExists("ACF Mass Buffer" .. self:EntIndex()) then return end - local Volume = ExteriorVolume - InteriorVolume - local Mass = Volume * 0.13 -- Kg of steel per inch + TimerCreate("ACF Mass Buffer" .. self:EntIndex(), 5, 1, function() + if not IsValid(self) then return end - self.EmptyMass = Mass - end + UpdateMass(self) + end) + end +end --------------------------------------------- - self.HitBoxes = { - Main = { - Pos = self:OBBCenter(), - Scale = Size, - } - } +do -- Ammo Consumption ------------------------- + function ENT:CanConsume() + if self.Disabled then return false end + if not self.Load then return false end + if self.Damaged then return false end - self:UpdateOverlay() - end + return self.Ammo > 0 + end + + function ENT:Consume(Num) + self.Ammo = math.Clamp(self.Ammo - (Num or 1), 0, self.Capacity) + + self:UpdateOverlay() + self:UpdateMass() - function ENT:Detonate() - timer.Remove("ACF Crate Cookoff " .. self:EntIndex()) -- Prevent multiple explosions - self.Damaged = nil -- Prevent multiple explosions + WireLib.TriggerOutput(self, "Ammo", self.Ammo) + WireLib.TriggerOutput(self, "Loading", self:CanConsume() and 1 or 0) - local Pos = self:LocalToWorld(self:OBBCenter() + VectorRand() * (self:OBBMaxs() - self:OBBMins()) / 2) - local Filler = self.RoundType == "Refill" and 0.001 or self.BulletData.FillerMass or 0 - local Propellant = self.RoundType == "Refill" and 0.001 or self.BulletData.PropMass or 0 + if TimerExists("ACF Network Ammo " .. self:EntIndex()) then return end - local ExplosiveMass = (Filler + Propellant * (ACF.PBase / ACF.HEPower)) * self.Ammo - local FragMass = self.BulletData.ProjMass or ExplosiveMass * 0.5 + TimerCreate("ACF Network Ammo " .. self:EntIndex(), 0.5, 1, function() + if not IsValid(self) then return end - ACF_KillChildProps(self, Pos, ExplosiveMass) - ACF_HE(Pos, ExplosiveMass, FragMass, self.Inflictor, {self}, self) + self:SetNWInt("Ammo", self.Ammo) + end) + end +end --------------------------------------------- - local Effect = EffectData() - Effect:SetOrigin(Pos) - Effect:SetNormal(Vector(0, 0, -1)) - Effect:SetScale(math.max(ExplosiveMass ^ 0.33 * 8 * 39.37, 1)) - Effect:SetRadius(0) +do -- Misc -------------------------------------- + function ENT:Enable() + WireLib.TriggerOutput(self, "Loading", self:CanConsume() and 1 or 0) + + self:UpdateMass(true) + end + + function ENT:Disable() + WireLib.TriggerOutput(self, "Loading", 0) + + self:UpdateMass(true) + end - util.Effect("ACF_Explosion", Effect) + function ENT:OnResized(Size) + do -- Calculate new empty mass + local A = ACF.AmmoArmor * 0.039 -- Millimeters to inches + local ExteriorVolume = Size.x * Size.y * Size.z + local InteriorVolume = (Size.x - A) * (Size.y - A) * (Size.z - A) -- Math degree - constraint.RemoveAll(self) - self:Remove() + local Volume = ExteriorVolume - InteriorVolume + local Mass = Volume * 0.13 -- Kg of steel per inch + + self.EmptyMass = Mass end - function ENT:OnRemove() - ActiveCrates[self] = nil + self.HitBoxes = { + Main = { + Pos = self:OBBCenter(), + Scale = Size, + } + } + end - if self.SupplyingTo then - for Crate in pairs(self.SupplyingTo) do - Crate:RemoveCallOnRemove("ACF Refill " .. self:EntIndex()) + function ENT:OnRemove() + local Class = self.ClassData - self.SupplyingTo[Crate] = nil - end - end + if Class.OnLast then + Class.OnLast(self, Class) + end - if self.Damaged then -- Detonate immediately if cooking off - self:Detonate() - end + HookRun("ACF_OnEntityLast", "acf_ammo", self, Class) - for K in pairs(self.Weapons) do -- Unlink weapons - self:Unlink(K) - end + ActiveCrates[self] = nil - timer.Remove("ACF Refill " .. self:EntIndex()) - timer.Remove("ACF Crate Cookoff " .. self:EntIndex()) + if self.RoundData.OnLast then + self.RoundData:OnLast(self) + end + + self:Detonate() -- Detonate immediately if cooking off - WireLib.Remove(self) + for K in pairs(self.Weapons) do -- Unlink weapons + self:Unlink(K) end + + WireLib.Remove(self) end -end +end --------------------------------------------- diff --git a/lua/entities/acf_engine/init.lua b/lua/entities/acf_engine/init.lua index d332340a7..c83cda173 100644 --- a/lua/entities/acf_engine/init.lua +++ b/lua/entities/acf_engine/init.lua @@ -104,7 +104,7 @@ end local CheckLegal = ACF_CheckLegal local ClassLink = ACF.GetClassLink local ClassUnlink = ACF.GetClassUnlink -local Engines = ACF.Classes.Engines +local Engines = ACF.Classes.Engines local EngineTypes = ACF.Classes.EngineTypes local Inputs = ACF.GetInputActions("acf_engine") local UnlinkSound = "physics/metal/metal_box_impact_bullet%s.wav" @@ -114,6 +114,7 @@ local TimerCreate = timer.Create local TimerExists = timer.Exists local TimerSimple = timer.Simple local TimerRemove = timer.Remove +local HookRun = hook.Run local Gamemode = GetConVar("acf_gamemode") -- Fuel consumption is increased on competitive servers @@ -229,8 +230,6 @@ end --===============================================================================================-- do -- Spawn and Update functions - local HookRun = hook.Run - local function VerifyData(Data) -- Entity was created via menu tool if Data.Engine then diff --git a/lua/entities/acf_gun/init.lua b/lua/entities/acf_gun/init.lua index 36951bd3c..6f631a08a 100644 --- a/lua/entities/acf_gun/init.lua +++ b/lua/entities/acf_gun/init.lua @@ -252,12 +252,12 @@ do -- Metamethods -------------------------------- ACF.RegisterClassLink("acf_gun", "acf_ammo", function(Weapon, Target) if Weapon.Crates[Target] then return false, "This weapon is already linked to this crate." end if Target.Weapons[Weapon] then return false, "This weapon is already linked to this crate." end - if Target.RoundType == "Refill" then return false, "Refill crates cannot be linked to weapons." end - if Weapon.Id ~= Target.BulletData.Id then return false, "Wrong ammo type for this weapon." end + if Target.IsRefill then return false, "Refill crates cannot be linked to weapons." end + if Weapon.Id ~= Target.Weapon then return false, "Wrong ammo type for this weapon." end - local Blacklist = ACF.AmmoBlacklist[Target.RoundType] + local Blacklist = Target.RoundData.Blacklist - if table.HasValue(Blacklist, Weapon.Class) then + if Blacklist[Weapon.Class] then return false, "The ammo type in this crate cannot be used for this weapon." end diff --git a/lua/entities/gmod_wire_expression2/core/custom/acffunctions.lua b/lua/entities/gmod_wire_expression2/core/custom/acffunctions.lua index 3ba3b35e2..dd18be4f6 100644 --- a/lua/entities/gmod_wire_expression2/core/custom/acffunctions.lua +++ b/lua/entities/gmod_wire_expression2/core/custom/acffunctions.lua @@ -961,7 +961,7 @@ e2function string entity:acfRoundType() if not IsACFEntity(this) then return "" end if RestrictInfo(self, this) then return "" end - return this.RoundType or "" + return this.AmmoType or "" end -- Returns the type of ammo in a crate or gun diff --git a/lua/starfall/libs_sv/acffunctions.lua b/lua/starfall/libs_sv/acffunctions.lua index 75141070d..f649095d0 100644 --- a/lua/starfall/libs_sv/acffunctions.lua +++ b/lua/starfall/libs_sv/acffunctions.lua @@ -853,9 +853,9 @@ function ents_methods:acfNameShort () if isEngine( this ) then return this.Id or "" end if isGearbox( this ) then return this.Id or "" end if isGun( this ) then return this.Id or "" end - if isAmmo( this ) then return this.RoundId or "" end + if isAmmo( this ) then return this.Weapon or "" end if isFuel( this ) then return this.FuelType .. " " .. this.SizeId end - + return "" end @@ -985,7 +985,7 @@ function ents_methods:acfName () if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end - if isAmmo( this ) then return ( this.RoundId .. " " .. this.RoundType) end + if isAmmo( this ) then return this.Weapon .. " " .. this.AmmoType end if isFuel( this ) then return this.FuelType .. " " .. this.SizeId end local acftype = "" @@ -1013,7 +1013,7 @@ function ents_methods:acfType () local Classes = list.Get( "ACFClasses" ) return Classes[ "GunClass" ][ this.Class ][ "name" ] or "" end - if isAmmo( this ) then return this.RoundType or "" end + if isAmmo( this ) then return this.AmmoType or "" end if isFuel( this ) then return this.FuelType or "" end return "" end @@ -1936,8 +1936,8 @@ function ents_methods:acfRoundType () --cartridge? if not isAmmo( this ) then return "" end if restrictInfo( this ) then return "" end - --return this.RoundId or "" - return this.RoundType or "" -- E2 uses this one now + + return this.AmmoType or "" -- E2 uses this one now end --- Returns the type of ammo in a crate or gun From 953ee5c1448ff9716b97853f3907b6892f80cfe3 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sat, 7 Nov 2020 19:39:38 -0300 Subject: [PATCH 139/279] Added ACF.CheckNumber function - Added shared ACF.CheckNumber function to convert any value to a number, including nil. If the conversion failed, this function will return nil. --- lua/acf/base/util/sh_util.lua | 6 ++++++ lua/acf/shared/gearboxes/3-auto.lua | 14 ++++---------- lua/acf/shared/gearboxes/5-auto.lua | 14 ++++---------- lua/acf/shared/gearboxes/7-auto.lua | 14 ++++---------- lua/acf/shared/gearboxes/cvt.lua | 10 ++-------- lua/entities/acf_gearbox/init.lua | 14 ++++---------- 6 files changed, 24 insertions(+), 48 deletions(-) diff --git a/lua/acf/base/util/sh_util.lua b/lua/acf/base/util/sh_util.lua index 98c76df69..50f098862 100644 --- a/lua/acf/base/util/sh_util.lua +++ b/lua/acf/base/util/sh_util.lua @@ -313,6 +313,12 @@ do -- Sound aliases end end +function ACF.CheckNumber(Value) + if not Value then return end + + return tonumber(Value) +end + do -- Parentable Wire model list local WireModels = { ["models/blacknecro/ledboard60.mdl"] = true, diff --git a/lua/acf/shared/gearboxes/3-auto.lua b/lua/acf/shared/gearboxes/3-auto.lua index 118781c1d..4937fbbd6 100644 --- a/lua/acf/shared/gearboxes/3-auto.lua +++ b/lua/acf/shared/gearboxes/3-auto.lua @@ -18,12 +18,6 @@ local ShiftS = 0.25 local ShiftM = 0.35 local ShiftL = 0.5 -local function CheckNumber(Value) - if not Value then return end -- nil or false, both are not numbers - - return tonumber(Value) -end - local function InitGearbox(Gearbox) local Gears = Gearbox.Gears @@ -66,7 +60,7 @@ ACF.RegisterGearboxClass("3-Auto", { if Count > Max then break end - Points[Count] = CheckNumber(Point) or Count * 100 + Points[Count] = ACF.CheckNumber(Point) or Count * 100 end end @@ -76,7 +70,7 @@ ACF.RegisterGearboxClass("3-Auto", { end for I = 1, Max do - local Point = CheckNumber(Points[I]) + local Point = ACF.CheckNumber(Points[I]) if not Point then Point = (CheckNumber(Data["Shift" .. I]) or I * 100) * Mult @@ -89,10 +83,10 @@ ACF.RegisterGearboxClass("3-Auto", { end do -- Reverse gear verification - local Reverse = CheckNumber(Data.Reverse) + local Reverse = ACF.CheckNumber(Data.Reverse) if not Reverse then - Reverse = CheckNumber(Data.Gear8) or -1 + Reverse = ACF.CheckNumber(Data.Gear8) or -1 Data.Gear8 = nil end diff --git a/lua/acf/shared/gearboxes/5-auto.lua b/lua/acf/shared/gearboxes/5-auto.lua index 30c510a9d..4ce3d6c32 100644 --- a/lua/acf/shared/gearboxes/5-auto.lua +++ b/lua/acf/shared/gearboxes/5-auto.lua @@ -18,12 +18,6 @@ local ShiftS = 0.25 local ShiftM = 0.35 local ShiftL = 0.5 -local function CheckNumber(Value) - if not Value then return end -- nil or false, both are not numbers - - return tonumber(Value) -end - local function InitGearbox(Gearbox) local Gears = Gearbox.Gears @@ -65,7 +59,7 @@ ACF.RegisterGearboxClass("5-Auto", { if Count > Max then break end - Points[Count] = CheckNumber(Point) or Count * 100 + Points[Count] = ACF.CheckNumber(Point) or Count * 100 end end @@ -75,7 +69,7 @@ ACF.RegisterGearboxClass("5-Auto", { end for I = 1, Max do - local Point = CheckNumber(Points[I]) + local Point = ACF.CheckNumber(Points[I]) if not Point then Point = (CheckNumber(Data["Shift" .. I]) or I * 100) * Mult @@ -88,10 +82,10 @@ ACF.RegisterGearboxClass("5-Auto", { end do -- Reverse gear verification - local Reverse = CheckNumber(Data.Reverse) + local Reverse = ACF.CheckNumber(Data.Reverse) if not Reverse then - Reverse = CheckNumber(Data.Gear8) or -1 + Reverse = ACF.CheckNumber(Data.Gear8) or -1 Data.Gear8 = nil end diff --git a/lua/acf/shared/gearboxes/7-auto.lua b/lua/acf/shared/gearboxes/7-auto.lua index db3f57df1..90828c756 100644 --- a/lua/acf/shared/gearboxes/7-auto.lua +++ b/lua/acf/shared/gearboxes/7-auto.lua @@ -18,12 +18,6 @@ local ShiftS = 0.25 local ShiftM = 0.35 local ShiftL = 0.5 -local function CheckNumber(Value) - if not Value then return end -- nil or false, both are not numbers - - return tonumber(Value) -end - local function InitGearbox(Gearbox) local Gears = Gearbox.Gears @@ -65,7 +59,7 @@ ACF.RegisterGearboxClass("7-Auto", { if Count > Max then break end - Points[Count] = CheckNumber(Point) or Count * 100 + Points[Count] = ACF.CheckNumber(Point) or Count * 100 end end @@ -75,7 +69,7 @@ ACF.RegisterGearboxClass("7-Auto", { end for I = 1, Max do - local Point = CheckNumber(Points[I]) + local Point = ACF.CheckNumber(Points[I]) if not Point then Point = (CheckNumber(Data["Shift" .. I]) or I * 100) * Mult @@ -88,10 +82,10 @@ ACF.RegisterGearboxClass("7-Auto", { end do -- Reverse gear verification - local Reverse = CheckNumber(Data.Reverse) + local Reverse = ACF.CheckNumber(Data.Reverse) if not Reverse then - Reverse = CheckNumber(Data.Gear8) or -1 + Reverse = ACF.CheckNumber(Data.Gear8) or -1 Data.Gear8 = nil end diff --git a/lua/acf/shared/gearboxes/cvt.lua b/lua/acf/shared/gearboxes/cvt.lua index 6675f1ea5..b697f5e5e 100644 --- a/lua/acf/shared/gearboxes/cvt.lua +++ b/lua/acf/shared/gearboxes/cvt.lua @@ -323,12 +323,6 @@ ACF_DefineGearbox("CVT-ST-L", { } }) -local function CheckNumber(Value) - if not Value then return end -- nil or false, both are not numbers - - return tonumber(Value) -end - local function InitGearbox(Gearbox) local Gears = Gearbox.Gears @@ -354,13 +348,13 @@ ACF.RegisterGearboxClass("CVT", { Data.Gears[1] = 0.01 if not Min then - Min = CheckNumber(Data.Gear3) or 3000 + Min = ACF.CheckNumber(Data.Gear3) or 3000 Data.Gear3 = nil end if not Max then - Max = CheckNumber(Data.Gear4) or 5000 + Max = ACF.CheckNumber(Data.Gear4) or 5000 Data.Gear4 = nil end diff --git a/lua/entities/acf_gearbox/init.lua b/lua/entities/acf_gearbox/init.lua index 4ad77a7e3..f335b07a6 100644 --- a/lua/entities/acf_gearbox/init.lua +++ b/lua/entities/acf_gearbox/init.lua @@ -209,12 +209,6 @@ end --===============================================================================================-- do -- Spawn and Update functions - local function CheckNumber(Value) - if not Value then return end -- nil or false, both are not numbers - - return tonumber(Value) - end - local function VerifyData(Data) if not Data.Gearbox then Data.Gearbox = Data.Id or "2Gear-T-S" @@ -240,10 +234,10 @@ do -- Spawn and Update functions end for I = 1, Class.Gears.Max do - local Gear = CheckNumber(Gears[I]) + local Gear = ACF.CheckNumber(Gears[I]) if not Gear then - Gear = CheckNumber(Data["Gear" .. I]) or I * 0.1 + Gear = ACF.CheckNumber(Data["Gear" .. I]) or I * 0.1 Data["Gear" .. I] = nil end @@ -253,10 +247,10 @@ do -- Spawn and Update functions end do -- Final drive verification - local Final = CheckNumber(Data.FinalDrive) + local Final = ACF.CheckNumber(Data.FinalDrive) if not Final then - Final = CheckNumber(Data.Gear0) or 1 + Final = ACF.CheckNumber(Data.Gear0) or 1 Data.Gear0 = nil end From 0d87c7c85ffa5d20264693c1f227eb66e0cbdebb Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sat, 7 Nov 2020 20:23:56 -0300 Subject: [PATCH 140/279] Added ammo type data hooks - Added shared ACF_GetDisplayData hook, called whenever the display data of an ammo type is requested. - Added shared ACF_UpdateRoundData hook, called whenever the stats of a bullet are updated. - Added ENT.IsAmmoCrate flag on ammo crate entities. - The spawn menu will now reset the Destiny tool value. --- lua/acf/client/cl_spawn_menu.lua | 1 + lua/acf/shared/ammo_types/ap.lua | 15 ++++++++++----- lua/acf/shared/ammo_types/apcr.lua | 2 ++ lua/acf/shared/ammo_types/apds.lua | 2 ++ lua/acf/shared/ammo_types/apfsds.lua | 2 ++ lua/acf/shared/ammo_types/aphe.lua | 20 ++++++++++++-------- lua/acf/shared/ammo_types/fl.lua | 15 ++++++++++----- lua/acf/shared/ammo_types/he.lua | 17 +++++++++++------ lua/acf/shared/ammo_types/heat.lua | 23 ++++++++++++++--------- lua/acf/shared/ammo_types/heatfs.lua | 2 ++ lua/acf/shared/ammo_types/hp.lua | 14 +++++++++----- lua/acf/shared/ammo_types/refill.lua | 4 ++++ lua/acf/shared/ammo_types/smoke.lua | 25 +++++++++++++++---------- lua/entities/acf_ammo/shared.lua | 3 ++- 14 files changed, 96 insertions(+), 49 deletions(-) diff --git a/lua/acf/client/cl_spawn_menu.lua b/lua/acf/client/cl_spawn_menu.lua index 890785422..78f2273b1 100644 --- a/lua/acf/client/cl_spawn_menu.lua +++ b/lua/acf/client/cl_spawn_menu.lua @@ -204,6 +204,7 @@ do -- ACF Menu context panel self.Selected = Node ACF.SetToolMode("acf_menu2", "Main", "Idle") + ACF.WriteValue("Destiny") Menu:ClearTemporal() Menu:StartTemporal() diff --git a/lua/acf/shared/ammo_types/ap.lua b/lua/acf/shared/ammo_types/ap.lua index 258131e71..ad6a655de 100644 --- a/lua/acf/shared/ammo_types/ap.lua +++ b/lua/acf/shared/ammo_types/ap.lua @@ -11,12 +11,15 @@ function Ammo:OnLoaded() } end -function Ammo:GetDisplayData(BulletData) - local Energy = ACF_Kinetic(BulletData.MuzzleVel * 39.37, BulletData.ProjMass, BulletData.LimitVel) - - return { - MaxPen = (Energy.Penetration / BulletData.PenArea) * ACF.KEtoRHA +function Ammo:GetDisplayData(Data) + local Energy = ACF_Kinetic(Data.MuzzleVel * 39.37, Data.ProjMass, Data.LimitVel) + local Display = { + MaxPen = (Energy.Penetration / Data.PenArea) * ACF.KEtoRHA } + + hook.Run("ACF_GetDisplayData", self, Data, Display) + + return Display end function Ammo:UpdateRoundData(ToolData, Data, GUIData) @@ -29,6 +32,8 @@ function Ammo:UpdateRoundData(ToolData, Data, GUIData) Data.DragCoef = Data.FrArea * 0.0001 / Data.ProjMass Data.CartMass = Data.PropMass + Data.ProjMass + hook.Run("ACF_UpdateRoundData", self, ToolData, Data, GUIData) + for K, V in pairs(self:GetDisplayData(Data)) do GUIData[K] = V end diff --git a/lua/acf/shared/ammo_types/apcr.lua b/lua/acf/shared/ammo_types/apcr.lua index 174025dcd..65f313917 100644 --- a/lua/acf/shared/ammo_types/apcr.lua +++ b/lua/acf/shared/ammo_types/apcr.lua @@ -25,6 +25,8 @@ function Ammo:UpdateRoundData(ToolData, Data, GUIData) Data.DragCoef = (Data.FrArea * 0.000125) / Data.ProjMass -- Worse drag (Manually fudged to make a meaningful difference) Data.CartMass = Data.PropMass + Data.ProjMass + hook.Run("ACF_UpdateRoundData", self, ToolData, Data, GUIData) + for K, V in pairs(self:GetDisplayData(Data)) do GUIData[K] = V end diff --git a/lua/acf/shared/ammo_types/apds.lua b/lua/acf/shared/ammo_types/apds.lua index 891f0d4c1..fb9128cc8 100644 --- a/lua/acf/shared/ammo_types/apds.lua +++ b/lua/acf/shared/ammo_types/apds.lua @@ -28,6 +28,8 @@ function Ammo:UpdateRoundData(ToolData, Data, GUIData) Data.DragCoef = Data.RoundArea * 0.0001 / Data.ProjMass Data.CartMass = Data.PropMass + Data.ProjMass + SabotMass + hook.Run("ACF_UpdateRoundData", self, ToolData, Data, GUIData) + for K, V in pairs(self:GetDisplayData(Data)) do GUIData[K] = V end diff --git a/lua/acf/shared/ammo_types/apfsds.lua b/lua/acf/shared/ammo_types/apfsds.lua index 9e03fe30e..567fa4f06 100644 --- a/lua/acf/shared/ammo_types/apfsds.lua +++ b/lua/acf/shared/ammo_types/apfsds.lua @@ -25,6 +25,8 @@ function Ammo:UpdateRoundData(ToolData, Data, GUIData) Data.DragCoef = Data.FrArea * 0.0001 / Data.ProjMass Data.CartMass = Data.PropMass + Data.ProjMass + SabotMass + hook.Run("ACF_UpdateRoundData", self, ToolData, Data, GUIData) + for K, V in pairs(self:GetDisplayData(Data)) do GUIData[K] = V end diff --git a/lua/acf/shared/ammo_types/aphe.lua b/lua/acf/shared/ammo_types/aphe.lua index ed4093933..073a02f32 100644 --- a/lua/acf/shared/ammo_types/aphe.lua +++ b/lua/acf/shared/ammo_types/aphe.lua @@ -13,16 +13,18 @@ function Ammo:OnLoaded() } end -function Ammo:GetDisplayData(BulletData) - local Data = Ammo.BaseClass.GetDisplayData(self, BulletData) - local FragMass = BulletData.ProjMass - BulletData.FillerMass +function Ammo:GetDisplayData(Data) + local Display = Ammo.BaseClass.GetDisplayData(self, Data) + local FragMass = Data.ProjMass - Data.FillerMass - Data.BlastRadius = BulletData.FillerMass ^ 0.33 * 8 - Data.Fragments = math.max(math.floor((BulletData.FillerMass / FragMass) * ACF.HEFrag), 2) - Data.FragMass = FragMass / Data.Fragments - Data.FragVel = (BulletData.FillerMass * ACF.HEPower * 1000 / Data.FragMass / Data.Fragments) ^ 0.5 + Display.BlastRadius = Data.FillerMass ^ 0.33 * 8 + Display.Fragments = math.max(math.floor((Data.FillerMass / FragMass) * ACF.HEFrag), 2) + Display.FragMass = FragMass / Display.Fragments + Display.FragVel = (Data.FillerMass * ACF.HEPower * 1000 / Display.FragMass / Display.Fragments) ^ 0.5 - return Data + hook.Run("ACF_GetDisplayData", self, Data, Display) + + return Display end function Ammo:UpdateRoundData(ToolData, Data, GUIData) @@ -46,6 +48,8 @@ function Ammo:UpdateRoundData(ToolData, Data, GUIData) Data.DragCoef = Data.FrArea * 0.0001 / Data.ProjMass Data.CartMass = Data.PropMass + Data.ProjMass + hook.Run("ACF_UpdateRoundData", self, ToolData, Data, GUIData) + for K, V in pairs(self:GetDisplayData(Data)) do GUIData[K] = V end diff --git a/lua/acf/shared/ammo_types/fl.lua b/lua/acf/shared/ammo_types/fl.lua index 2b92c8f0d..c65e1f460 100644 --- a/lua/acf/shared/ammo_types/fl.lua +++ b/lua/acf/shared/ammo_types/fl.lua @@ -16,12 +16,15 @@ function Ammo:OnLoaded() } end -function Ammo:GetDisplayData(BulletData) - local Energy = ACF_Kinetic(BulletData.MuzzleVel * 39.37, BulletData.FlechetteMass, BulletData.LimitVel) - - return { - MaxPen = (Energy.Penetration / BulletData.FlechettePenArea) * ACF.KEtoRHA +function Ammo:GetDisplayData(Data) + local Energy = ACF_Kinetic(Data.MuzzleVel * 39.37, Data.FlechetteMass, Data.LimitVel) + local Display = { + MaxPen = (Energy.Penetration / Data.FlechettePenArea) * ACF.KEtoRHA } + + hook.Run("ACF_GetDisplayData", self, Data, Display) + + return Display end function Ammo:UpdateRoundData(ToolData, Data, GUIData) @@ -46,6 +49,8 @@ function Ammo:UpdateRoundData(ToolData, Data, GUIData) Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass) Data.CartMass = Data.PropMass + Data.ProjMass + hook.Run("ACF_UpdateRoundData", self, ToolData, Data, GUIData) + for K, V in pairs(self:GetDisplayData(Data)) do GUIData[K] = V end diff --git a/lua/acf/shared/ammo_types/he.lua b/lua/acf/shared/ammo_types/he.lua index 6007fd7e9..e7f475d75 100644 --- a/lua/acf/shared/ammo_types/he.lua +++ b/lua/acf/shared/ammo_types/he.lua @@ -14,13 +14,16 @@ end function Ammo:GetDisplayData(Data) local FragMass = Data.ProjMass - Data.FillerMass local Fragments = math.max(math.floor((Data.FillerMass / FragMass) * ACF.HEFrag), 2) - - return { - BlastRadius = Data.FillerMass ^ 0.33 * 8, - Fragments = Fragments, - FragMass = FragMass / Fragments, - FragVel = (Data.FillerMass * ACF.HEPower * 1000 / FragMass / Fragments / Fragments) ^ 0.5, + local Display = { + BlastRadius = Data.FillerMass ^ 0.33 * 8, + Fragments = Fragments, + FragMass = FragMass / Fragments, + FragVel = (Data.FillerMass * ACF.HEPower * 1000 / FragMass / Fragments / Fragments) ^ 0.5, } + + hook.Run("ACF_GetDisplayData", self, Data, Display) + + return Display end function Ammo:UpdateRoundData(ToolData, Data, GUIData) @@ -44,6 +47,8 @@ function Ammo:UpdateRoundData(ToolData, Data, GUIData) Data.DragCoef = Data.FrArea * 0.0001 / Data.ProjMass Data.CartMass = Data.PropMass + Data.ProjMass + hook.Run("ACF_UpdateRoundData", self, ToolData, Data, GUIData) + for K, V in pairs(self:GetDisplayData(Data)) do GUIData[K] = V end diff --git a/lua/acf/shared/ammo_types/heat.lua b/lua/acf/shared/ammo_types/heat.lua index 15972021a..c697ad066 100644 --- a/lua/acf/shared/ammo_types/heat.lua +++ b/lua/acf/shared/ammo_types/heat.lua @@ -47,20 +47,23 @@ function Ammo:GetDisplayData(Data) local Energy = ACF_Kinetic(Data.MuzzleVel * 39.37 + SlugMV * 39.37, MassUsed, 999999) local FragMass = Data.CasingMass + Data.SlugMass * Crushed local Fragments = math.max(math.floor((BoomFiller / FragMass) * ACF.HEFrag), 2) - - return { - Crushed = Crushed, + local Display = { + Crushed = Crushed, HEATFillerMass = HEATFiller, BoomFillerMass = BoomFiller, - SlugMV = SlugMV, + SlugMV = SlugMV, SlugMassUsed = MassUsed, - MaxPen = (Energy.Penetration / Data.SlugPenArea) * ACF.KEtoRHA, + MaxPen = (Energy.Penetration / Data.SlugPenArea) * ACF.KEtoRHA, TotalFragMass = FragMass, - BlastRadius = BoomFiller ^ 0.33 * 8, - Fragments = Fragments, - FragMass = FragMass / Fragments, - FragVel = (BoomFiller * ACF.HEPower * 1000 / FragMass) ^ 0.5, + BlastRadius = BoomFiller ^ 0.33 * 8, + Fragments = Fragments, + FragMass = FragMass / Fragments, + FragVel = (BoomFiller * ACF.HEPower * 1000 / FragMass) ^ 0.5, } + + hook.Run("ACF_GetDisplayData", self, Data, Display) + + return Display end function Ammo:UpdateRoundData(ToolData, Data, GUIData) @@ -102,6 +105,8 @@ function Ammo:UpdateRoundData(ToolData, Data, GUIData) Data.DragCoef = Data.FrArea * 0.0001 / Data.ProjMass Data.CartMass = Data.PropMass + Data.ProjMass + hook.Run("ACF_UpdateRoundData", self, ToolData, Data, GUIData) + for K, V in pairs(self:GetDisplayData(Data)) do GUIData[K] = V end diff --git a/lua/acf/shared/ammo_types/heatfs.lua b/lua/acf/shared/ammo_types/heatfs.lua index 187d886cb..711a9a18d 100644 --- a/lua/acf/shared/ammo_types/heatfs.lua +++ b/lua/acf/shared/ammo_types/heatfs.lua @@ -49,6 +49,8 @@ function Ammo:UpdateRoundData(ToolData, Data, GUIData) Data.DragCoef = Data.FrArea * 0.0001 / Data.ProjMass Data.CartMass = Data.PropMass + Data.ProjMass + hook.Run("ACF_UpdateRoundData", self, ToolData, Data, GUIData) + for K, V in pairs(self:GetDisplayData(Data)) do GUIData[K] = V end diff --git a/lua/acf/shared/ammo_types/hp.lua b/lua/acf/shared/ammo_types/hp.lua index b68126dda..3028953e6 100644 --- a/lua/acf/shared/ammo_types/hp.lua +++ b/lua/acf/shared/ammo_types/hp.lua @@ -7,13 +7,15 @@ function Ammo:OnLoaded() self.Description = "A round with a hollow cavity, meant to flatten against surfaces on impact." end -function Ammo:GetDisplayData(BulletData) - local Data = Ammo.BaseClass.GetDisplayData(self, BulletData) - local Energy = ACF_Kinetic(BulletData.MuzzleVel * 39.37, BulletData.ProjMass, BulletData.LimitVel) +function Ammo:GetDisplayData(Data) + local Display = Ammo.BaseClass.GetDisplayData(self, Data) + local Energy = ACF_Kinetic(Data.MuzzleVel * 39.37, Data.ProjMass, Data.LimitVel) - Data.MaxKETransfert = Energy.Kinetic * BulletData.ShovePower + Display.MaxKETransfert = Energy.Kinetic * Data.ShovePower - return Data + hook.Run("ACF_GetDisplayData", self, Data, Display) + + return Display end function Ammo:UpdateRoundData(ToolData, Data, GUIData) @@ -40,6 +42,8 @@ function Ammo:UpdateRoundData(ToolData, Data, GUIData) Data.DragCoef = Data.FrArea * 0.0001 / Data.ProjMass Data.CartMass = Data.PropMass + Data.ProjMass + hook.Run("ACF_UpdateRoundData", self, ToolData, Data, GUIData) + for K, V in pairs(self:GetDisplayData(Data)) do GUIData[K] = V end diff --git a/lua/acf/shared/ammo_types/refill.lua b/lua/acf/shared/ammo_types/refill.lua index 56ff00213..767185f2e 100644 --- a/lua/acf/shared/ammo_types/refill.lua +++ b/lua/acf/shared/ammo_types/refill.lua @@ -106,6 +106,8 @@ if SERVER then end function Ammo:OnFirst(Entity) + if not Entity.IsAmmoCrate then return end + if not Entity.SupplyingTo then Entity.SupplyingTo = {} end @@ -120,6 +122,8 @@ if SERVER then end function Ammo:OnLast(Entity) + if not Entity.IsRefill then return end + local CallName = "ACF Refill " .. Entity:EntIndex() for Crate in pairs(Entity.SupplyingTo) do diff --git a/lua/acf/shared/ammo_types/smoke.lua b/lua/acf/shared/ammo_types/smoke.lua index 52bfb73e3..bb2d29933 100644 --- a/lua/acf/shared/ammo_types/smoke.lua +++ b/lua/acf/shared/ammo_types/smoke.lua @@ -19,17 +19,20 @@ end function Ammo:GetDisplayData(Data) local SMFiller = math.min(math.log(1 + Data.FillerMass * 8 * 39.37) * 43.4216, 350) local WPFiller = math.min(math.log(1 + Data.WPMass * 8 * 39.37) * 43.4216, 350) - - return { - SMFiller = SMFiller, - SMLife = math.Round(20 + SMFiller * 0.25, 2), - SMRadiusMin = math.Round(SMFiller * 1.25 * 0.15 * 0.0254, 2), - SMRadiusMax = math.Round(SMFiller * 1.25 * 2 * 0.0254, 2), - WPFiller = WPFiller, - WPLife = math.Round(6 + WPFiller * 0.1, 2), - WPRadiusMin = math.Round(WPFiller * 1.25 * 0.0254, 2), - WPRadiusMax = math.Round(WPFiller * 1.25 * 2 * 0.0254, 2), + local Display = { + SMFiller = SMFiller, + SMLife = math.Round(20 + SMFiller * 0.25, 2), + SMRadiusMin = math.Round(SMFiller * 1.25 * 0.15 * 0.0254, 2), + SMRadiusMax = math.Round(SMFiller * 1.25 * 2 * 0.0254, 2), + WPFiller = WPFiller, + WPLife = math.Round(6 + WPFiller * 0.1, 2), + WPRadiusMin = math.Round(WPFiller * 1.25 * 0.0254, 2), + WPRadiusMax = math.Round(WPFiller * 1.25 * 2 * 0.0254, 2), } + + hook.Run("ACF_GetDisplayData", self, Data, Display) + + return Display end function Ammo:UpdateRoundData(ToolData, Data, GUIData) @@ -65,6 +68,8 @@ function Ammo:UpdateRoundData(ToolData, Data, GUIData) Data.DragCoef = Data.FrArea * 0.0001 / Data.ProjMass Data.CartMass = Data.PropMass + Data.ProjMass + hook.Run("ACF_UpdateRoundData", self, ToolData, Data, GUIData) + for K, V in pairs(self:GetDisplayData(Data)) do GUIData[K] = V end diff --git a/lua/entities/acf_ammo/shared.lua b/lua/entities/acf_ammo/shared.lua index 78844338f..c4d867fef 100644 --- a/lua/entities/acf_ammo/shared.lua +++ b/lua/entities/acf_ammo/shared.lua @@ -1,4 +1,5 @@ DEFINE_BASECLASS("base_scalable_box") ENT.PrintName = "ACF Ammo Crate" -ENT.WireDebugName = "ACF Ammo Crate" \ No newline at end of file +ENT.WireDebugName = "ACF Ammo Crate" +ENT.IsAmmoCrate = true \ No newline at end of file From 3ecba2488bdcedddf989b71b25ece9b1b8454a56 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Mon, 9 Nov 2020 03:36:23 -0300 Subject: [PATCH 141/279] Changed argument order on ammo event hooks - ACF_OnAmmoFirst and ACF_OnAmmoLast functions will now take the ammo type table as the first argument instead of the entity, which will now be the second argument. - ACF_OnAmmoFirst will now receive the Data table as the third argument. --- lua/entities/acf_ammo/init.lua | 17 +++++++++-------- lua/entities/acf_gun/init.lua | 13 ++++++++----- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/lua/entities/acf_ammo/init.lua b/lua/entities/acf_ammo/init.lua index eea2735b3..7c5c9a42e 100644 --- a/lua/entities/acf_ammo/init.lua +++ b/lua/entities/acf_ammo/init.lua @@ -258,12 +258,13 @@ do -- Spawning and Updating -------------------- local function UpdateCrate(Entity, Data, Class, Weapon, Ammo) local Name, ShortName, WireName = Ammo:GetCrateName() - Entity.Name = Name or Weapon.Name .. " " .. Ammo.Name - Entity.ShortName = ShortName or Weapon.ID .. " " .. Ammo.ID - Entity.EntType = "Ammo Crate" - Entity.ClassData = Class - Entity.Caliber = Weapon.Caliber - Entity.Class = Class.ID + Entity.Name = Name or Weapon.Name .. " " .. Ammo.Name + Entity.ShortName = ShortName or Weapon.ID .. " " .. Ammo.ID + Entity.EntType = "Ammo Crate" + Entity.ClassData = Class + Entity.WeaponData = Weapon + Entity.Caliber = Weapon.Caliber + Entity.Class = Class.ID Entity:SetNWString("WireName", "ACF " .. (WireName or Weapon.Name .. " Ammo Crate")) Entity:SetSize(Data.Size) @@ -276,7 +277,7 @@ do -- Spawning and Updating -------------------- OldAmmo:OnLast(Entity) end - HookRun("ACF_OnAmmoLast", Entity, OldAmmo) + HookRun("ACF_OnAmmoLast", OldAmmo, Entity) end Entity.RoundData = Ammo @@ -287,7 +288,7 @@ do -- Spawning and Updating -------------------- Ammo:OnFirst(Entity) end - HookRun("ACF_OnAmmoFirst", Entity, Ammo, Class, Weapon) + HookRun("ACF_OnAmmoFirst", Ammo, Entity, Data, Class, Weapon) Ammo:Network(Entity, Entity.BulletData) end diff --git a/lua/entities/acf_gun/init.lua b/lua/entities/acf_gun/init.lua index 6f631a08a..f6beef95a 100644 --- a/lua/entities/acf_gun/init.lua +++ b/lua/entities/acf_gun/init.lua @@ -5,13 +5,15 @@ include("shared.lua") -- Local Vars ----------------------------------- +local ACF = ACF local ACF_RECOIL = GetConVar("acf_recoilpush") local UnlinkSound = "physics/metal/metal_box_impact_bullet%s.wav" local CheckLegal = ACF_CheckLegal local Shove = ACF.KEShove local Overpressure = ACF.Overpressure -local Weapons = ACF.Classes.Weapons -local Inputs = ACF.GetInputActions("acf_gun") +local Weapons = ACF.Classes.Weapons +local AmmoTypes = ACF.Classes.AmmoTypes +local Inputs = ACF.GetInputActions("acf_gun") local TraceRes = {} -- Output for traces local TraceData = {start = true, endpos = true, filter = true, mask = MASK_SOLID, output = TraceRes} local Trace = util.TraceLine @@ -80,11 +82,12 @@ do -- Spawn and Update functions -------------------------------- end Entity.Name = Weapon.Name - Entity.ShortName = Entity.Id + Entity.ShortName = Weapon.ID Entity.EntType = Class.Name Entity.ClassData = Class - Entity.Caliber = Caliber + Entity.WeaponData = Weapon Entity.Class = Class.ID -- Needed for custom killicons + Entity.Caliber = Caliber Entity.MagReload = Weapon.MagReload Entity.MagSize = Weapon.MagSize or 1 Entity.Cyclic = Weapon.Cyclic and 60 / Weapon.Cyclic @@ -487,7 +490,7 @@ do -- Metamethods -------------------------------- self.BulletData.Fuze = self.Fuze -- Must be set when firing as the table is shared self.BulletData.Filter = self.BarrelFilter - ACF.RoundTypes[self.BulletData.Type].create(self, self.BulletData) -- Spawn projectile + AmmoTypes[self.BulletData.Type]:Create(self, self.BulletData) -- Spawn projectile self:MuzzleEffect() self:Recoil() From 4ce43f116ab669fd620de3fbb9c89149e2969b7f Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Mon, 9 Nov 2020 23:03:49 -0300 Subject: [PATCH 142/279] Solved conflicts from latest branch merge - Solved a bunch of conflicts from the latest branch merge. - Marked a few functions for replacement or deletion. --- lua/acf/base/acf_globals.lua | 9 +- lua/acf/client/sk_menu.lua | 16 ++-- lua/acf/shared/ammo_types/apcr.lua | 1 - lua/acf/shared/ammo_types/apds.lua | 1 - lua/acf/shared/ammo_types/fl.lua | 2 +- lua/acf/shared/ammo_types/heat.lua | 22 ++--- lua/acf/shared/guns/autocannon.lua | 8 +- lua/acf/shared/guns/autoloader.lua | 8 +- lua/acf/shared/guns/cannon.lua | 10 +- lua/acf/shared/guns/grenadelauncher.lua | 4 +- lua/acf/shared/guns/heavymachinegun.lua | 9 +- lua/acf/shared/guns/howitzer.lua | 9 +- lua/acf/shared/guns/machinegun.lua | 29 ++++-- lua/acf/shared/guns/mortar.lua | 9 +- lua/acf/shared/guns/rotaryautocannon.lua | 5 +- lua/acf/shared/guns/semiauto.lua | 9 +- lua/acf/shared/guns/shortcannon.lua | 9 +- lua/acf/shared/guns/smokelauncher.lua | 26 +---- lua/acf/shared/guns/smoothbore.lua | 8 +- lua/acf/shared/rounds/ap.lua | 4 +- lua/acf/shared/rounds/apcr.lua | 2 +- lua/acf/shared/rounds/apds.lua | 2 +- lua/acf/shared/rounds/apfsds.lua | 2 +- lua/acf/shared/rounds/aphe.lua | 2 +- lua/acf/shared/rounds/fl.lua | 2 +- lua/acf/shared/rounds/he.lua | 2 +- lua/acf/shared/rounds/heat.lua | 2 +- lua/acf/shared/rounds/heatfs.lua | 2 +- lua/acf/shared/rounds/hp.lua | 2 +- lua/acf/shared/rounds/refill.lua | 2 +- lua/acf/shared/rounds/smoke.lua | 2 +- lua/autorun/acf_loader.lua | 28 +++--- lua/effects/acf_bullet_effect.lua | 2 +- lua/entities/acf_ammo/init.lua | 1 + lua/entities/acf_engine/cl_init.lua | 1 + lua/entities/acf_engine/init.lua | 8 -- lua/entities/acf_fueltank/cl_init.lua | 2 + lua/entities/acf_gearbox/init.lua | 95 +++++++++++++------ lua/entities/acf_gun/cl_init.lua | 1 + lua/entities/acf_gun/init.lua | 1 + .../core/custom/acffunctions.lua | 2 +- lua/starfall/libs_sv/acffunctions.lua | 16 ++-- lua/weapons/acf_base/init.lua | 6 +- lua/weapons/acf_base/shared.lua | 2 +- lua/weapons/gmod_tool/stools/acfsound.lua | 2 +- 45 files changed, 226 insertions(+), 161 deletions(-) diff --git a/lua/acf/base/acf_globals.lua b/lua/acf/base/acf_globals.lua index 15944bd3c..8404cb25a 100644 --- a/lua/acf/base/acf_globals.lua +++ b/lua/acf/base/acf_globals.lua @@ -96,14 +96,14 @@ do -- ACF global vars ACF.RefillDistance = 300 --Distance in which ammo crate starts refilling. ACF.RefillSpeed = 700 -- (ACF.RefillSpeed / RoundMass) / Distance - --kg/liter + -- DELETE ACF.FuelDensity = { Diesel = 0.832, Petrol = 0.745, Electric = 3.89 -- li-ion } - --how efficient various engine types are, higher is worse + -- DELETE ACF.Efficiency = { GenericPetrol = 0.304, -- kg per kw hr GenericDiesel = 0.243, @@ -113,7 +113,7 @@ do -- ACF global vars Electric = 0.2125 --percent efficiency converting chemical kw into mechanical kw } - --how fast damage drops torque, lower loses more % torque + -- DELETE ACF.TorqueScale = { GenericPetrol = 0.25, GenericDiesel = 0.35, @@ -123,7 +123,7 @@ do -- ACF global vars Electric = 0.5 } - --health multiplier for engines + -- DELETE ACF.EngineHPMult = { GenericPetrol = 0.2, GenericDiesel = 0.5, @@ -236,6 +236,7 @@ elseif CLIENT then --------------------------------------------- end +-- REPLACE or REMOVE? timer.Simple(0, function() for _, Table in pairs(ACF.Classes.GunClass) do PrecacheParticleSystem(Table["muzzleflash"]) diff --git a/lua/acf/client/sk_menu.lua b/lua/acf/client/sk_menu.lua index cf22889dd..3a3aef5f2 100644 --- a/lua/acf/client/sk_menu.lua +++ b/lua/acf/client/sk_menu.lua @@ -1,3 +1,4 @@ +-- DELETE function PANEL:Init() acfmenupanel = self.Panel -- height @@ -191,12 +192,11 @@ function PANEL:Init() -- end end ---[[------------------------------------ - Think -------------------------------------]] +-- DELETE function PANEL:Think() end +-- DELETE function PANEL:UpdateDisplay(Table) RunConsoleCommand("acfmenu_id", Table.id or 0) @@ -225,6 +225,7 @@ function PANEL:UpdateDisplay(Table) acfmenupanel:PerformLayout() end +-- DELETE function PANEL:PerformLayout() --Starting positions local vspacing = 10 @@ -242,6 +243,7 @@ function PANEL:PerformLayout() end end +-- DELETE function ACFHomeGUICreate() if not acfmenupanel.CustomDisplay then return end @@ -281,6 +283,7 @@ function ACFHomeGUICreate() Display:AddItem(CData.ClientStatus) end +-- DELETE function PANEL:AmmoSelect(Blacklist) if not acfmenupanel.CustomDisplay then return end @@ -380,7 +383,7 @@ function PANEL:AmmoSelect(Blacklist) end end --- If it works don't fix it man, btw just add this function to every single ammo type +-- DELETE function PANEL:AmmoUpdate() local AmmoData = acfmenupanel.AmmoData @@ -389,7 +392,7 @@ function PANEL:AmmoUpdate() acfmenupanel:AmmoSlider("Ammo Scale Z", AmmoData["Ammo Scale Z"], 6, 96, 3, "Crate Z scale") end ---Variable name in the table, Value, Min value, Max Value, slider text title, slider decimals, description text below slider +-- DELETE function PANEL:AmmoSlider(Name, Value, Min, Max, Decimals, Title, Desc) local Panels = acfmenupanel.CData @@ -441,7 +444,7 @@ function PANEL:AmmoSlider(Name, Value, Min, Max, Decimals, Title, Desc) end end ---Variable name in the table, slider text title, slider decimeals, description text below slider +-- DELETE function PANEL:AmmoCheckbox(Name, Title, Desc) if not acfmenupanel["CData"][Name] then acfmenupanel["CData"][Name] = vgui.Create("DCheckBoxLabel") @@ -477,6 +480,7 @@ function PANEL:AmmoCheckbox(Name, Title, Desc) acfmenupanel["CData"][Name .. "_text"]:SizeToContentsX() end +-- DELETE function PANEL:CPanelText(Name, Desc) if not acfmenupanel["CData"][Name .. "_text"] then acfmenupanel["CData"][Name .. "_text"] = vgui.Create("DLabel") diff --git a/lua/acf/shared/ammo_types/apcr.lua b/lua/acf/shared/ammo_types/apcr.lua index 65f313917..b730779dc 100644 --- a/lua/acf/shared/ammo_types/apcr.lua +++ b/lua/acf/shared/ammo_types/apcr.lua @@ -6,7 +6,6 @@ function Ammo:OnLoaded() self.Name = "Armor Piercing Composite Rigid" self.Description = "A hardened core munition designed for weapons in the 1940s." self.Blacklist = ACF.GetWeaponBlacklist({ - RAC = true, AL = true, AC = true, SA = true, diff --git a/lua/acf/shared/ammo_types/apds.lua b/lua/acf/shared/ammo_types/apds.lua index fb9128cc8..31e26d8e3 100644 --- a/lua/acf/shared/ammo_types/apds.lua +++ b/lua/acf/shared/ammo_types/apds.lua @@ -6,7 +6,6 @@ function Ammo:OnLoaded() self.Name = "Armor Piercing Discarging Sabot" self.Description = "A subcaliber munition designed to trade damage for penetration. Loses energy quickly over distance." self.Blacklist = ACF.GetWeaponBlacklist({ - RAC = true, AL = true, AC = true, SA = true, diff --git a/lua/acf/shared/ammo_types/fl.lua b/lua/acf/shared/ammo_types/fl.lua index c65e1f460..2b8d5990b 100644 --- a/lua/acf/shared/ammo_types/fl.lua +++ b/lua/acf/shared/ammo_types/fl.lua @@ -181,7 +181,7 @@ if SERVER then local Spread = 0 if Gun then - local GunClass = ACF.Classes.GunClass[Gun.gunclass] + local GunClass = ACF.Classes.GunClass[Gun.gunclass] -- REPLACE Spread = GunClass and (GunClass.spread * ACF.GunInaccuracyScale) or 0 end diff --git a/lua/acf/shared/ammo_types/heat.lua b/lua/acf/shared/ammo_types/heat.lua index c697ad066..04fe6e22c 100644 --- a/lua/acf/shared/ammo_types/heat.lua +++ b/lua/acf/shared/ammo_types/heat.lua @@ -187,19 +187,15 @@ if SERVER then if Crushed == 1 then return false end -- no HEAT jet to fire off, it was all converted to HE - local DeltaTime = ACF.CurTime - Bullet.LastThink - - Bullet.Detonated = true - Bullet.InitTime = ACF.CurTime - Bullet.Flight = Bullet.Flight + Bullet.Flight:GetNormalized() * self:CalcSlugMV(Bullet, HEATFillerMass) * 39.37 - Bullet.Pos = HitPos - Bullet.DragCoef = Bullet.SlugDragCoef - Bullet.ProjMass = Bullet.SlugMass * (1 - Crushed) - Bullet.Caliber = Bullet.SlugCaliber - Bullet.PenArea = Bullet.SlugPenArea - Bullet.Ricochet = Bullet.SlugRicochet - Bullet.StartTrace = Bullet.Pos - Bullet.Flight:GetNormalized() * math.min(ACF.PhysMaxVel * DeltaTime, Bullet.FlightTime * Bullet.Flight:Length()) - Bullet.NextPos = Bullet.Pos + (Bullet.Flight * ACF.Scale * DeltaTime) --Calculates the next shell position + Bullet.Detonated = true + Bullet.InitTime = ACF.CurTime + Bullet.Flight = Bullet.Flight + Bullet.Flight:GetNormalized() * self:CalcSlugMV(Bullet, HEATFillerMass) * 39.37 + Bullet.NextPos = HitPos + Bullet.DragCoef = Bullet.SlugDragCoef + Bullet.ProjMass = Bullet.SlugMass * (1 - Crushed) + Bullet.Caliber = Bullet.SlugCaliber + Bullet.PenArea = Bullet.SlugPenArea + Bullet.Ricochet = Bullet.SlugRicochet return true end diff --git a/lua/acf/shared/guns/autocannon.lua b/lua/acf/shared/guns/autocannon.lua index cb6055153..52918246e 100644 --- a/lua/acf/shared/guns/autocannon.lua +++ b/lua/acf/shared/guns/autocannon.lua @@ -1,4 +1,4 @@ ---define the class +-- DELETE ACF_defineGunClass("AC", { spread = 0.2, name = "Autocannon", @@ -10,8 +10,7 @@ ACF_defineGunClass("AC", { soundNormal = " " }) ---add a gun to the class ---id +-- DELETE ACF_defineGun("20mmAC", { name = "20mm Autocannon", desc = "The 20mm AC is the smallest of the family; having a good rate of fire but a tiny shell.", @@ -30,6 +29,7 @@ ACF_defineGun("20mmAC", { } }) +-- DELETE ACF_defineGun("30mmAC", { name = "30mm Autocannon", desc = "The 30mm AC can fire shells with sufficient space for a small payload, and has modest anti-armor capability", @@ -48,6 +48,7 @@ ACF_defineGun("30mmAC", { } }) +-- DELETE ACF_defineGun("40mmAC", { name = "40mm Autocannon", desc = "The 40mm AC can fire shells with sufficient space for a useful payload, and can get decent penetration with proper rounds.", @@ -66,6 +67,7 @@ ACF_defineGun("40mmAC", { } }) +-- DELETE ACF_defineGun("50mmAC", { name = "50mm Autocannon", desc = "The 50mm AC fires shells comparable with the 50mm Cannon, making it capable of destroying light armour quite quickly.", diff --git a/lua/acf/shared/guns/autoloader.lua b/lua/acf/shared/guns/autoloader.lua index b57b56cf0..f78e3fae7 100644 --- a/lua/acf/shared/guns/autoloader.lua +++ b/lua/acf/shared/guns/autoloader.lua @@ -1,4 +1,4 @@ ---define the class +-- DELETE ACF_defineGunClass("AL", { spread = 0.08, name = "Autoloader", @@ -10,8 +10,7 @@ ACF_defineGunClass("AL", { soundNormal = " " }) ---add a gun to the class ---id +-- DELETE ACF_defineGun("75mmAL", { name = "75mm Autoloading Cannon", desc = "A quick-firing 75mm gun, pops off a number of rounds in relatively short order.", @@ -30,6 +29,7 @@ ACF_defineGun("75mmAL", { } }) +-- DELETE ACF_defineGun("100mmAL", { name = "100mm Autoloading Cannon", desc = "The 100mm is good for rapidly hitting medium armor, then running like your ass is on fire to reload.", @@ -48,6 +48,7 @@ ACF_defineGun("100mmAL", { } }) +-- DELETE ACF_defineGun("120mmAL", { name = "120mm Autoloading Cannon", desc = "The 120mm autoloader can do serious damage before reloading, but the reload time is killer.", @@ -66,6 +67,7 @@ ACF_defineGun("120mmAL", { } }) +-- DELETE ACF_defineGun("140mmAL", { name = "140mm Autoloading Cannon", desc = "The 140mm can shred a medium tank's armor with one magazine, and even function as shoot & scoot artillery, with its useful HE payload.", diff --git a/lua/acf/shared/guns/cannon.lua b/lua/acf/shared/guns/cannon.lua index c63cd6a1c..b6776551e 100644 --- a/lua/acf/shared/guns/cannon.lua +++ b/lua/acf/shared/guns/cannon.lua @@ -1,4 +1,4 @@ ---define the class +-- DELETE ACF_defineGunClass("C", { spread = 0.08, name = "Cannon", @@ -10,8 +10,7 @@ ACF_defineGunClass("C", { soundNormal = " " }) ---add a gun to the class ---id +-- DELETE ACF_defineGun("37mmC", { name = "37mm Cannon", desc = "A light and fairly weak cannon with good accuracy.", @@ -28,6 +27,7 @@ ACF_defineGun("37mmC", { } }) +-- DELETE ACF_defineGun("50mmC", { name = "50mm Cannon", desc = "The 50mm is surprisingly fast-firing, with good effectiveness against light armor, but a pea-shooter compared to its bigger cousins", @@ -43,6 +43,7 @@ ACF_defineGun("50mmC", { } }) +-- DELETE ACF_defineGun("75mmC", { name = "75mm Cannon", desc = "The 75mm is still rather respectable in rate of fire, but has only modest payload. Often found on the Eastern Front, and on cold war light tanks.", @@ -57,6 +58,7 @@ ACF_defineGun("75mmC", { } }) +-- DELETE ACF_defineGun("100mmC", { name = "100mm Cannon", desc = "The 100mm was a benchmark for the early cold war period, and has great muzzle velocity and hitting power, while still boasting a respectable, if small, payload.", @@ -71,6 +73,7 @@ ACF_defineGun("100mmC", { } }) +-- DELETE ACF_defineGun("120mmC", { name = "120mm Cannon", desc = "Often found in MBTs, the 120mm shreds lighter armor with utter impunity, and is formidable against even the big boys.", @@ -85,6 +88,7 @@ ACF_defineGun("120mmC", { } }) +-- DELETE ACF_defineGun("140mmC", { name = "140mm Cannon", desc = "The 140mm fires a massive shell with enormous penetrative capability, but has a glacial reload speed and a very hefty weight.", diff --git a/lua/acf/shared/guns/grenadelauncher.lua b/lua/acf/shared/guns/grenadelauncher.lua index b2cc0e331..deaee689f 100644 --- a/lua/acf/shared/guns/grenadelauncher.lua +++ b/lua/acf/shared/guns/grenadelauncher.lua @@ -1,4 +1,4 @@ ---define the class +-- DELETE ACF_defineGunClass("GL", { spread = 0.28, name = "Grenade Launcher", @@ -10,7 +10,7 @@ ACF_defineGunClass("GL", { soundNormal = " " } ) ---add a gun to the class +-- DELETE ACF_defineGun("40mmGL", { --id name = "40mm Grenade Launcher", desc = "The 40mm chews up infantry but is about as useful as tits on a nun for fighting armor. Often found on 4x4s rolling through the third world.", diff --git a/lua/acf/shared/guns/heavymachinegun.lua b/lua/acf/shared/guns/heavymachinegun.lua index 88f82a8fd..a7aef2322 100644 --- a/lua/acf/shared/guns/heavymachinegun.lua +++ b/lua/acf/shared/guns/heavymachinegun.lua @@ -1,4 +1,4 @@ ---define the class +-- DELETE ACF_defineGunClass("HMG", { spread = 1.2, name = "Heavy Machinegun", @@ -15,7 +15,7 @@ ACF_defineGunClass("HMG", { } }) ---add a gun to the class +-- DELETE ACF_defineGun("13mmHMG", { name = "13mm Heavy Machinegun", desc = "The lightest of the HMGs, the 13mm has a rapid fire rate but suffers from poor payload size. Often used to strafe ground troops or annoy low-flying aircraft.", @@ -35,6 +35,7 @@ ACF_defineGun("13mmHMG", { } }) +-- DELETE ACF_defineGun("20mmHMG", { name = "20mm Heavy Machinegun", desc = "The 20mm has a rapid fire rate but suffers from poor payload size. Often used to strafe ground troops or annoy low-flying aircraft.", @@ -54,6 +55,7 @@ ACF_defineGun("20mmHMG", { } }) +-- DELETE ACF_defineGun("30mmHMG", { name = "30mm Heavy Machinegun", desc = "30mm shell chucker, light and compact. Your average cold war dogfight go-to.", @@ -73,6 +75,7 @@ ACF_defineGun("30mmHMG", { } }) +-- DELETE ACF_defineGun("40mmHMG", { name = "40mm Heavy Machinegun", desc = "The heaviest of the heavy machineguns. Massively powerful with a killer reload and hefty ammunition requirements, it can pop even relatively heavy targets with ease.", @@ -96,7 +99,7 @@ ACF.RegisterWeaponClass("HMG", { Name = "Heavy Machinegun", Description = "Designed as autocannons for aircraft, HMGs are rapid firing, lightweight, and compact but sacrifice accuracy, magazine size, and reload times.", MuzzleFlash = "mg_muzzleflash_noscale", - Spread = 0.24, + Spread = 1.2, Sound = "acf_base/weapons/mg_fire3.mp3", Caliber = { Min = 13, diff --git a/lua/acf/shared/guns/howitzer.lua b/lua/acf/shared/guns/howitzer.lua index 94e0fc52e..a98a217f8 100644 --- a/lua/acf/shared/guns/howitzer.lua +++ b/lua/acf/shared/guns/howitzer.lua @@ -1,4 +1,4 @@ ---define the class +-- DELETE ACF_defineGunClass("HW", { spread = 0.1, name = "Howitzer", @@ -10,8 +10,7 @@ ACF_defineGunClass("HW", { soundNormal = " " }) ---add a gun to the class ---id +-- DELETE ACF_defineGun("75mmHW", { name = "75mm Howitzer", desc = "Often found being towed by large smelly animals, the 75mm has a high rate of fire, and is surprisingly lethal against light armor. Great for a sustained barrage against someone you really don't like.", @@ -26,6 +25,7 @@ ACF_defineGun("75mmHW", { } }) +-- DELETE ACF_defineGun("105mmHW", { name = "105mm Howitzer", desc = "The 105 lobs a big shell far, and its HEAT rounds can be extremely effective against even heavier armor.", @@ -40,6 +40,7 @@ ACF_defineGun("105mmHW", { } }) +-- DELETE ACF_defineGun("122mmHW", { name = "122mm Howitzer", desc = "The 122mm bridges the gap between the 105 and the 155, providing a lethal round with a big splash radius.", @@ -54,6 +55,7 @@ ACF_defineGun("122mmHW", { } }) +-- DELETE ACF_defineGun("155mmHW", { name = "155mm Howitzer", desc = "The 155 is a classic heavy artillery round, with good reason. A versatile weapon, it's found on most modern SPGs.", @@ -68,6 +70,7 @@ ACF_defineGun("155mmHW", { } }) +-- DELETE ACF_defineGun("203mmHW", { name = "203mm Howitzer", desc = "An 8-inch deck gun, found on siege artillery and cruisers.", diff --git a/lua/acf/shared/guns/machinegun.lua b/lua/acf/shared/guns/machinegun.lua index e14ce475f..ec0ff4ea4 100644 --- a/lua/acf/shared/guns/machinegun.lua +++ b/lua/acf/shared/guns/machinegun.lua @@ -1,4 +1,4 @@ ---define the class +-- DELETE ACF_defineGunClass("MG", { spread = 0.16, name = "Machinegun", @@ -10,8 +10,7 @@ ACF_defineGunClass("MG", { soundDistance = "" }) ---add a gun to the class ---id +-- DELETE ACF_defineGun("7.62mmMG", { name = "7.62mm Machinegun", desc = "The 7.62mm is effective against infantry, but its usefulness against armor is laughable at best.", @@ -31,6 +30,7 @@ ACF_defineGun("7.62mmMG", { } }) +-- DELETE ACF_defineGun("12.7mmMG", { name = "12.7mm Machinegun", desc = "The 12.7mm MG is still light, finding its way into a lot of mountings, including on top of tanks.", @@ -50,6 +50,7 @@ ACF_defineGun("12.7mmMG", { } }) +-- DELETE ACF_defineGun("14.5mmMG", { name = "14.5mm Machinegun", desc = "The 14.5mm MG trades its smaller stablemates' rate of fire for more armor penetration and damage.", @@ -78,7 +79,7 @@ ACF.RegisterWeaponClass("MG", { IsBoxed = true, Caliber = { Min = 5.56, - Max = 14.5, + Max = 20, }, }) @@ -90,7 +91,7 @@ ACF.RegisterWeapon("7.62mmMG", "MG", { Mass = 15, Year = 1930, MagSize = 250, - MagReload = 6, + MagReload = 5, Cyclic = 700, -- Rounds per minute Round = { MaxLength = 13, @@ -122,10 +123,26 @@ ACF.RegisterWeapon("14.5mmMG", "MG", { Mass = 45, Year = 1932, MagSize = 90, - MagReload = 5, + MagReload = 7, Cyclic = 500, Round = { MaxLength = 19.5, PropMass = 0.04, } }) + +ACF.RegisterWeapon("20mmMG", "MG", { + Name = "20mm Machinegun", + Description = "The 20mm MG is practically a cannon in its own right; the weight and recoil made it difficult to mount on light land vehicles, though it was adapted for use on both aircraft and ships.", + Model = "models/machinegun/machinegun_20mm.mdl", + Caliber = 20, + Mass = 95, + Year = 1935, + MagSize = 200, + MagReload = 8, + Cyclic = 400, + Round = { + MaxLength = 22, + PropMass = 0.09, + } +}) diff --git a/lua/acf/shared/guns/mortar.lua b/lua/acf/shared/guns/mortar.lua index 67e081217..bd640efa6 100644 --- a/lua/acf/shared/guns/mortar.lua +++ b/lua/acf/shared/guns/mortar.lua @@ -1,4 +1,4 @@ ---define the class +-- DELETE ACF_defineGunClass("MO", { spread = 0.72, name = "Mortar", @@ -10,8 +10,7 @@ ACF_defineGunClass("MO", { soundNormal = " " }) ---add a gun to the class ---id +-- DELETE ACF_defineGun("60mmM", { name = "60mm Mortar", desc = "The 60mm is a common light infantry support weapon, with a high rate of fire but a puny payload.", @@ -27,6 +26,7 @@ ACF_defineGun("60mmM", { } }) +-- DELETE ACF_defineGun("80mmM", { name = "80mm Mortar", desc = "The 80mm is a common infantry support weapon, with a good bit more boom than its little cousin.", @@ -41,6 +41,7 @@ ACF_defineGun("80mmM", { } }) +-- DELETE ACF_defineGun("120mmM", { name = "120mm Mortar", desc = "The versatile 120 is sometimes vehicle-mounted to provide quick boomsplat to support the infantry. Carries more boom in its boomsplat, has good HEAT performance, and is more accurate in high-angle firing.", @@ -55,6 +56,7 @@ ACF_defineGun("120mmM", { } }) +-- DELETE ACF_defineGun("150mmM", { name = "150mm Mortar", desc = "The perfect balance between the 120mm and the 200mm. Can prove a worthy main gun weapon, as well as a mighty good mortar emplacement", @@ -69,6 +71,7 @@ ACF_defineGun("150mmM", { } }) +-- DELETE ACF_defineGun("200mmM", { name = "200mm Mortar", desc = "The 200mm is a beast, often used against fortifications. Though enormously powerful, feel free to take a nap while it reloads", diff --git a/lua/acf/shared/guns/rotaryautocannon.lua b/lua/acf/shared/guns/rotaryautocannon.lua index a84a53910..066a392db 100644 --- a/lua/acf/shared/guns/rotaryautocannon.lua +++ b/lua/acf/shared/guns/rotaryautocannon.lua @@ -1,4 +1,4 @@ ---define the class +-- DELETE ACF_defineGunClass("RAC", { spread = 0.48, name = "Rotary Autocannon", @@ -11,6 +11,7 @@ ACF_defineGunClass("RAC", { color = {135, 135, 135} } ) +-- DELETE ACF_defineGun("14.5mmRAC", { --id name = "14.5mm Rotary Autocannon", desc = "A lightweight rotary autocannon, used primarily against infantry and light vehicles.", @@ -29,6 +30,7 @@ ACF_defineGun("14.5mmRAC", { --id } } ) +-- DELETE ACF_defineGun("20mmRAC", { name = "20mm Rotary Autocannon", desc = "The 20mm is able to chew up light armor with decent penetration or put up a big flak screen.", @@ -47,6 +49,7 @@ ACF_defineGun("20mmRAC", { } } ) +-- DELETE ACF_defineGun("30mmRAC", { name = "30mm Rotary Autocannon", desc = "The 30mm is the bane of ground-attack aircraft, able to tear up light armor without giving one single fuck. Also seen in the skies above dead T-72s.", diff --git a/lua/acf/shared/guns/semiauto.lua b/lua/acf/shared/guns/semiauto.lua index fe328c287..c3afb8a56 100644 --- a/lua/acf/shared/guns/semiauto.lua +++ b/lua/acf/shared/guns/semiauto.lua @@ -1,4 +1,4 @@ ---define the class +-- DELETE ACF_defineGunClass("SA", { spread = 0.12, name = "Semiautomatic Cannon", @@ -10,8 +10,7 @@ ACF_defineGunClass("SA", { soundNormal = " " }) ---add a gun to the class ---id +-- DELETE ACF_defineGun("25mmSA", { name = "25mm Semiautomatic Cannon", desc = "The 25mm semiauto can quickly put five rounds downrange, being lethal, yet light.", @@ -31,6 +30,7 @@ ACF_defineGun("25mmSA", { } }) +-- DELETE ACF_defineGun("37mmSA", { name = "37mm Semiautomatic Cannon", desc = "The 37mm is surprisingly powerful, its five-round clips boasting a respectable payload and a high muzzle velocity.", @@ -50,6 +50,7 @@ ACF_defineGun("37mmSA", { } }) +-- DELETE ACF_defineGun("45mmSA", { name = "45mm Semiautomatic Cannon", desc = "The 45mm can easily shred light armor, with a respectable rate of fire, but its armor penetration pales in comparison to regular cannons.", @@ -69,6 +70,7 @@ ACF_defineGun("45mmSA", { } }) +-- DELETE ACF_defineGun("57mmSA", { name = "57mm Semiautomatic Cannon", desc = "The 57mm is a respectable light armament, offering considerable penetration and moderate fire rate.", @@ -88,6 +90,7 @@ ACF_defineGun("57mmSA", { } }) +-- DELETE ACF_defineGun("76mmSA", { name = "76mm Semiautomatic Cannon", desc = "The 76mm semiauto is a fearsome weapon, able to put 5 76mm rounds downrange in 8 seconds.", diff --git a/lua/acf/shared/guns/shortcannon.lua b/lua/acf/shared/guns/shortcannon.lua index 5a873a957..4be7f294c 100644 --- a/lua/acf/shared/guns/shortcannon.lua +++ b/lua/acf/shared/guns/shortcannon.lua @@ -1,4 +1,4 @@ ---define the class +-- DELETE ACF_defineGunClass("SC", { spread = 0.16, name = "Short-Barrel Cannon", @@ -10,7 +10,7 @@ ACF_defineGunClass("SC", { soundNormal = " " } ) ---add a gun to the class +-- DELETE ACF_defineGun("37mmSC", { name = "37mm Short Cannon", desc = "Quick-firing and light, but penetration is laughable. You're better off throwing rocks.", @@ -27,6 +27,7 @@ ACF_defineGun("37mmSC", { } } ) +-- DELETE ACF_defineGun("50mmSC", { name = "50mm Short Cannon", desc = "The 50mm is a quick-firing pea-shooter, good for scouts, and common on old interwar tanks.", @@ -43,6 +44,7 @@ ACF_defineGun("50mmSC", { } } ) +-- DELETE ACF_defineGun("75mmSC", { name = "75mm Short Cannon", desc = "The 75mm is common WW2 medium tank armament, and still useful in many other applications.", @@ -57,6 +59,7 @@ ACF_defineGun("75mmSC", { } } ) +-- DELETE ACF_defineGun("100mmSC", { name = "100mm Short Cannon", desc = "The 100mm is an effective infantry-support or antitank weapon, with a lot of uses and surprising lethality.", @@ -71,6 +74,7 @@ ACF_defineGun("100mmSC", { } } ) +-- DELETE ACF_defineGun("120mmSC", { name = "120mm Short Cannon", desc = "The 120mm is a formidable yet lightweight weapon, with excellent performance against larger vehicles.", @@ -85,6 +89,7 @@ ACF_defineGun("120mmSC", { } } ) +-- DELETE ACF_defineGun("140mmSC", { name = "140mm Short Cannon", desc = "A specialized weapon, developed from dark magic and anti-heavy tank hatred. Deal with it.", diff --git a/lua/acf/shared/guns/smokelauncher.lua b/lua/acf/shared/guns/smokelauncher.lua index 165fe8f2a..2cfb21703 100644 --- a/lua/acf/shared/guns/smokelauncher.lua +++ b/lua/acf/shared/guns/smokelauncher.lua @@ -1,4 +1,4 @@ ---define the class +-- DELETE ACF_defineGunClass("SL", { spread = 0.32, name = "Smoke Launcher", @@ -10,8 +10,7 @@ ACF_defineGunClass("SL", { soundNormal = " " }) ---add a gun to the class ---id +-- DELETE ACF_defineGun("40mmSL", { name = "40mm Smoke Launcher", desc = "", @@ -31,8 +30,7 @@ ACF_defineGun("40mmSL", { } }) ---add a gun to the class ---id +-- DELETE ACF_defineGun("40mmCL", { name = "40mm Countermeasure Launcher", desc = "A revolver-style launcher capable of firing off several smoke or flare rounds.", @@ -80,25 +78,9 @@ ACF.RegisterWeapon("40mmSL", "SL", { Year = 1941, MagSize = 1, MagReload = 30, - Cyclic = 1, + Cyclic = 600, Round = { MaxLength = 17.5, PropMass = 0.000075, } }) - -ACF.RegisterWeapon("40mmCL", "SL", { - Name = "40mm Countermeasure Launcher", - Description = "A revolver-style launcher capable of firing off several smoke or flare rounds.", - Model = "models/launcher/40mmgl.mdl", - Caliber = 40, - Mass = 20, - Year = 1950, - MagSize = 6, - MagReload = 40, - Cyclic = 200, - Round = { - MaxLength = 12, - PropMass = 0.001, - } -}) diff --git a/lua/acf/shared/guns/smoothbore.lua b/lua/acf/shared/guns/smoothbore.lua index a053a129c..eda02a985 100644 --- a/lua/acf/shared/guns/smoothbore.lua +++ b/lua/acf/shared/guns/smoothbore.lua @@ -1,4 +1,4 @@ ---define the class +-- DELETE ACF_defineGunClass("SB", { spread = 0.08, name = "Smoothbore Cannon", @@ -10,9 +10,7 @@ ACF_defineGunClass("SB", { soundNormal = " " } ) ---add a gun to the class - - +-- DELETE ACF_defineGun("105mmSB", { name = "105mm Smoothbore Cannon", desc = "The 105mm was a benchmark for the early cold war period, and has great muzzle velocity and hitting power, while still boasting a respectable, if small, payload.", @@ -27,6 +25,7 @@ ACF_defineGun("105mmSB", { } } ) +-- DELETE ACF_defineGun("120mmSB", { name = "120mm Smoothbore Cannon", desc = "Often found in MBTs, the 120mm shreds lighter armor with utter impunity, and is formidable against even the big boys.", @@ -41,6 +40,7 @@ ACF_defineGun("120mmSB", { } } ) +-- DELETE ACF_defineGun("140mmSB", { name = "140mm Smoothbore Cannon", desc = "The 140mm fires a massive shell with enormous penetrative capability, but has a glacial reload speed and a very hefty weight.", diff --git a/lua/acf/shared/rounds/ap.lua b/lua/acf/shared/rounds/ap.lua index 158d04093..5023c8870 100644 --- a/lua/acf/shared/rounds/ap.lua +++ b/lua/acf/shared/rounds/ap.lua @@ -1,4 +1,4 @@ -ACF.AmmoBlacklist.AP = {"MO", "SL", "SB"} +ACF.AmmoBlacklist.AP = {"MO", "SL", "SB"} -- DELETE local Round = {} Round.type = "Ammo" --Tells the spawn menu what entity to spawn Round.name = "Armour Piercing (AP)" --Human readable name @@ -206,6 +206,6 @@ function Round.guiupdate(Panel) acfmenupanel:CPanelText("PenetrationDisplay", "Maximum Penetration : " .. math.floor(Data.MaxPen) .. " mm RHA\n\n300m pen: " .. math.Round(R1P, 0) .. "mm @ " .. math.Round(R1V, 0) .. " m\\s\n800m pen: " .. math.Round(R2P, 0) .. "mm @ " .. math.Round(R2V, 0) .. " m\\s\n\nThe range data is an approximation and may not be entirely accurate.") --Proj muzzle penetration (Name, Desc) end -ACF.RoundTypes.AP = Round --Set the round properties +ACF.RoundTypes.AP = Round -- DELETE ACF.RegisterAmmoDecal("AP", "damage/ap_pen", "damage/ap_rico") \ No newline at end of file diff --git a/lua/acf/shared/rounds/apcr.lua b/lua/acf/shared/rounds/apcr.lua index 6b2d5ed5a..b9a57079c 100644 --- a/lua/acf/shared/rounds/apcr.lua +++ b/lua/acf/shared/rounds/apcr.lua @@ -211,6 +211,6 @@ function Round.guiupdate(Panel) acfmenupanel:CPanelText("PenetrationDisplay", "Maximum Penetration : " .. math.floor(Data.MaxPen) .. " mm RHA\n\n300m pen: " .. math.Round(R1P,0) .. "mm @ " .. math.Round(R1V,0) .. " m\\s\n800m pen: " .. math.Round(R2P,0) .. "mm @ " .. math.Round(R2V,0) .. " m\\s\n\nThe range data is an approximation and may not be entirely accurate.") --Proj muzzle penetration (Name, Desc) end -ACF.RoundTypes.APCR = Round --Set the round properties +ACF.RoundTypes.APCR = Round -- DELETE ACF.RegisterAmmoDecal("APCR", "damage/apcr_pen", "damage/apcr_rico") diff --git a/lua/acf/shared/rounds/apds.lua b/lua/acf/shared/rounds/apds.lua index 43d29fde1..7e04d2144 100644 --- a/lua/acf/shared/rounds/apds.lua +++ b/lua/acf/shared/rounds/apds.lua @@ -218,6 +218,6 @@ function Round.guiupdate(Panel) acfmenupanel:CPanelText("PenetrationDisplay", "Maximum Penetration : " .. math.floor(Data.MaxPen) .. " mm RHA\n\n300m pen: " .. math.Round(R1P,0) .. "mm @ " .. math.Round(R1V,0) .. " m\\s\n800m pen: " .. math.Round(R2P,0) .. "mm @ " .. math.Round(R2V,0) .. " m\\s\n\nThe range data is an approximation and may not be entirely accurate.") --Proj muzzle penetration (Name, Desc) end -ACF.RoundTypes.APDS = Round --Set the round properties +ACF.RoundTypes.APDS = Round -- DELETE ACF.RegisterAmmoDecal("APDS", "damage/apcr_pen", "damage/apcr_rico") diff --git a/lua/acf/shared/rounds/apfsds.lua b/lua/acf/shared/rounds/apfsds.lua index 855c2598a..dd216d42c 100644 --- a/lua/acf/shared/rounds/apfsds.lua +++ b/lua/acf/shared/rounds/apfsds.lua @@ -218,6 +218,6 @@ function Round.guiupdate(Panel) acfmenupanel:CPanelText("PenetrationDisplay", "Maximum Penetration : " .. math.floor(Data.MaxPen) .. " mm RHA\n\n300m pen: " .. math.Round(R1P,0) .. "mm @ " .. math.Round(R1V,0) .. " m\\s\n800m pen: " .. math.Round(R2P,0) .. "mm @ " .. math.Round(R2V,0) .. " m\\s\n\nThe range data is an approximation and may not be entirely accurate.") --Proj muzzle penetration (Name, Desc) end -ACF.RoundTypes.APFSDS = Round --Set the round properties +ACF.RoundTypes.APFSDS = Round -- DELETE ACF.RegisterAmmoDecal("APFSDS", "damage/apcr_pen", "damage/apcr_rico") diff --git a/lua/acf/shared/rounds/aphe.lua b/lua/acf/shared/rounds/aphe.lua index 2139a5dd0..cfe5b1a0d 100644 --- a/lua/acf/shared/rounds/aphe.lua +++ b/lua/acf/shared/rounds/aphe.lua @@ -241,6 +241,6 @@ function Round.guiupdate(Panel) acfmenupanel:CPanelText("PenetrationRanging", "\n300m pen: " .. math.Round(R1P, 0) .. "mm @ " .. math.Round(R1V, 0) .. " m\\s\n800m pen: " .. math.Round(R2P, 0) .. "mm @ " .. math.Round(R2V, 0) .. " m\\s\n\nThe range data is an approximation and may not be entirely accurate.") --Proj muzzle penetration (Name, Desc) end -ACF.RoundTypes.APHE = Round --Set the round properties +ACF.RoundTypes.APHE = Round -- DELETE ACF.RegisterAmmoDecal("APHE", "damage/ap_pen", "damage/ap_rico") \ No newline at end of file diff --git a/lua/acf/shared/rounds/fl.lua b/lua/acf/shared/rounds/fl.lua index 9580e5485..f8297f5d5 100644 --- a/lua/acf/shared/rounds/fl.lua +++ b/lua/acf/shared/rounds/fl.lua @@ -312,6 +312,6 @@ function Round.guiupdate(Panel) acfmenupanel:CPanelText("PenetrationDisplay", "Maximum Penetration : " .. math.floor(Data.MaxPen) .. " mm RHA\n\n300m pen: " .. math.Round(R1P, 0) .. "mm @ " .. math.Round(R1V, 0) .. " m\\s\n800m pen: " .. math.Round(R2P, 0) .. "mm @ " .. math.Round(R2V, 0) .. " m\\s\n\nThe range data is an approximation and may not be entirely accurate.") --Proj muzzle penetration (Name, Desc) end -ACF.RoundTypes.FL = Round --Set the round properties +ACF.RoundTypes.FL = Round -- DELETE ACF.RegisterAmmoDecal("FL", "damage/ap_pen", "damage/ap_rico") \ No newline at end of file diff --git a/lua/acf/shared/rounds/he.lua b/lua/acf/shared/rounds/he.lua index 417bc5f73..e5de4c1d7 100644 --- a/lua/acf/shared/rounds/he.lua +++ b/lua/acf/shared/rounds/he.lua @@ -213,6 +213,6 @@ function Round.guiupdate(Panel) --acfmenupanel:CPanelText("RicoDisplay", "Ricochet probability vs impact angle:\n".." 0% @ "..RicoAngs.Min.." degrees\n 50% @ "..RicoAngs.Mean.." degrees\n100% @ "..RicoAngs.Max.." degrees") end -ACF.RoundTypes.HE = Round --Set the round properties +ACF.RoundTypes.HE = Round -- DELETE ACF.RegisterAmmoDecal("HE", "damage/he_pen", "damage/he_rico") \ No newline at end of file diff --git a/lua/acf/shared/rounds/heat.lua b/lua/acf/shared/rounds/heat.lua index 9cbf1daa0..164a745d8 100644 --- a/lua/acf/shared/rounds/heat.lua +++ b/lua/acf/shared/rounds/heat.lua @@ -374,6 +374,6 @@ function Round.guiupdate(Panel) acfmenupanel:CPanelText("SlugDisplay", "Penetrator Mass : " .. (math.floor(Data.SlugMassUsed * 10000) / 10) .. " g \n Penetrator Caliber : " .. (math.floor(Data.SlugCaliber * 100) / 10) .. " mm \n Penetrator Velocity : " .. math.floor(Data.MuzzleVel + Data.SlugMV) .. " m/s \n Penetrator Maximum Penetration : " .. math.floor(Data.MaxPen) .. " mm RHA\n\n300m pen: " .. math.Round(R1P, 0) .. "mm @ " .. math.Round(R1V, 0) .. " m\\s\n800m pen: " .. math.Round(R2P, 0) .. "mm @ " .. math.Round(R2V, 0) .. " m\\s\n\nThe range data is an approximation and may not be entirely accurate.") --Proj muzzle penetration (Name, Desc) end -ACF.RoundTypes.HEAT = Round --Set the round properties +ACF.RoundTypes.HEAT = Round -- DELETE ACF.RegisterAmmoDecal("HEAT", "damage/heat_pen", "damage/heat_rico", function(Caliber) return Caliber * 0.1667 end) \ No newline at end of file diff --git a/lua/acf/shared/rounds/heatfs.lua b/lua/acf/shared/rounds/heatfs.lua index 42a7b77c2..48217de36 100644 --- a/lua/acf/shared/rounds/heatfs.lua +++ b/lua/acf/shared/rounds/heatfs.lua @@ -400,6 +400,6 @@ function Round.guiupdate(Panel) acfmenupanel:CPanelText("SlugDisplay", "Penetrator Mass : " .. (math.floor(Data.SlugMassUsed * 10000) / 10) .. " g \n Penetrator Caliber : " .. (math.floor(Data.SlugCaliber * 100) / 10) .. " mm \n Penetrator Velocity : " .. math.floor(Data.MuzzleVel + Data.SlugMV) .. " m/s \n Penetrator Maximum Penetration : " .. math.floor(Data.MaxPen) .. " mm RHA\n\n300m pen: " .. math.Round(R1P,0) .. "mm @ " .. math.Round(R1V,0) .. " m\\s\n800m pen: " .. math.Round(R2P,0) .. "mm @ " .. math.Round(R2V,0) .. " m\\s\n\nThe range data is an approximation and may not be entirely accurate.") --Proj muzzle penetration (Name, Desc) end -ACF.RoundTypes.HEATFS = Round --Set the round properties +ACF.RoundTypes.HEATFS = Round -- DELETE ACF.RegisterAmmoDecal("HEATFS", "damage/heat_pen", "damage/heat_rico", function(Caliber) return Caliber * 0.1667 end) diff --git a/lua/acf/shared/rounds/hp.lua b/lua/acf/shared/rounds/hp.lua index c383e02bf..2d39c53c7 100644 --- a/lua/acf/shared/rounds/hp.lua +++ b/lua/acf/shared/rounds/hp.lua @@ -146,6 +146,6 @@ function Round.guiupdate(Panel) acfmenupanel:CPanelText("PenetrationDisplay", "Maximum Penetration : " .. math.floor(Data.MaxPen) .. " mm RHA\n\n300m pen: " .. math.Round(R1P, 0) .. "mm @ " .. math.Round(R1V, 0) .. " m\\s\n800m pen: " .. math.Round(R2P, 0) .. "mm @ " .. math.Round(R2V, 0) .. " m\\s\n\nThe range data is an approximation and may not be entirely accurate.") --Proj muzzle penetration (Name, Desc) end -ACF.RoundTypes.HP = Round --Set the round properties +ACF.RoundTypes.HP = Round -- DELETE ACF.RegisterAmmoDecal("HP", "damage/ap_pen", "damage/ap_rico") \ No newline at end of file diff --git a/lua/acf/shared/rounds/refill.lua b/lua/acf/shared/rounds/refill.lua index 8994f0b19..35e9ffd66 100644 --- a/lua/acf/shared/rounds/refill.lua +++ b/lua/acf/shared/rounds/refill.lua @@ -82,4 +82,4 @@ function Round.guiupdate() acfmenupanel.CustomDisplay:PerformLayout() end -ACF.RoundTypes.Refill = Round --Set the round properties \ No newline at end of file +ACF.RoundTypes.Refill = Round -- DELETE \ No newline at end of file diff --git a/lua/acf/shared/rounds/smoke.lua b/lua/acf/shared/rounds/smoke.lua index 57f5a4060..3288afe56 100644 --- a/lua/acf/shared/rounds/smoke.lua +++ b/lua/acf/shared/rounds/smoke.lua @@ -238,6 +238,6 @@ function Round.guiupdate(Panel) ---acfmenupanel:CPanelText("FragDisplay", "Fragments : "..(Data.Fragments).."\n Average Fragment Weight : "..(math.floor(Data.FragMass*10000)/10).." ---g \n Average Fragment Velocity : "..math.floor(Data.FragVel).." m/s") --Proj muzzle penetration (Name, Desc) end -ACF.RoundTypes.SM = Round --Set the round properties +ACF.RoundTypes.SM = Round -- DELETE ACF.RegisterAmmoDecal("SM", "damage/he_pen", "damage/he_rico") \ No newline at end of file diff --git a/lua/autorun/acf_loader.lua b/lua/autorun/acf_loader.lua index b4c9c32e7..657a50fd8 100644 --- a/lua/autorun/acf_loader.lua +++ b/lua/autorun/acf_loader.lua @@ -15,48 +15,49 @@ ]]-- MsgN("\n===========[ Loading ACF ]============\n|") -local GunClasses = {} -local GunTable = {} -local MobilityTable = {} -local FuelTankTable = {} +local GunClasses = {} -- DELETE +local GunTable = {} -- DELETE +local MobilityTable = {} -- DELETE +local FuelTankTable = {} -- DELETE if not ACF then ACF = {} end -ACF.RoundTypes = ACF.RoundTypes or {} +ACF.RoundTypes = ACF.RoundTypes or {} -- DELETE -ACF.Classes = ACF.Classes or { +ACF.Classes = ACF.Classes or { -- DELETE GunClass = GunClasses } -ACF.Weapons = ACF.Weapons or { +ACF.Weapons = ACF.Weapons or { -- DELETE Guns = GunTable, Mobility = MobilityTable, FuelTanks = FuelTankTable } -local gun_base = { +local gun_base = { -- DELETE ent = "acf_gun", type = "Guns" } -local engine_base = { +local engine_base = { -- DELETE ent = "acf_engine", type = "Mobility" } -local gearbox_base = { +local gearbox_base = { -- DELETE ent = "acf_gearbox", type = "Mobility", sound = "vehicles/junker/jnk_fourth_cruise_loop2.wav" } -local fueltank_base = { +local fueltank_base = { -- DELETE ent = "acf_fueltank", type = "Mobility", explosive = true } do + -- REPLACE function ACF_defineGunClass( id, data ) data.id = id GunClasses[ id ] = data @@ -64,6 +65,7 @@ do PrecacheParticleSystem(data["muzzleflash"]) end + -- REPLACE function ACF_defineGun( id, data ) data.id = id data.round.id = id @@ -71,24 +73,28 @@ do GunTable[ id ] = data end + -- REPLACE function ACF_DefineEngine( id, data ) data.id = id table.Inherit( data, engine_base ) MobilityTable[ id ] = data end + -- REPLACE function ACF_DefineGearbox( id, data ) data.id = id table.Inherit( data, gearbox_base ) MobilityTable[ id ] = data end + -- REPLACE function ACF_DefineFuelTank( id, data ) data.id = id table.Inherit( data, fueltank_base ) MobilityTable[ id ] = data end + -- REPLACE function ACF_DefineFuelTankSize( id, data ) data.id = id table.Inherit( data, fueltank_base ) diff --git a/lua/effects/acf_bullet_effect.lua b/lua/effects/acf_bullet_effect.lua index c23e34d14..969ee4cb1 100644 --- a/lua/effects/acf_bullet_effect.lua +++ b/lua/effects/acf_bullet_effect.lua @@ -20,7 +20,7 @@ function EFFECT:Init(Data) -- Scale encodes the hit type, so if it's 0 it's a new bullet, else it's an update so we need to remove the effect if Bullet and Hit > 0 then - local RoundData = ACF.RoundTypes[Bullet.AmmoType] + local RoundData = ACF.RoundTypes[Bullet.AmmoType] -- REPLACE -- Updating old effect with new values Bullet.SimFlight = Flight diff --git a/lua/entities/acf_ammo/init.lua b/lua/entities/acf_ammo/init.lua index 7c5c9a42e..539f7e802 100644 --- a/lua/entities/acf_ammo/init.lua +++ b/lua/entities/acf_ammo/init.lua @@ -188,6 +188,7 @@ do -- Spawning and Updating -------------------- local Updated = { ["20mmHRAC"] = "20mmRAC", ["30mmHRAC"] = "30mmRAC", + ["40mmCL"] = "40mmGL", } local function VerifyData(Data) diff --git a/lua/entities/acf_engine/cl_init.lua b/lua/entities/acf_engine/cl_init.lua index 95e159aa2..15acdf0a0 100644 --- a/lua/entities/acf_engine/cl_init.lua +++ b/lua/entities/acf_engine/cl_init.lua @@ -21,6 +21,7 @@ function ENT:Draw() end end +-- DELETE function ACFEngineGUICreate(Table) acfmenupanel:CPanelText("Name", Table.name) acfmenupanel.CData.DisplayModel = vgui.Create("DModelPanel", acfmenupanel.CustomDisplay) diff --git a/lua/entities/acf_engine/init.lua b/lua/entities/acf_engine/init.lua index e682b89dc..c83cda173 100644 --- a/lua/entities/acf_engine/init.lua +++ b/lua/entities/acf_engine/init.lua @@ -13,14 +13,6 @@ do if not Engine.FuelTypes[Target.FuelType] then return false, "Cannot link because fuel type is incompatible." end if Target.NoLinks then return false, "This fuel tank doesn't allow linking." end - if Engine.FuelType == "Multifuel" then - if Target.FuelType == "Electric" then - return false, "Cannot link because fuel type is incompatible." - end - elseif Engine.FuelType ~= Target.FuelType then - return false, "Cannot link because fuel type is incompatible." - end - Engine.FuelTanks[Target] = true Target.Engines[Engine] = true diff --git a/lua/entities/acf_fueltank/cl_init.lua b/lua/entities/acf_fueltank/cl_init.lua index d2a15eb4f..13c315bd6 100644 --- a/lua/entities/acf_fueltank/cl_init.lua +++ b/lua/entities/acf_fueltank/cl_init.lua @@ -32,6 +32,7 @@ function ENT:Draw() end end +-- DELETE function ACFFuelTankGUICreate(Table) if not acfmenupanel.CustomDisplay then return end @@ -89,6 +90,7 @@ function ACFFuelTankGUICreate(Table) acfmenupanel.CustomDisplay:PerformLayout() end +-- DELETE function ACFFuelTankGUIUpdate() if not acfmenupanel.CustomDisplay then return end local Tanks = ACF.Weapons.FuelTanks diff --git a/lua/entities/acf_gearbox/init.lua b/lua/entities/acf_gearbox/init.lua index deb028e46..c47e75c09 100644 --- a/lua/entities/acf_gearbox/init.lua +++ b/lua/entities/acf_gearbox/init.lua @@ -192,16 +192,42 @@ local function CalcWheel(Entity, Link, Wheel, SelfWorld) return BaseRPM / Entity.GearRatio / -6 end -local function ActWheel(Link, Wheel, Torque, Brake, DeltaTime) +-- TODO: Mix ActWheel and BrakeWheel into a single function again, gearboxes should think by themselves +local function ActWheel(Link, Wheel, Torque, DeltaTime) local Phys = Wheel:GetPhysicsObject() + + if not Phys:IsMotionEnabled() then return end -- skipping entirely if its frozen + + local TorqueAxis = Phys:LocalToWorldVector(Link.Axis) + + Phys:ApplyTorqueCenter(TorqueAxis * Clamp(math.deg(-Torque * 1.5) * DeltaTime, -500000, 500000)) +end + +local function BrakeWheel(Link, Wheel, Brake, DeltaTime) + local Phys = Wheel:GetPhysicsObject() + + if not Phys:IsMotionEnabled() then return end -- skipping entirely if its frozen + local TorqueAxis = Phys:LocalToWorldVector(Link.Axis) - local BrakeMult = 0 + local Velocity = Phys:GetVelocity():Length() + local BrakeMult = Link.Vel * Brake - if Brake > 0 then - BrakeMult = Link.Vel * Link.Inertia * Brake / 5 + -- TODO: Add a proper method to deal with parking brakes + if Velocity < 1 then + BrakeMult = BrakeMult * (1 - Velocity) end - Phys:ApplyTorqueCenter(TorqueAxis * Clamp(math.deg(-Torque * 1.5 - BrakeMult) * DeltaTime, -500000, 500000)) + Phys:ApplyTorqueCenter(TorqueAxis * Clamp(math.deg(-BrakeMult) * DeltaTime, -500000, 500000)) +end + +local function SetCanApplyBrakes(Gearbox) + local CanApply = Gearbox.LBrake ~= 0 or Gearbox.RBrake ~= 0 + + if CanApply ~= Gearbox.Braking then + Gearbox.Braking = CanApply + + Gearbox:ApplyBrakes() + end end --===============================================================================================-- @@ -317,8 +343,7 @@ do -- Spawn and Update functions Entity.MinGear = Class.Gears.Min Entity.MaxGear = Class.Gears.Max Entity.GearCount = Entity.MaxGear - Entity.LClutch = Entity.MaxTorque - Entity.RClutch = Entity.MaxTorque + Entity.DualClutch = Gearbox.DualClutch Entity.In = Entity:WorldToLocal(Entity:GetAttachment(Entity:LookupAttachment("input")).Pos) Entity.OutL = Entity:WorldToLocal(Entity:GetAttachment(Entity:LookupAttachment("driveshaftL")).Pos) Entity.OutR = Entity:WorldToLocal(Entity:GetAttachment(Entity:LookupAttachment("driveshaftR")).Pos) @@ -344,7 +369,7 @@ do -- Spawn and Update functions -- Some information may still be passed from the menu tool -- We don't want to save it on the entity if it's not needed - local function CleanupData(Class, Gearbox, _, _, GearboxData) + local function CleanupData(Class, Gearbox) if Class ~= "acf_gearbox" then return end if not Gearbox.Automatic then @@ -356,19 +381,19 @@ do -- Spawn and Update functions Gearbox.MaxRPM = nil end - if GearboxData.DualClutch then + if Gearbox.DualClutch then Gearbox:SetBodygroup(1, 1) end end hook.Add("ACF_OnEntitySpawn", "ACF Cleanup Gearbox Data", CleanupData) hook.Add("ACF_OnEntityUpdate", "ACF Cleanup Gearbox Data", CleanupData) - hook.Add("ACF_OnSetupInputs", "ACF Cleanup Gearbox Data", function(Class, List, _, _, _, GearboxData) + hook.Add("ACF_OnSetupInputs", "ACF Cleanup Gearbox Data", function(Class, List, Entity) if Class ~= "acf_gearbox" then return end local Count = #List - if GearboxData.DualClutch then + if Entity.DualClutch then List[Count + 1] = "Left Clutch" List[Count + 2] = "Right Clutch" List[Count + 3] = "Left Brake" @@ -407,19 +432,23 @@ do -- Spawn and Update functions Player:AddCleanup("acfmenu", Gearbox) Player:AddCount(Limit, Gearbox) - Gearbox.Owner = Player -- MUST be stored on ent for PP - Gearbox.Engines = {} - Gearbox.Wheels = {} -- a "Link" has these components: Ent, Side, Axis, Rope, RopeLen, Output, ReqTq, Vel - Gearbox.GearboxIn = {} - Gearbox.GearboxOut = {} - Gearbox.TotalReqTq = 0 - Gearbox.TorqueOutput = 0 - Gearbox.LBrake = 0 - Gearbox.RBrake = 0 - Gearbox.ChangeFinished = 0 - Gearbox.InGear = false - Gearbox.LastActive = 0 - Gearbox.DataStore = ACF.GetEntityArguments("acf_gearbox") + Gearbox.Owner = Player -- MUST be stored on ent for PP + Gearbox.Engines = {} + Gearbox.Wheels = {} -- a "Link" has these components: Ent, Side, Axis, Rope, RopeLen, Output, ReqTq, Vel + Gearbox.GearboxIn = {} + Gearbox.GearboxOut = {} + Gearbox.TotalReqTq = 0 + Gearbox.TorqueOutput = 0 + Gearbox.LBrake = 0 + Gearbox.RBrake = 0 + Gearbox.ChangeFinished = 0 + Gearbox.InGear = false + Gearbox.Braking = false + Gearbox.LastBrakeThink = 0 + Gearbox.LastActive = 0 + Gearbox.LClutch = 1 + Gearbox.RClutch = 1 + Gearbox.DataStore = ACF.GetEntityArguments("acf_gearbox") UpdateGearbox(Gearbox, Data, Class, GearboxData) @@ -678,29 +707,35 @@ ACF.AddInputAction("acf_gearbox", "Gear Down", function(Entity, Value) end) ACF.AddInputAction("acf_gearbox", "Clutch", function(Entity, Value) - Entity.LClutch = Clamp(1 - Value, 0, 1) * Entity.MaxTorque - Entity.RClutch = Clamp(1 - Value, 0, 1) * Entity.MaxTorque + Entity.LClutch = Clamp(1 - Value, 0, 1) + Entity.RClutch = Clamp(1 - Value, 0, 1) end) ACF.AddInputAction("acf_gearbox", "Left Clutch", function(Entity, Value) - Entity.LClutch = Clamp(1 - Value, 0, 1) * Entity.MaxTorque + Entity.LClutch = Clamp(1 - Value, 0, 1) end) ACF.AddInputAction("acf_gearbox", "Right Clutch", function(Entity, Value) - Entity.RClutch = Clamp(1 - Value, 0, 1) * Entity.MaxTorque + Entity.RClutch = Clamp(1 - Value, 0, 1) end) ACF.AddInputAction("acf_gearbox", "Brake", function(Entity, Value) Entity.LBrake = Clamp(Value, 0, 100) Entity.RBrake = Clamp(Value, 0, 100) + + SetCanApplyBrakes(Entity) end) ACF.AddInputAction("acf_gearbox", "Left Brake", function(Entity, Value) Entity.LBrake = Clamp(Value, 0, 100) + + SetCanApplyBrakes(Entity) end) ACF.AddInputAction("acf_gearbox", "Right Brake", function(Entity, Value) Entity.RBrake = Clamp(Value, 0, 100) + + SetCanApplyBrakes(Entity) end) ACF.AddInputAction("acf_gearbox", "CVT Ratio", function(Entity, Value) @@ -795,7 +830,7 @@ function ENT:Calc(InputRPM, InputInertia) self.TorqueOutput = 0 for Ent, Link in pairs(self.GearboxOut) do - local Clutch = self.MainClutch + local Clutch = Link.Side == 0 and self.LClutch or self.RClutch Link.ReqTq = 0 @@ -817,7 +852,7 @@ function ENT:Calc(InputRPM, InputInertia) Link.ReqTq = 0 if self.GearRatio ~= 0 then - local Clutch = self.Dual and ((Link.Side == 0 and self.LClutch) or self.RClutch) or self.MainClutch + local Clutch = Link.Side == 0 and self.LClutch or self.RClutch local OnRPM = ((InputRPM > 0 and RPM < InputRPM) or (InputRPM < 0 and RPM > InputRPM)) if Clutch > 0 and OnRPM then diff --git a/lua/entities/acf_gun/cl_init.lua b/lua/entities/acf_gun/cl_init.lua index 7e215c163..4db336711 100644 --- a/lua/entities/acf_gun/cl_init.lua +++ b/lua/entities/acf_gun/cl_init.lua @@ -74,6 +74,7 @@ function ENT:Animate(ReloadTime, LoadOnly) self.Reload = ReloadTime end +-- DELETE function ACFGunGUICreate(Table) acfmenupanel:CPanelText("Name", Table.name) acfmenupanel.CData.DisplayModel = vgui.Create("DModelPanel", acfmenupanel.CustomDisplay) diff --git a/lua/entities/acf_gun/init.lua b/lua/entities/acf_gun/init.lua index 856d92289..5f6b2990b 100644 --- a/lua/entities/acf_gun/init.lua +++ b/lua/entities/acf_gun/init.lua @@ -39,6 +39,7 @@ do -- Spawn and Update functions -------------------------------- local Updated = { ["20mmHRAC"] = "20mmRAC", ["30mmHRAC"] = "30mmRAC", + ["40mmCL"] = "40mmGL", } local function VerifyData(Data) diff --git a/lua/entities/gmod_wire_expression2/core/custom/acffunctions.lua b/lua/entities/gmod_wire_expression2/core/custom/acffunctions.lua index dd18be4f6..c640f2168 100644 --- a/lua/entities/gmod_wire_expression2/core/custom/acffunctions.lua +++ b/lua/entities/gmod_wire_expression2/core/custom/acffunctions.lua @@ -14,7 +14,7 @@ E2Lib.RegisterExtension("acf", true) local RestrictInfoConVar = GetConVar("acf_restrict_info") local AllLinkSources = ACF.GetAllLinkSources local LinkSource = ACF.GetLinkSource -local RoundTypes = ACF.RoundTypes +local RoundTypes = ACF.RoundTypes -- REPLACE local match = string.match local floor = math.floor local Round = math.Round diff --git a/lua/starfall/libs_sv/acffunctions.lua b/lua/starfall/libs_sv/acffunctions.lua index f47969727..dca112428 100644 --- a/lua/starfall/libs_sv/acffunctions.lua +++ b/lua/starfall/libs_sv/acffunctions.lua @@ -489,7 +489,7 @@ end -- Set ammo properties local ammo_properties = {} -for id, data in pairs(ACF.RoundTypes) do +for id, data in pairs(ACF.RoundTypes) do -- REPLACE ammo_properties[id] = { name = data.name, desc = data.desc, @@ -1004,7 +1004,7 @@ function ents_methods:acfName () if isGun( this ) then acftype = "Guns" end if ( acftype == "" ) then return "" end local List = list.Get( "ACFEnts" ) - return List[ acftype ][ this.Id ][ "name" ] or "" + return List[ acftype ][ this.Id ][ "name" ] or "" -- REPLACE end --- Returns the type of ACF entity @@ -1017,11 +1017,11 @@ function ents_methods:acfType () if isEngine( this ) or isGearbox( this ) then local List = list.Get( "ACFEnts" ) - return List[ "Mobility" ][ this.Id ][ "category" ] or "" + return List[ "Mobility" ][ this.Id ][ "category" ] or "" -- REPLACE end if isGun( this ) then local Classes = list.Get( "ACFClasses" ) - return Classes[ "GunClass" ][ this.Class ][ "name" ] or "" + return Classes[ "GunClass" ][ this.Class ][ "name" ] or "" -- REPLACE end if isAmmo( this ) then return this.AmmoType or "" end if isFuel( this ) then return this.FuelType or "" end @@ -2084,9 +2084,9 @@ function ents_methods:acfPenetration () Energy = ACF_Kinetic(this.BulletData["MuzzleVel"]*39.37, this.BulletData["ProjMass"] - (this.BulletData["FillerMass"] or 0), this.BulletData["LimitVel"] ) return math.Round((Energy.Penetration/this.BulletData["PenArea"])*ACF.KEtoRHA,3) elseif Type == "HEAT" then - local Crushed, HEATFillerMass, BoomFillerMass = ACF.RoundTypes["HEAT"].CrushCalc(this.BulletData.MuzzleVel, this.BulletData.FillerMass) + local Crushed, HEATFillerMass, BoomFillerMass = ACF.RoundTypes["HEAT"].CrushCalc(this.BulletData.MuzzleVel, this.BulletData.FillerMass) -- REPLACE if Crushed == 1 then return 0 end -- no HEAT jet to fire off, it was all converted to HE - Energy = ACF_Kinetic(ACF.RoundTypes["HEAT"].CalcSlugMV( this.BulletData, HEATFillerMass )*39.37, this.BulletData["SlugMass"], 9999999 ) + Energy = ACF_Kinetic(ACF.RoundTypes["HEAT"].CalcSlugMV( this.BulletData, HEATFillerMass )*39.37, this.BulletData["SlugMass"], 9999999 ) -- REPLACE return math.Round((Energy.Penetration/this.BulletData["SlugPenArea"])*ACF.KEtoRHA,3) elseif Type == "FL" then Energy = ACF_Kinetic(this.BulletData["MuzzleVel"]*39.37 , this.BulletData["FlechetteMass"], this.BulletData["LimitVel"] ) @@ -2365,7 +2365,7 @@ function ents_methods:acfFuelUse () Consumption = 60 * ( this.Torque * this.FlyRPM / 9548.8 ) * this.FuelUse else local Load = 0.3 + this.Throttle * 0.7 - Consumption = 60 * Load * this.FuelUse * ( this.FlyRPM / this.PeakKwRPM ) / ACF.FuelDensity[ tank.FuelType ] + Consumption = 60 * Load * this.FuelUse * ( this.FlyRPM / this.PeakKwRPM ) / ACF.FuelDensity[ tank.FuelType ] -- REPLACE end return math.Round( Consumption, 3 ) end @@ -2394,7 +2394,7 @@ function ents_methods:acfPeakFuelUse () Consumption = 60 * ( this.PeakTorque * this.LimitRPM / ( 4 * 9548.8 ) ) * this.FuelUse else local Load = 0.3 + this.Throttle * 0.7 - Consumption = 60 * this.FuelUse / ACF.FuelDensity[ fuel ] + Consumption = 60 * this.FuelUse / ACF.FuelDensity[ fuel ] -- REPLACE end return math.Round( Consumption, 3 ) end diff --git a/lua/weapons/acf_base/init.lua b/lua/weapons/acf_base/init.lua index 362b2b758..acf3db620 100644 --- a/lua/weapons/acf_base/init.lua +++ b/lua/weapons/acf_base/init.lua @@ -6,9 +6,9 @@ SWEP.AutoSwitchFrom = false function SWEP:Initialize() self.Primary.BulletData = {} - self.ConvertData = ACF.RoundTypes[self.Primary.UserData["Type"]]["convert"] --Call the correct function for this round type to convert user input data into ballistics data + self.ConvertData = ACF.RoundTypes[self.Primary.UserData["Type"]]["convert"] -- REPLACE self.Primary.BulletData = self:ConvertData(self.Primary.UserData) --Put the results into the BulletData table - self.NetworkData = ACF.RoundTypes[self.Primary.UserData["Type"]]["network"] + self.NetworkData = ACF.RoundTypes[self.Primary.UserData["Type"]]["network"] -- REPLACE self:NetworkData(self.Primary.BulletData) if (SERVER) then @@ -57,7 +57,7 @@ function SWEP:CrateReload() AmmoEnt.Ammo = AmmoEnt.Ammo - Transfert self.Owner:GiveAmmo(Transfert, self.Primary.Ammo) self.Primary.BulletData = AmmoEnt.BulletData - self.NetworkData = ACF.RoundTypes[AmmoEnt.RoundType]["network"] + self.NetworkData = ACF.RoundTypes[AmmoEnt.RoundType]["network"] -- REPLACE self:NetworkData(self.Primary.BulletData) return true diff --git a/lua/weapons/acf_base/shared.lua b/lua/weapons/acf_base/shared.lua index 6faec873b..ddd806cc9 100644 --- a/lua/weapons/acf_base/shared.lua +++ b/lua/weapons/acf_base/shared.lua @@ -77,7 +77,7 @@ function SWEP:PrimaryAttack() self.Primary.BulletData["Owner"] = self.Owner self.Primary.BulletData["Gun"] = self.Owner self.Primary.BulletData["Crate"] = self:EntIndex() - self.CreateShell = ACF.RoundTypes[self.Primary.BulletData["Type"]]["create"] + self.CreateShell = ACF.RoundTypes[self.Primary.BulletData["Type"]]["create"] -- REPLACE self:CreateShell( self.Primary.BulletData ) self:TakePrimaryAmmo(1) diff --git a/lua/weapons/gmod_tool/stools/acfsound.lua b/lua/weapons/gmod_tool/stools/acfsound.lua index c1104fc74..843a788e3 100644 --- a/lua/weapons/gmod_tool/stools/acfsound.lua +++ b/lua/weapons/gmod_tool/stools/acfsound.lua @@ -27,7 +27,7 @@ ACF.SoundToolSupport = { local Classes = ACF.Classes local soundData = { - Sound = Classes["GunClass"][Class]["sound"] + Sound = Classes["GunClass"][Class]["sound"] -- REPLACE } local setSound = ACF.SoundToolSupport["acf_gun"].SetSound From 0aa0566344979bd24d836bcc37fac56253f626dd Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sat, 14 Nov 2020 00:40:33 -0300 Subject: [PATCH 143/279] Changed ballistics to use new ammo type classes - Both server-side and client-side ballistic events will now use information from the new ammo type classes. - Removed debug line on ACF.Trace. - Removed duplicated client-side ACF_CheckClip and ACF.Trace functions. --- lua/acf/base/util/sh_util.lua | 2 -- lua/acf/client/cl_ballistics.lua | 49 ------------------------------ lua/acf/server/ballistics.lua | 14 +++++---- lua/acf/shared/ammo_types/heat.lua | 4 +-- lua/effects/acf_bullet_effect.lua | 11 ++++--- 5 files changed, 17 insertions(+), 63 deletions(-) diff --git a/lua/acf/base/util/sh_util.lua b/lua/acf/base/util/sh_util.lua index d59a8a5e6..c15f6894c 100644 --- a/lua/acf/base/util/sh_util.lua +++ b/lua/acf/base/util/sh_util.lua @@ -161,8 +161,6 @@ do -- Trace functions return ACF.Trace(TraceData) end - debugoverlay.Line(TraceData.start, T.HitPos, 15, Color(0, 255, 0)) - return T end diff --git a/lua/acf/client/cl_ballistics.lua b/lua/acf/client/cl_ballistics.lua index 4930b54b5..f7de6bc87 100644 --- a/lua/acf/client/cl_ballistics.lua +++ b/lua/acf/client/cl_ballistics.lua @@ -1,52 +1,5 @@ ACF.BulletEffect = ACF.BulletEffect or {} -local TraceLine = util.TraceLine - -local function HitClip(Ent, Pos) - if not IsValid(Ent) then return false end - if Ent.ClipData == nil then return false end -- Doesn't have clips - if Ent:GetClass() ~= "prop_physics" then return false end -- Only care about props - - local Center = Ent:LocalToWorld(Ent:OBBCenter()) - - for I = 1, #Ent.ClipData do - local Clip = Ent.ClipData[I] - local Normal = Ent:LocalToWorldAngles(Clip[1]):Forward() - local Origin = Center + Normal * Clip[2] - - if Normal:Dot((Origin - Pos):GetNormalized()) > 0 then return true end - end - - return false -end - -local function Trace(TraceData, Filter) -- Pass true on filter to have Trace make it's own copy of TraceData.filter to modify - if Filter == true then - Filter = TraceData.filter - local NewFilter = {} - - for I = 1, #Filter do - NewFilter[I] = Filter[I] - end - - TraceData.filter = NewFilter - end - - local T = TraceLine(TraceData) - - if T.HitNonWorld and HitClip(T.Entity, T.HitPos) then - TraceData.filter[#TraceData.filter + 1] = T.Entity - - return Trace(TraceData, Filter) - end - - if Filter then - TraceData.filter = Filter - end - - return T -end - local function BulletFlight(Bullet) local DeltaTime = CurTime() - Bullet.LastThink local Drag = Bullet.SimFlight:GetNormalized() * (Bullet.DragCoef * Bullet.SimFlight:Length() ^ 2 ) / ACF.DragDiv @@ -71,5 +24,3 @@ hook.Add("Think", "ACF_ManageBulletEffects", function() end) ACF_SimBulletFlight = BulletFlight -ACF_CheckClips = HitClip -ACF.Trace = Trace diff --git a/lua/acf/server/ballistics.lua b/lua/acf/server/ballistics.lua index 677c846c1..4b14bcdad 100644 --- a/lua/acf/server/ballistics.lua +++ b/lua/acf/server/ballistics.lua @@ -12,6 +12,7 @@ local FlightTr = { start = true, endpos = true, filter = true, mask = true } local BackRes = {} local BackTrace = { start = true, endpos = true, filter = true, mask = true, output = BackRes } local GlobalFilter = ACF.GlobalFilter +local AmmoTypes = ACF.Classes.AmmoTypes local Gravity = Vector(0, 0, -GetConVar("sv_gravity"):GetInt()) cvars.AddChangeCallback("sv_gravity", function(_, _, Value) @@ -239,7 +240,7 @@ function ACF.DoBulletsFlight(Index, Bullet) Bullet.Filter = Filter end - local RoundData = ACF.RoundTypes[Bullet.Type] + local RoundData = AmmoTypes[Bullet.Type] if Bullet.Fuze and Bullet.Fuze <= ACF.CurTime then if not util.IsInWorld(Bullet.Pos) then -- Outside world, just delete @@ -260,7 +261,7 @@ function ACF.DoBulletsFlight(Index, Bullet) ACF.BulletClient(Index, Bullet, "Update", 1, Pos) - RoundData.endflight(Index, Bullet, Pos, Bullet.Flight:GetNormalized()) + RoundData:OnFlightEnd(Index, Bullet, Pos, Bullet.Flight:GetNormalized()) end end end @@ -270,7 +271,7 @@ function ACF.DoBulletsFlight(Index, Bullet) Bullet.SkipNextHit = nil end elseif FlightRes.HitNonWorld and not GlobalFilter[FlightRes.Entity:GetClass()] then - local Retry = RoundData.propimpact(Index, Bullet, FlightRes.Entity, FlightRes.HitNormal, FlightRes.HitPos, FlightRes.HitGroup) + local Retry = RoundData:PropImpact(Index, Bullet, FlightRes.Entity, FlightRes.HitNormal, FlightRes.HitPos, FlightRes.HitGroup) if Retry == "Penetrated" then if Bullet.OnPenetrated then @@ -293,11 +294,12 @@ function ACF.DoBulletsFlight(Index, Bullet) ACF.BulletClient(Index, Bullet, "Update", 1, FlightRes.HitPos) - RoundData.endflight(Index, Bullet, FlightRes.HitPos, FlightRes.HitNormal) + --RoundData.endflight(Index, Bullet, FlightRes.HitPos, FlightRes.HitNormal) + RoundData:OnFlightEnd(Index, Bullet, FlightRes.HitPos, FlightRes.HitNormal) end elseif FlightRes.HitWorld then if not FlightRes.HitSky then - local Retry = RoundData.worldimpact(Index, Bullet, FlightRes.HitPos, FlightRes.HitNormal) + local Retry = RoundData:WorldImpact(Index, Bullet, FlightRes.HitPos, FlightRes.HitNormal) if Retry == "Penetrated" then if Bullet.OnPenetrated then @@ -320,7 +322,7 @@ function ACF.DoBulletsFlight(Index, Bullet) ACF.BulletClient(Index, Bullet, "Update", 1, FlightRes.HitPos) - RoundData.endflight(Index, Bullet, FlightRes.HitPos, FlightRes.HitNormal) + RoundData:OnFlightEnd(Index, Bullet, FlightRes.HitPos, FlightRes.HitNormal) end else if FlightRes.HitNormal == Vector(0, 0, -1) then diff --git a/lua/acf/shared/ammo_types/heat.lua b/lua/acf/shared/ammo_types/heat.lua index 04fe6e22c..699b4564c 100644 --- a/lua/acf/shared/ammo_types/heat.lua +++ b/lua/acf/shared/ammo_types/heat.lua @@ -189,8 +189,8 @@ if SERVER then Bullet.Detonated = true Bullet.InitTime = ACF.CurTime - Bullet.Flight = Bullet.Flight + Bullet.Flight:GetNormalized() * self:CalcSlugMV(Bullet, HEATFillerMass) * 39.37 - Bullet.NextPos = HitPos + Bullet.Flight = Bullet.Flight:GetNormalized() * self:CalcSlugMV(Bullet, HEATFillerMass) * 39.37 + Bullet.NextPos = HitPos Bullet.DragCoef = Bullet.SlugDragCoef Bullet.ProjMass = Bullet.SlugMass * (1 - Crushed) Bullet.Caliber = Bullet.SlugCaliber diff --git a/lua/effects/acf_bullet_effect.lua b/lua/effects/acf_bullet_effect.lua index 969ee4cb1..ee73ce5d5 100644 --- a/lua/effects/acf_bullet_effect.lua +++ b/lua/effects/acf_bullet_effect.lua @@ -1,3 +1,6 @@ + +local ACF = ACF +local AmmoTypes = ACF.Classes.AmmoTypes local Bullets = ACF.BulletEffect function EFFECT:Init(Data) @@ -20,7 +23,7 @@ function EFFECT:Init(Data) -- Scale encodes the hit type, so if it's 0 it's a new bullet, else it's an update so we need to remove the effect if Bullet and Hit > 0 then - local RoundData = ACF.RoundTypes[Bullet.AmmoType] -- REPLACE + local RoundData = AmmoTypes[Bullet.AmmoType] -- Updating old effect with new values Bullet.SimFlight = Flight @@ -28,15 +31,15 @@ function EFFECT:Init(Data) if Hit == 1 then -- Bullet has reached end of flight, remove old effect - RoundData.endeffect(Bullet.Effect, Bullet) + RoundData:ImpactEffect(Bullet.Effect, Bullet) Bullet.Effect.Kill = true elseif Hit == 2 then -- Bullet penetrated, don't remove old effect - RoundData.pierceeffect(Bullet.Effect, Bullet) + RoundData:PenetrationEffect(Bullet.Effect, Bullet) elseif Hit == 3 then -- Bullet ricocheted, don't remove old effect - RoundData.ricocheteffect(Bullet.Effect, Bullet) + RoundData:RicochetEffect(Bullet.Effect, Bullet) end -- We don't need this new effect, so we just remove it From fb436d56b855c175fafa5ecc25b736dca2de20fd Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sun, 15 Nov 2020 05:43:54 -0300 Subject: [PATCH 144/279] Edited traceline override - We'll now make sure TraceData is a table before inserting the zero vectors for the hull size - TraceData.mins vector is no longer negated as it had literally no effect. - The default traceline function will be available as util.LegacyTraceLine. --- lua/acf/base/sh_traceline.lua | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/lua/acf/base/sh_traceline.lua b/lua/acf/base/sh_traceline.lua index 0df7995ea..eafbb2246 100644 --- a/lua/acf/base/sh_traceline.lua +++ b/lua/acf/base/sh_traceline.lua @@ -9,14 +9,22 @@ -- Note from Dakota: Check impacts on wedge joints, especially if they are visclipped. Hitnormal might be fucked in some cases. -- Note from the wiki: This function may not always give desired results clientside due to certain physics mechanisms not existing on the client. -local Hull = util.TraceHull -local Zero = Vector() +-- Known issues: +-- MASK_SHOT ignores all entities. -function util.TraceLine(TraceData, ...) - if TraceData then - TraceData.mins = -Zero -- I wonder if negating it is necessary at all. - TraceData.maxs = Zero - end +if not util.LegacyTraceLine then + local Hull = util.TraceHull + local Zero = Vector() + + -- Available for use, just in case + util.LegacyTraceLine = util.TraceLine - return Hull(TraceData, ...) + function util.TraceLine(TraceData, ...) + if istable(TraceData) then + TraceData.mins = Zero + TraceData.maxs = Zero + end + + return Hull(TraceData, ...) + end end From 9297287d0b9c6d75a736e1effaa2cdff752403de Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sun, 15 Nov 2020 05:51:57 -0300 Subject: [PATCH 145/279] Fixed example config overriding globals - Fixed example userconfig file overriding two global ACF variables. - Reduced ACF.GunInnaccuracyScale from 1 to 0.5. --- lua/acf/base/acf_globals.lua | 2 +- lua/acf/shared/acf_userconfig_example.lua | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lua/acf/base/acf_globals.lua b/lua/acf/base/acf_globals.lua index 8404cb25a..3ba9a5b25 100644 --- a/lua/acf/base/acf_globals.lua +++ b/lua/acf/base/acf_globals.lua @@ -84,7 +84,7 @@ do -- ACF global vars -- Weapon Accuracy ACF.SpreadScale = 4 -- The maximum amount that damage can decrease a gun"s accuracy. Default 4x - ACF.GunInaccuracyScale = 1 -- A multiplier for gun accuracy. Must be between 0.5 and 4 + ACF.GunInaccuracyScale = 0.5 -- A multiplier for gun accuracy. Must be between 0.5 and 4 ACF.GunInaccuracyBias = 2 -- Higher numbers make shots more likely to be inaccurate. Choose between 0.5 to 4. Default is 2 (unbiased). -- Fuel diff --git a/lua/acf/shared/acf_userconfig_example.lua b/lua/acf/shared/acf_userconfig_example.lua index 93f0c8bb0..c57285cdc 100644 --- a/lua/acf/shared/acf_userconfig_example.lua +++ b/lua/acf/shared/acf_userconfig_example.lua @@ -12,6 +12,6 @@ -- There are more settings like this. Find them all in lua/autorun/shared/acf_globals.lua -ACF.EnableDefaultDP = true -- Enable the inbuilt damage protection system. -ACF.GunInaccuracyScale = 0.5 -- Make guns 2x more accurate by halving the spread scale. -ACF.GunInaccuracyBias = 1.2 -- Shots are more likely to be accurate with bias < 2 \ No newline at end of file +--ACF.EnableDefaultDP = true -- Enable the inbuilt damage protection system. +--ACF.GunInaccuracyScale = 1 -- Make guns 2x less accurate by increasing the spread scale. +--ACF.GunInaccuracyBias = 1.2 -- Shots are more likely to be accurate with bias < 2 \ No newline at end of file From 9b7f1ce3215b2f0b1dbcf514b66567b288fbf089 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Mon, 16 Nov 2020 21:28:11 -0300 Subject: [PATCH 146/279] Added basic ammo crate menu function - Added basic ammo crate menu creation and update functions. - Added ACF.GetCurrentAmmoData function for menu items that use the ammo crate menu function. - Added client-side ACF.LoadSortedList function to reduce the amount of copypaste of the same. - Adjusted all menus to use the new ACF.LoadSortedList instead of their local version. - Reduced the reload times for RACs. --- lua/acf/base/util/cl_util.lua | 39 ++++ lua/acf/client/cl_ammo_menu.lua | 161 +++++++++++++++ lua/acf/client/menu_items/components_menu.lua | 41 +--- lua/acf/client/menu_items/engines_menu.lua | 59 ++---- lua/acf/client/menu_items/gearboxes_menu.lua | 41 +--- lua/acf/client/menu_items/sensors_menu.lua | 41 +--- lua/acf/client/menu_items/weapons_menu.lua | 187 ++---------------- lua/acf/shared/ammo_types/refill.lua | 5 +- lua/acf/shared/guns/rotaryautocannon.lua | 6 +- lua/entities/acf_ammo/init.lua | 14 +- 10 files changed, 253 insertions(+), 341 deletions(-) create mode 100644 lua/acf/client/cl_ammo_menu.lua diff --git a/lua/acf/base/util/cl_util.lua b/lua/acf/base/util/cl_util.lua index 72f512916..283f79cf7 100644 --- a/lua/acf/base/util/cl_util.lua +++ b/lua/acf/base/util/cl_util.lua @@ -1,4 +1,5 @@ local ACF = ACF + do -- Clientside chat messages local Types = { Normal = { @@ -354,3 +355,41 @@ do -- Clientside visclip check return false end end + +do -- Panel helpers + local Sorted = {} + + function ACF.LoadSortedList(Panel, List, Member) + local Data = Sorted[List] + + if not Data then + local Choices = {} + local Count = 0 + + for _, Value in pairs(List) do + Count = Count + 1 + + Choices[Count] = Value + end + + table.SortByMember(Choices, Member, true) + + Data = { + Choices = Choices, + Index = 1, + } + + Sorted[List] = Data + end + + local Current = Data.Index + + Panel.ListData = Data + + Panel:Clear() + + for Index, Value in ipairs(Data.Choices) do + Panel:AddChoice(Value.Name, Value, Index == Current) + end + end +end \ No newline at end of file diff --git a/lua/acf/client/cl_ammo_menu.lua b/lua/acf/client/cl_ammo_menu.lua new file mode 100644 index 000000000..23439f445 --- /dev/null +++ b/lua/acf/client/cl_ammo_menu.lua @@ -0,0 +1,161 @@ + +local ACF = ACF +local AmmoTypes = ACF.Classes.AmmoTypes +local CurrentAmmo, AmmoData + +local function GetAmmoList(Class) + local Result = {} + + for K, V in pairs(AmmoTypes) do + if V.Unlistable then continue end + if V.Blacklist[Class] then continue end + + Result[K] = V + end + + return Result +end + +function ACF.GetCurrentAmmoData() + return AmmoData +end + +function ACF.UpdateAmmoMenu(Menu) + local Ammo = CurrentAmmo + + if not Ammo then return end + + local ToolData = ACF.GetToolData() + local Base = Menu.AmmoBase + + AmmoData = Ammo:ClientConvert(ToolData) + + Menu:ClearTemporal(Base) + Menu:StartTemporal(Base) + + if not Ammo.SupressDefaultMenu then + local RoundLength = Base:AddLabel() + RoundLength:TrackDataVar("Projectile", "SetText") + RoundLength:TrackDataVar("Propellant") + RoundLength:TrackDataVar("Tracer") + RoundLength:SetValueFunction(function() + local Text = "Round Length: %s / %s cm" + local CurLength = AmmoData.ProjLength + AmmoData.PropLength + AmmoData.Tracer + local MaxLength = AmmoData.MaxRoundLength + + return Text:format(CurLength, MaxLength) + end) + + local Projectile = Base:AddSlider("Projectile Length", 0, AmmoData.MaxRoundLength, 2) + Projectile:SetDataVar("Projectile", "OnValueChanged") + Projectile:SetValueFunction(function(Panel, IsTracked) + ToolData.Projectile = ACF.ReadNumber("Projectile") + + if not IsTracked then + AmmoData.Priority = "Projectile" + end + + Ammo:UpdateRoundData(ToolData, AmmoData) + + ACF.WriteValue("Propellant", AmmoData.PropLength) + + Panel:SetValue(AmmoData.ProjLength) + + return AmmoData.ProjLength + end) + + local Propellant = Base:AddSlider("Propellant Length", 0, AmmoData.MaxRoundLength, 2) + Propellant:SetDataVar("Propellant", "OnValueChanged") + Propellant:SetValueFunction(function(Panel, IsTracked) + ToolData.Propellant = ACF.ReadNumber("Propellant") + + if not IsTracked then + AmmoData.Priority = "Propellant" + end + + Ammo:UpdateRoundData(ToolData, AmmoData) + + ACF.WriteValue("Projectile", AmmoData.ProjLength) + + Panel:SetValue(AmmoData.PropLength) + + return AmmoData.PropLength + end) + end + + if Ammo.MenuAction then + Ammo:MenuAction(Base, ToolData, AmmoData) + end + + Base:AddLabel("This entity can be fully parented.") + + Menu:EndTemporal(Base) +end + +function ACF.CreateAmmoMenu(Menu) + Menu:AddTitle("Ammo Settings") + + local List = Menu:AddComboBox() + + local SizeX = Menu:AddSlider("Crate Width", 6, 96, 2) + SizeX:SetDataVar("CrateSizeX", "OnValueChanged") + SizeX:SetValueFunction(function(Panel) + local Value = ACF.ReadNumber("CrateSizeX") + + Panel:SetValue(Value) + + return Value + end) + + local SizeY = Menu:AddSlider("Crate Height", 6, 96, 2) + SizeY:SetDataVar("CrateSizeY", "OnValueChanged") + SizeY:SetValueFunction(function(Panel) + local Value = ACF.ReadNumber("CrateSizeY") + + Panel:SetValue(Value) + + return Value + end) + + local SizeZ = Menu:AddSlider("Crate Depth", 6, 96, 2) + SizeZ:SetDataVar("CrateSizeZ", "OnValueChanged") + SizeZ:SetValueFunction(function(Panel) + local Value = ACF.ReadNumber("CrateSizeZ") + + Panel:SetValue(Value) + + return Value + end) + + local Base = Menu:AddCollapsible("Ammo Information") + local Desc = Base:AddLabel() + + local Preview = Base:AddModelPreview() + Preview:SetCamPos(Vector(45, 45, 30)) + Preview:SetHeight(120) + Preview:SetFOV(50) + + function List:LoadEntries(Class) + ACF.LoadSortedList(self, GetAmmoList(Class), "Name") + end + + function List:OnSelect(Index, _, Data) + if self.Selected == Data then return end + + self.ListData.Index = Index + self.Selected = Data + + CurrentAmmo = Data + + ACF.WriteValue("AmmoType", Data.ID) + + Desc:SetText(Data.Description) + Preview:SetModel(Data.Model) + + ACF.UpdateAmmoMenu(Menu) + end + + Menu.AmmoBase = Base + + return List +end diff --git a/lua/acf/client/menu_items/components_menu.lua b/lua/acf/client/menu_items/components_menu.lua index b8e8321dd..197aa2e8c 100644 --- a/lua/acf/client/menu_items/components_menu.lua +++ b/lua/acf/client/menu_items/components_menu.lua @@ -1,33 +1,5 @@ +local ACF = ACF local Components = ACF.Classes.Components -local Selected = {} -local Sorted = {} - -local function LoadSortedList(Panel, List, Member) - local Choices = Sorted[List] - - if not Choices then - Choices = {} - - local Count = 0 - for _, V in pairs(List) do - Count = Count + 1 - Choices[Count] = V - end - - table.SortByMember(Choices, Member, true) - - Sorted[List] = Choices - Selected[Choices] = 1 - end - - Panel:Clear() - - for _, V in pairs(Choices) do - Panel:AddChoice(V.Name, V) - end - - Panel:ChooseOptionID(Selected[Choices]) -end local function CreateMenu(Menu) ACF.WriteValue("PrimaryClass", "N/A") @@ -54,25 +26,22 @@ local function CreateMenu(Menu) function ComponentClass:OnSelect(Index, _, Data) if self.Selected == Data then return end + self.ListData.Index = Index self.Selected = Data - local Choices = Sorted[Components] - Selected[Choices] = Index - ACF.WriteValue("ComponentClass", Data.ID) - LoadSortedList(ComponentList, Data.Items, "ID") + ACF.LoadSortedList(ComponentList, Data.Items, "ID") end function ComponentList:OnSelect(Index, _, Data) if self.Selected == Data then return end + self.ListData.Index = Index self.Selected = Data local Preview = Data.Preview local ClassData = ComponentClass.Selected - local Choices = Sorted[ClassData.Items] - Selected[Choices] = Index ACF.WriteValue("Component", Data.ID) @@ -97,7 +66,7 @@ local function CreateMenu(Menu) Menu:EndTemporal(Base) end - LoadSortedList(ComponentClass, Components, "ID") + ACF.LoadSortedList(ComponentClass, Components, "ID") end ACF.AddMenuItem(501, "Entities", "Components", "drive", CreateMenu) diff --git a/lua/acf/client/menu_items/engines_menu.lua b/lua/acf/client/menu_items/engines_menu.lua index 615a5f2f1..7d4b04b6d 100644 --- a/lua/acf/client/menu_items/engines_menu.lua +++ b/lua/acf/client/menu_items/engines_menu.lua @@ -1,36 +1,8 @@ +local ACF = ACF local EngineTypes = ACF.Classes.EngineTypes local FuelTypes = ACF.Classes.FuelTypes local FuelTanks = ACF.Classes.FuelTanks local Engines = ACF.Classes.Engines -local Selected = {} -local Sorted = {} - -local function LoadSortedList(Panel, List, Member) - local Choices = Sorted[List] - - if not Choices then - Choices = {} - - local Count = 0 - for _, V in pairs(List) do - Count = Count + 1 - Choices[Count] = V - end - - table.SortByMember(Choices, Member, true) - - Sorted[List] = Choices - Selected[Choices] = 1 - end - - Panel:Clear() - - for _, V in pairs(Choices) do - Panel:AddChoice(V.Name, V) - end - - Panel:ChooseOptionID(Selected[Choices]) -end local function UpdateEngineStats(Label, Data) local RPM = Data.RPM @@ -115,26 +87,23 @@ local function CreateMenu(Menu) function EngineClass:OnSelect(Index, _, Data) if self.Selected == Data then return end + self.ListData.Index = Index self.Selected = Data - local Choices = Sorted[Engines] - Selected[Choices] = Index - ACF.WriteValue("EngineClass", Data.ID) - LoadSortedList(EngineList, Data.Items, "Mass") + ACF.LoadSortedList(EngineList, Data.Items, "Mass") end function EngineList:OnSelect(Index, _, Data) if self.Selected == Data then return end + self.ListData.Index = Index self.Selected = Data local Preview = Data.Preview local ClassData = EngineClass.Selected local ClassDesc = ClassData.Description - local Choices = Sorted[ClassData.Items] - Selected[Choices] = Index ACF.WriteValue("Engine", Data.ID) @@ -149,30 +118,27 @@ local function CreateMenu(Menu) UpdateEngineStats(EngineStats, Data) - LoadSortedList(FuelType, Data.Fuel, "ID") + ACF.LoadSortedList(FuelType, Data.Fuel, "ID") end function FuelClass:OnSelect(Index, _, Data) if self.Selected == Data then return end + self.ListData.Index = Index self.Selected = Data - local Choices = Sorted[FuelTanks] - Selected[Choices] = Index - - LoadSortedList(FuelList, Data.Items, "ID") + ACF.LoadSortedList(FuelList, Data.Items, "ID") end function FuelList:OnSelect(Index, _, Data) if self.Selected == Data then return end + self.ListData.Index = Index self.Selected = Data local Preview = Data.Preview local ClassData = FuelClass.Selected local ClassDesc = ClassData.Description - local Choices = Sorted[ClassData.Items] - Selected[Choices] = Index self.Description = (ClassDesc and (ClassDesc .. "\n\n") or "") .. Data.Description @@ -190,12 +156,9 @@ local function CreateMenu(Menu) function FuelType:OnSelect(Index, _, Data) if self.Selected == Data then return end + self.ListData.Index = Index self.Selected = Data - local ClassData = EngineList.Selected - local Choices = Sorted[ClassData.Fuel] - Selected[Choices] = Index - ACF.WriteValue("FuelType", Data.ID) self:UpdateFuelText() @@ -237,8 +200,8 @@ local function CreateMenu(Menu) FuelInfo:SetText(FuelText) end - LoadSortedList(EngineClass, Engines, "ID") - LoadSortedList(FuelClass, FuelTanks, "ID") + ACF.LoadSortedList(EngineClass, Engines, "ID") + ACF.LoadSortedList(FuelClass, FuelTanks, "ID") end ACF.AddMenuItem(201, "Entities", "Engines", "car", CreateMenu) diff --git a/lua/acf/client/menu_items/gearboxes_menu.lua b/lua/acf/client/menu_items/gearboxes_menu.lua index fe5d44fae..91372c760 100644 --- a/lua/acf/client/menu_items/gearboxes_menu.lua +++ b/lua/acf/client/menu_items/gearboxes_menu.lua @@ -1,33 +1,5 @@ +local ACF = ACF local Gearboxes = ACF.Classes.Gearboxes -local Selected = {} -local Sorted = {} - -local function LoadSortedList(Panel, List, Member) - local Choices = Sorted[List] - - if not Choices then - Choices = {} - - local Count = 0 - for _, V in pairs(List) do - Count = Count + 1 - Choices[Count] = V - end - - table.SortByMember(Choices, Member, true) - - Sorted[List] = Choices - Selected[Choices] = 1 - end - - Panel:Clear() - - for _, V in pairs(Choices) do - Panel:AddChoice(V.Name, V) - end - - Panel:ChooseOptionID(Selected[Choices]) -end local function CreateMenu(Menu) Menu:AddTitle("Gearbox Settings") @@ -48,25 +20,22 @@ local function CreateMenu(Menu) function GearboxClass:OnSelect(Index, _, Data) if self.Selected == Data then return end + self.ListData.Index = Index self.Selected = Data - local Choices = Sorted[Gearboxes] - Selected[Choices] = Index - ACF.WriteValue("GearboxClass", Data.ID) - LoadSortedList(GearboxList, Data.Items, "ID") + ACF.LoadSortedList(GearboxList, Data.Items, "ID") end function GearboxList:OnSelect(Index, _, Data) if self.Selected == Data then return end + self.ListData.Index = Index self.Selected = Data local Preview = Data.Preview local ClassData = GearboxClass.Selected - local Choices = Sorted[ClassData.Items] - Selected[Choices] = Index ACF.WriteValue("Gearbox", Data.ID) @@ -89,7 +58,7 @@ local function CreateMenu(Menu) Menu:EndTemporal(Base) end - LoadSortedList(GearboxClass, Gearboxes, "ID") + ACF.LoadSortedList(GearboxClass, Gearboxes, "ID") end ACF.AddMenuItem(301, "Entities", "Gearboxes", "cog", CreateMenu) diff --git a/lua/acf/client/menu_items/sensors_menu.lua b/lua/acf/client/menu_items/sensors_menu.lua index c2b69d3e7..1d646349b 100644 --- a/lua/acf/client/menu_items/sensors_menu.lua +++ b/lua/acf/client/menu_items/sensors_menu.lua @@ -1,33 +1,5 @@ +local ACF = ACF local Sensors = ACF.Classes.Sensors -local Selected = {} -local Sorted = {} - -local function LoadSortedList(Panel, List, Member) - local Choices = Sorted[List] - - if not Choices then - Choices = {} - - local Count = 0 - for _, V in pairs(List) do - Count = Count + 1 - Choices[Count] = V - end - - table.SortByMember(Choices, Member, true) - - Sorted[List] = Choices - Selected[Choices] = 1 - end - - Panel:Clear() - - for _, V in pairs(Choices) do - Panel:AddChoice(V.Name, V) - end - - Panel:ChooseOptionID(Selected[Choices]) -end local function CreateMenu(Menu) ACF.WriteValue("PrimaryClass", "N/A") @@ -54,25 +26,22 @@ local function CreateMenu(Menu) function SensorClass:OnSelect(Index, _, Data) if self.Selected == Data then return end + self.ListData.Index = Index self.Selected = Data - local Choices = Sorted[Sensors] - Selected[Choices] = Index - ACF.WriteValue("SensorClass", Data.ID) - LoadSortedList(SensorList, Data.Items, "ID") + ACF.LoadSortedList(SensorList, Data.Items, "ID") end function SensorList:OnSelect(Index, _, Data) if self.Selected == Data then return end + self.ListData.Index = Index self.Selected = Data local Preview = Data.Preview local ClassData = SensorClass.Selected - local Choices = Sorted[ClassData.Items] - Selected[Choices] = Index ACF.WriteValue("Sensor", Data.ID) @@ -97,7 +66,7 @@ local function CreateMenu(Menu) Menu:EndTemporal(Base) end - LoadSortedList(SensorClass, Sensors, "ID") + ACF.LoadSortedList(SensorClass, Sensors, "ID") end ACF.AddMenuItem(401, "Entities", "Sensors", "transmit", CreateMenu) diff --git a/lua/acf/client/menu_items/weapons_menu.lua b/lua/acf/client/menu_items/weapons_menu.lua index 4145ba0de..d5b249eaf 100644 --- a/lua/acf/client/menu_items/weapons_menu.lua +++ b/lua/acf/client/menu_items/weapons_menu.lua @@ -1,59 +1,9 @@ -local AmmoTypes = ACF.Classes.AmmoTypes +local ACF = ACF local Weapons = ACF.Classes.Weapons -local Crates = ACF.Classes.Crates -local AmmoLists = {} -local Selected = {} -local Sorted = {} - -local function GetAmmoList(Class) - if not Class then return {} end - if AmmoLists[Class] then return AmmoLists[Class] end - - local Result = {} - - for K, V in pairs(AmmoTypes) do - if V.Unlistable then continue end - if V.Blacklist[Class] then continue end - - Result[K] = V - end - - AmmoLists[Class] = Result - - return Result -end - -local function LoadSortedList(Panel, List, Member) - local Choices = Sorted[List] - - if not Choices then - Choices = {} - - local Count = 0 - for _, V in pairs(List) do - Count = Count + 1 - Choices[Count] = V - end - - table.SortByMember(Choices, Member, true) - - Sorted[List] = Choices - Selected[Choices] = 1 - end - - Panel:Clear() - - for _, V in pairs(Choices) do - Panel:AddChoice(V.Name, V) - end - - Panel:ChooseOptionID(Selected[Choices]) -end local function CreateMenu(Menu) local EntText = "Mass : %s kg\nFirerate : %s rpm\nSpread : %s degrees%s\n\nThis entity can be fully parented." local MagText = "\nRounds : %s rounds\nReload : %s seconds" - local AmmoData Menu:AddTitle("Weapon Settings") @@ -66,14 +16,7 @@ local function CreateMenu(Menu) local EntPreview = WeaponBase:AddModelPreview() local EntData = WeaponBase:AddLabel() - Menu:AddTitle("Ammo Settings") - - local CrateList = Menu:AddComboBox() - local AmmoList = Menu:AddComboBox() - - local AmmoBase = Menu:AddCollapsible("Ammo Information") - local AmmoDesc = AmmoBase:AddLabel() - local AmmoPreview = AmmoBase:AddModelPreview() + local AmmoList = ACF.CreateAmmoMenu(Menu) ACF.WriteValue("PrimaryClass", "acf_gun") ACF.WriteValue("SecondaryClass", "acf_ammo") @@ -82,14 +25,15 @@ local function CreateMenu(Menu) local function UpdateEntityData() local Class = ClassList.Selected - local Data = EntList.Selected + local Data = EntList.Selected if not Class then return "" end if not Data then return "" end + local AmmoData = ACF.GetCurrentAmmoData() local ReloadTime = AmmoData and (ACF.BaseReload + (AmmoData.ProjMass + AmmoData.PropMass) * ACF.MassToTime) or 60 - local Firerate = Data.Cyclic or 60 / ReloadTime - local Magazine = Data.MagSize and MagText:format(Data.MagSize, Data.MagReload) or "" + local Firerate = Data.Cyclic or 60 / ReloadTime + local Magazine = Data.MagSize and MagText:format(Data.MagSize, Data.MagReload) or "" return EntText:format(Data.Mass, math.Round(Firerate, 2), Class.Spread * 100, Magazine) end @@ -97,28 +41,25 @@ local function CreateMenu(Menu) function ClassList:OnSelect(Index, _, Data) if self.Selected == Data then return end + self.ListData.Index = Index self.Selected = Data - local Choices = Sorted[Weapons] - Selected[Choices] = Index - ACF.WriteValue("WeaponClass", Data.ID) ClassDesc:SetText(Data.Description) - LoadSortedList(EntList, Data.Items, "Caliber") - LoadSortedList(AmmoList, GetAmmoList(Data.ID), "Name") + ACF.LoadSortedList(EntList, Data.Items, "Caliber") + + AmmoList:LoadEntries(Data.ID) end function EntList:OnSelect(Index, _, Data) if self.Selected == Data then return end + self.ListData.Index = Index self.Selected = Data local Preview = Data.Preview - local ClassData = ClassList.Selected - local Choices = Sorted[ClassData.Items] - Selected[Choices] = Index ACF.WriteValue("Weapon", Data.ID) ACF.WriteValue("Destiny", Data.Destiny or "Weapons") @@ -132,7 +73,7 @@ local function CreateMenu(Menu) EntPreview:SetHeight(Preview and Preview.Height or 80) EntPreview:SetFOV(Preview and Preview.FOV or 75) - AmmoList:UpdateMenu() + ACF.UpdateAmmoMenu(Menu) end EntData:TrackDataVar("Projectile", "SetText") @@ -140,109 +81,7 @@ local function CreateMenu(Menu) EntData:TrackDataVar("Tracer") EntData:SetValueFunction(UpdateEntityData) - function CrateList:OnSelect(Index, _, Data) - if self.Selected == Data then return end - - self.Selected = Data - - local Preview = Data.Preview - local Choices = Sorted[Crates] - Selected[Choices] = Index - - ACF.WriteValue("Crate", Data.ID) - - AmmoPreview:SetModel(Data.Model) - AmmoPreview:SetCamPos(Preview and Preview.Offset or Vector(45, 60, 45)) - AmmoPreview:SetLookAt(Preview and Preview.Position or Vector()) - AmmoPreview:SetHeight(Preview and Preview.Height or 80) - AmmoPreview:SetFOV(Preview and Preview.FOV or 75) - end - - function AmmoList:OnSelect(Index, _, Data) - if self.Selected == Data then return end - - self.Selected = Data - - local Choices = Sorted[GetAmmoList(ClassList.Selected.ID)] - Selected[Choices] = Index - - ACF.WriteValue("AmmoType", Data.ID) - - AmmoDesc:SetText(Data.Description .. "\n\nThis entity can be fully parented.") - - self:UpdateMenu() - end - - function AmmoList:UpdateMenu() - if not self.Selected then return end - - local Ammo = self.Selected - local ToolData = ACF.GetToolData() - - AmmoData = Ammo:ClientConvert(ToolData) - - Menu:ClearTemporal(AmmoBase) - Menu:StartTemporal(AmmoBase) - - if not Ammo.SupressDefaultMenu then - local RoundLength = AmmoBase:AddLabel() - RoundLength:TrackDataVar("Projectile", "SetText") - RoundLength:TrackDataVar("Propellant") - RoundLength:TrackDataVar("Tracer") - RoundLength:SetValueFunction(function() - local Text = "Round Length: %s / %s cm" - local CurLength = AmmoData.ProjLength + AmmoData.PropLength + AmmoData.Tracer - local MaxLength = AmmoData.MaxRoundLength - - return Text:format(CurLength, MaxLength) - end) - - local Projectile = AmmoBase:AddSlider("Projectile Length", 0, AmmoData.MaxRoundLength, 2) - Projectile:SetDataVar("Projectile", "OnValueChanged") - Projectile:SetValueFunction(function(Panel, IsTracked) - ToolData.Projectile = ACF.ReadNumber("Projectile") - - if not IsTracked then - AmmoData.Priority = "Projectile" - end - - Ammo:UpdateRoundData(ToolData, AmmoData) - - ACF.WriteValue("Propellant", AmmoData.PropLength) - - Panel:SetValue(AmmoData.ProjLength) - - return AmmoData.ProjLength - end) - - local Propellant = AmmoBase:AddSlider("Propellant Length", 0, AmmoData.MaxRoundLength, 2) - Propellant:SetDataVar("Propellant", "OnValueChanged") - Propellant:SetValueFunction(function(Panel, IsTracked) - ToolData.Propellant = ACF.ReadNumber("Propellant") - - if not IsTracked then - AmmoData.Priority = "Propellant" - end - - Ammo:UpdateRoundData(ToolData, AmmoData) - - ACF.WriteValue("Projectile", AmmoData.ProjLength) - - Panel:SetValue(AmmoData.PropLength) - - return AmmoData.PropLength - end) - end - - if Ammo.MenuAction then - Ammo:MenuAction(AmmoBase, ToolData, AmmoData) - end - - Menu:EndTemporal(AmmoBase) - end - - LoadSortedList(ClassList, Weapons, "Name") - LoadSortedList(CrateList, Crates, "ID") + ACF.LoadSortedList(ClassList, Weapons, "Name") end ACF.AddMenuItem(1, "Entities", "Weapons", "gun", CreateMenu) diff --git a/lua/acf/shared/ammo_types/refill.lua b/lua/acf/shared/ammo_types/refill.lua index 767185f2e..6fe5bfc0b 100644 --- a/lua/acf/shared/ammo_types/refill.lua +++ b/lua/acf/shared/ammo_types/refill.lua @@ -2,6 +2,7 @@ local Ammo = ACF.RegisterAmmoType("Refill", "AP") function Ammo:OnLoaded() self.Name = "Refill" + self.Model = "models/Items/BoxSRounds.mdl" self.Description = "Provides supplies to other ammo crates." self.Blacklist = {} self.SupressDefaultMenu = true @@ -12,8 +13,8 @@ function Ammo:GetDisplayData() end function Ammo:BaseConvert(ToolData) - local ProjMass = 5.5 * 0.079 --Volume of the projectile as a cylinder * streamline factor (Data5) * density of steel - local PropMass = 0.001 --Volume of the case as a cylinder * Powder density converted from g to kg + local ProjMass = 5.5 * 0.079 + local PropMass = 0.001 return { Id = "12.7mmMG", diff --git a/lua/acf/shared/guns/rotaryautocannon.lua b/lua/acf/shared/guns/rotaryautocannon.lua index 066a392db..08bbf3f35 100644 --- a/lua/acf/shared/guns/rotaryautocannon.lua +++ b/lua/acf/shared/guns/rotaryautocannon.lua @@ -88,7 +88,7 @@ ACF.RegisterWeapon("14.5mmRAC", "RAC", { Mass = 400, Year = 1962, MagSize = 250, - MagReload = 15, + MagReload = 10, Cyclic = 2250, Round = { MaxLength = 25, @@ -104,7 +104,7 @@ ACF.RegisterWeapon("20mmRAC", "RAC", { Mass = 760, Year = 1965, MagSize = 200, - MagReload = 20, + MagReload = 15, Cyclic = 2000, Round = { MaxLength = 30, @@ -120,7 +120,7 @@ ACF.RegisterWeapon("30mmRAC", "RAC", { Mass = 1500, Year = 1975, MagSize = 100, - MagReload = 30, + MagReload = 20, Cyclic = 1500, Round = { MaxLength = 40, diff --git a/lua/entities/acf_ammo/init.lua b/lua/entities/acf_ammo/init.lua index 539f7e802..0ec2f1e33 100644 --- a/lua/entities/acf_ammo/init.lua +++ b/lua/entities/acf_ammo/init.lua @@ -213,13 +213,15 @@ do -- Spawning and Updating -------------------- do -- Clamping size local Size = Data.Size - if isvector(Size) then - Size.x = math.Clamp(Size.x, 6, 96) - Size.y = math.Clamp(Size.y, 6, 96) - Size.z = math.Clamp(Size.z, 6, 96) - else - Data.Size = Vector(24, 24, 24) + if not isvector(Size) then + Size = Vector(Data.CrateSizeX or 24, Data.CrateSizeY or 24, Data.CrateSizeZ or 24) + + Data.Size = Size end + + Size.x = math.Clamp(Size.x, 6, 96) + Size.y = math.Clamp(Size.y, 6, 96) + Size.z = math.Clamp(Size.z, 6, 96) end if not Data.Destiny then From 89f4bfc6abf2daba868d2359e3e00af134040043 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Wed, 18 Nov 2020 22:16:36 -0300 Subject: [PATCH 147/279] Added class and class group creation hooks - Added shared ACF_OnNewSimpleClass, ACF_OnNewClassGroup and ACF_OnNewGroupedClass hooks. Called any time a simple class, a class group or a grouped class are registered to ACF. - Renamed OnClassLoaded hook to ACF_OnClassLoaded. - Actual classes will set a Loaded flag as true when they're loaded. - Moved ACF_CVarChangeCallback function to a proper scope. - Removed all unnecessary information from the new ammo crate registrations. We only need the size and offset after all. --- lua/acf/base/acf_globals.lua | 68 ++++++------ lua/acf/base/sh_classes.lua | 10 +- lua/acf/shared/ammo_crates/crates.lua | 144 -------------------------- 3 files changed, 42 insertions(+), 180 deletions(-) diff --git a/lua/acf/base/acf_globals.lua b/lua/acf/base/acf_globals.lua index 3ba9a5b25..77a58d332 100644 --- a/lua/acf/base/acf_globals.lua +++ b/lua/acf/base/acf_globals.lua @@ -135,6 +135,34 @@ do -- ACF global vars end do -- ACF Convars/Callbacks ------------------------ + function ACF_CVarChangeCallback(CVar, _, New) + if CVar == "acf_healthmod" then + ACF.Threshold = 264.7 / math.max(New, 0.01) + print("Health Mod changed to a factor of " .. New) + elseif CVar == "acf_armormod" then + ACF.ArmorMod = 1 * math.max(New, 0) + print("Armor Mod changed to a factor of " .. New) + elseif CVar == "acf_ammomod" then + ACF.AmmoMod = 1 * math.max(New, 0.01) + print("Ammo Mod changed to a factor of " .. New) + elseif CVar == "acf_fuelrate" then + local Value = tonumber(New) or 1 + + ACF.FuelRate = math.max(Value, 0.01) + + print("Fuel Rate changed to a factor of " .. Value) + elseif CVar == "acf_gunfire" then + ACF.GunfireEnabled = tobool(New) + local text = "disabled" + + if ACF.GunfireEnabled then + text = "enabled" + end + + print("ACF Gunfire has been " .. text) + end + end + CreateConVar("sbox_max_acf_ammo", 32) -- New healthmod/armormod/ammomod cvars CreateConVar("acf_healthmod", 1) @@ -222,21 +250,19 @@ elseif CLIENT then end --------------------------------------------- - -- Hitbox Updating -------------------------- + -- Clientside Updating -------------------------- net.Receive("ACF_UpdateEntity", function() local Entity = net.ReadEntity() - timer.Simple(0.1, function() - if not IsValid(Entity) then return end - if not isfunction(Entity.Update) then return end + if not IsValid(Entity) then return end + if not isfunction(Entity.Update) then return end - Entity:Update() - end) + Entity:Update() end) --------------------------------------------- end --- REPLACE or REMOVE? +-- DELETE timer.Simple(0, function() for _, Table in pairs(ACF.Classes.GunClass) do PrecacheParticleSystem(Table["muzzleflash"]) @@ -279,34 +305,6 @@ function ACF_Kinetic(Speed, Mass, LimitVel) return Energy end -function ACF_CVarChangeCallback(CVar, _, New) - if CVar == "acf_healthmod" then - ACF.Threshold = 264.7 / math.max(New, 0.01) - print("Health Mod changed to a factor of " .. New) - elseif CVar == "acf_armormod" then - ACF.ArmorMod = 1 * math.max(New, 0) - print("Armor Mod changed to a factor of " .. New) - elseif CVar == "acf_ammomod" then - ACF.AmmoMod = 1 * math.max(New, 0.01) - print("Ammo Mod changed to a factor of " .. New) - elseif CVar == "acf_fuelrate" then - local Value = tonumber(New) or 1 - - ACF.FuelRate = math.max(Value, 0.01) - - print("Fuel Rate changed to a factor of " .. Value) - elseif CVar == "acf_gunfire" then - ACF.GunfireEnabled = tobool(New) - local text = "disabled" - - if ACF.GunfireEnabled then - text = "enabled" - end - - print("ACF Gunfire has been " .. text) - end -end - do -- ACF Notify ----------------------------------- if SERVER then function ACF_SendNotify(ply, success, msg) diff --git a/lua/acf/base/sh_classes.lua b/lua/acf/base/sh_classes.lua index 7f2eb05d8..a385183dc 100644 --- a/lua/acf/base/sh_classes.lua +++ b/lua/acf/base/sh_classes.lua @@ -18,6 +18,8 @@ do -- Basic class registration functions Class[K] = V end + hook.Run("ACF_OnNewSimpleClass", ID, Class) + return Class end @@ -43,6 +45,8 @@ do -- Basic class registration functions Group[K] = V end + hook.Run("ACF_OnNewClassGroup", ID, Group) + return Group end @@ -89,6 +93,8 @@ do -- Basic class registration functions Class[K] = V end + hook.Run("ACF_OnNewGroupedClass", ID, Group, Class) + return Class end @@ -165,7 +171,9 @@ do -- Class registration function Class:OnLoaded() end - hook.Run("OnClassLoaded", Class.ID, Class) + hook.Run("ACF_OnClassLoaded", Class.ID, Class) + + Class.Loaded = true end) end diff --git a/lua/acf/shared/ammo_crates/crates.lua b/lua/acf/shared/ammo_crates/crates.lua index 337edbd26..f80659fcb 100644 --- a/lua/acf/shared/ammo_crates/crates.lua +++ b/lua/acf/shared/ammo_crates/crates.lua @@ -1,323 +1,179 @@ ACF.RegisterCrate("AmmoSmall", { - Name = "Small Ammo Crate", - Model = "models/ammocrate_small.mdl", - Mass = 10, - Volume = 2198, Size = Vector(20.44, 7.93, 13.77), Offset = Vector(-0.36, -0.01, 7.01) }) ACF.RegisterCrate("AmmoMedCube", { - Name = "Medium Cubic Ammo Crate", - Model = "models/ammocrate_medium_small.mdl", - Mass = 80, - Volume = 17769, Size = Vector(26.27, 25.9, 26.3), Offset = Vector(-0.03, 0.42, 13.1) }) ACF.RegisterCrate("AmmoMedium", { - Name = "Medium Ammo Crate", - Model = "models/ammocrate_medium.mdl", - Mass = 150, - Volume = 35105, Size = Vector(51.9, 26.27, 25.9), Offset = Vector(-0.12, 0.42, 13.1) }) ACF.RegisterCrate("AmmoLarge", { - Name = "Large Ammo Crate", - Model = "models/ammocrate_large.mdl", - Mass = 1000, - Volume = 140503, Size = Vector(52.17, 52.06, 51.92), Offset = Vector(-0.05, -0.38, 26.06) }) ACF.RegisterCrate("Ammo1x1x8", { - Name = "Modular 1x1x8 Ammo Crate", - Model = "models/ammocrates/ammo_1x1x8.mdl", - Mass = 40, - Volume = 10872, Size = Vector(11.09, 89.15, 11.13), Offset = Vector(0, -0.02, -0.12) }) ACF.RegisterCrate("Ammo1x1x6", { - Name = "Modular 1x1x6 Ammo Crate", - Model = "models/ammocrates/ammo_1x1x6.mdl", - Mass = 30, - Volume = 8202, Size = Vector(11.2, 66.51, 11.14), Offset = Vector(0, 0.02, -0.14) }) ACF.RegisterCrate("Ammo1x1x4", { - Name = "Modular 1x1x4 Ammo Crate", - Model = "models/ammocrates/ammo_1x1x4.mdl", - Mass = 20, - Volume = 5519, Size = Vector(11.16, 45.06, 11.11), Offset = Vector(0, 0.16, -0.17) }) ACF.RegisterCrate("Ammo1x1x2", { - Name = "Modular 1x1x2 Ammo Crate", - Model = "models/ammocrates/ammo_1x1x2.mdl", - Mass = 10, - Volume = 2743, Size = Vector(11.16, 22.43, 11.11), Offset = Vector(0, 0.05, -0.17) }) ACF.RegisterCrate("Ammo2x2x1", { - Name = "Modular 2x2x1 Ammo Crate", - Model = "models/ammocrates/ammocrate_2x2x1.mdl", - Mass = 20, - Volume = 3200, Size = Vector(20.06, 8.06, 20.06), Offset = Vector(-0.52, 0, 10.19) }) ACF.RegisterCrate("Ammo2x2x2", { - Name = "Modular 2x2x2 Ammo Crate", - Model = "models/ammocrates/ammocrate_2x2x2.mdl", - Mass = 40, - Volume = 8000, Size = Vector(20.06, 20.06, 20.06), Offset = Vector(-0.09, 0.51, 10.51) }) ACF.RegisterCrate("Ammo2x2x4", { - Name = "Modular 2x2x4 Ammo Crate", - Model = "models/ammocrates/ammocrate_2x2x4.mdl", - Mass = 80, - Volume = 18000, Size = Vector(20.06, 45.06, 20.06), Offset = Vector(-0.71, 0, 10.18) }) ACF.RegisterCrate("Ammo2x2x6", { - Name = "Modular 2x2x6 Ammo Crate", - Model = "models/ammocrates/ammo_2x2x6.mdl", - Mass = 120, - Volume = 33179, Size = Vector(22.45, 66.59, 22.33), Offset = Vector(0, 0, -0.1) }) ACF.RegisterCrate("Ammo2x2x8", { - Name = "Modular 2x2x8 Ammo Crate", - Model = "models/ammocrates/ammo_2x2x8.mdl", - Mass = 160, - Volume = 45902, Size = Vector(22.46, 90.1, 22.82), Offset = Vector(0, 0, -0.14) }) ACF.RegisterCrate("Ammo2x3x1", { - Name = "Modular 2x3x1 Ammo Crate", - Model = "models/ammocrates/ammocrate_2x3x1.mdl", - Mass = 30, - Volume = 5119, Size = Vector(32.06, 8.06, 20.06), Offset = Vector(-0.64, 0, 10.19) }) ACF.RegisterCrate("Ammo2x3x2", { - Name = "Modular 2x3x2 Ammo Crate", - Model = "models/ammocrates/ammocrate_2x3x2.mdl", - Mass = 60, - Volume = 12799, Size = Vector(32.06, 20.06, 20.06), Offset = Vector(-0.64, 0, 10.19) }) ACF.RegisterCrate("Ammo2x3x4", { - Name = "Modular 2x3x4 Ammo Crate", - Model = "models/ammocrates/ammocrate_2x3x4.mdl", - Mass = 120, - Volume = 28800, Size = Vector(32.06, 45.06, 20.06), Offset = Vector(-0.79, 0, 10) }) ACF.RegisterCrate("Ammo2x3x6", { - Name = "Modular 2x3x6 Ammo Crate", - Model = "models/ammocrates/ammocrate_2x3x6.mdl", - Mass = 180, - Volume = 43421, Size = Vector(31.94, 68.04, 20.1), Offset = Vector(-0.79, -0.04, 10.02) }) ACF.RegisterCrate("Ammo2x3x8", { - Name = "Modular 2x3x8 Ammo Crate", - Model = "models/ammocrates/ammocrate_2x3x8.mdl", - Mass = 240, - Volume = 57509, Size = Vector(31.94, 90.1, 20.1), Offset = Vector(-0.79, 0, 10.02) }) ACF.RegisterCrate("Ammo2x4x1", { - Name = "Modular 2x4x1 Ammo Crate", - Model = "models/ammocrates/ammocrate_2x4x1.mdl", - Mass = 40, - Volume = 7200, Size = Vector(45.06, 8.06, 20.06), Offset = Vector(-0.64, 0, 10.19) }) ACF.RegisterCrate("Ammo2x4x2", { - Name = "Modular 2x4x2 Ammo Crate", - Model = "models/ammocrates/ammocrate_2x4x2.mdl", - Mass = 80, - Volume = 18000, Size = Vector(45.06, 20.06, 20.06), Offset = Vector(-0.2, 0.71, 10.18) }) ACF.RegisterCrate("Ammo2x4x4", { - Name = "Modular 2x4x4 Ammo Crate", - Model = "models/ammocrates/ammocrate_2x4x4.mdl", - Mass = 160, - Volume = 40500, Size = Vector(45.06, 45.06, 20.06), Offset = Vector(-0.79, 0, 10) }) ACF.RegisterCrate("Ammo2x4x6", { - Name = "Modular 2x4x6 Ammo Crate", - Model = "models/ammocrates/ammocrate_2x4x6.mdl", - Mass = 240, - Volume = 61200, Size = Vector(45.06, 68.06, 20.06), Offset = Vector(-0.79, 0, 10) }) ACF.RegisterCrate("Ammo2x4x8", { - Name = "Modular 2x4x8 Ammo Crate", - Model = "models/ammocrates/ammocrate_2x4x8.mdl", - Mass = 320, - Volume = 80999, Size = Vector(45.06, 90.06, 20.06), Offset = Vector(-0.79, 0, 10) }) ACF.RegisterCrate("Ammo3x4x1", { - Name = "Modular 3x4x1 Ammo Crate", - Model = "models/ammocrates/ammocrate_3x4x1.mdl", - Mass = 60, - Volume = 11520, Size = Vector(45.06, 8.06, 32.06), Offset = Vector(-0.64, 0, 16.25) }) ACF.RegisterCrate("Ammo3x4x2", { - Name = "Modular 3x4x2 Ammo Crate", - Model = "models/ammocrates/ammocrate_3x4x2.mdl", - Mass = 120, - Volume = 28800, Size = Vector(45.06, 20.06, 32.06), Offset = Vector(-0.2, 0.71, 16.26) }) ACF.RegisterCrate("Ammo3x4x4", { - Name = "Modular 3x4x4 Ammo Crate", - Model = "models/ammocrates/ammocrate_3x4x4.mdl", - Mass = 240, - Volume = 64800, Size = Vector(45.06, 45.06, 32.06), Offset = Vector(-0.79, 0, 16) }) ACF.RegisterCrate("Ammo3x4x6", { - Name = "Modular 3x4x6 Ammo Crate", - Model = "models/ammocrates/ammocrate_3x4x6.mdl", - Mass = 360, - Volume = 97920, Size = Vector(45.06, 68.06, 32.06), Offset = Vector(-0.79, 0, 16) }) ACF.RegisterCrate("Ammo3x4x8", { - Name = "Modular 3x4x8 Ammo Crate", - Model = "models/ammocrates/ammocrate_3x4x8.mdl", - Mass = 480, - Volume = 129599, Size = Vector(45.06, 90.06, 32.06), Offset = Vector(0.15, 0, 16) }) ACF.RegisterCrate("Ammo4x4x1", { - Name = "Modular 4x4x1 Ammo Crate", - Model = "models/ammocrates/ammo_4x4x1.mdl", - Mass = 80, - Volume = 23186, Size = Vector(45.06, 45.06, 11.51), Offset = Vector(0, 0, -0.06) }) ACF.RegisterCrate("Ammo4x4x2", { - Name = "Modular 4x4x2 Ammo Crate", - Model = "models/ammocrates/ammocrate_4x4x2.mdl", - Mass = 160, - Volume = 40500, Size = Vector(45.06, 20.06, 45.06), Offset = Vector(-0.14, 0.71, 22.5) }) ACF.RegisterCrate("Ammo4x4x4", { - Name = "Modular 4x4x4 Ammo Crate", - Model = "models/ammocrates/ammocrate_4x4x4.mdl", - Mass = 320, - Volume = 91125, Size = Vector(45.06, 45.06, 45.06), Offset = Vector(0.15, 0, 22.5) }) ACF.RegisterCrate("Ammo4x4x6", { - Name = "Modular 4x4x6 Ammo Crate", - Model = "models/ammocrates/ammocrate_4x4x6.mdl", - Mass = 480, - Volume = 137700, Size = Vector(45.06, 68.06, 45.06), Offset = Vector(0.15, 0.06, 22.5) }) ACF.RegisterCrate("Ammo4x4x8", { - Name = "Modular 4x4x8 Ammo Crate", - Model = "models/ammocrates/ammocrate_4x4x8.mdl", - Mass = 640, - Volume = 182249, Size = Vector(45.06, 90.06, 45.06), Offset = Vector(0.15, -0.01, 22.5) }) ACF.RegisterCrate("Ammo4x6x6", { - Name = "Modular 4x6x6 Ammo Crate", - Model = "models/ammocrates/ammo_4x6x6.mdl", - Mass = 720, - Volume = 204106, Size = Vector(67.56, 89.98, 44.99), Offset = Vector(0, 0, -0.07) }) ACF.RegisterCrate("Ammo4x6x8", { - Name = "Modular 4x6x8 Ammo Crate", - Model = "models/ammocrates/ammo_4x6x8.mdl", - Mass = 800, - Volume = 272664, Size = Vector(67.56, 67.35, 45), Offset = Vector(0, 0, -0.02) }) ACF.RegisterCrate("Ammo4x8x8", { - Name = "Modular 4x8x8 Ammo Crate", - Model = "models/ammocrates/ammo_4x8x8.mdl", - Mass = 960, - Volume = 366397, Size = Vector(90.21, 90.13, 45.19), Offset = Vector(0, 0, -0.15) }) From 708d7df81f3ad1a888b297ca9982f72dd3801079 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Wed, 18 Nov 2020 22:40:35 -0300 Subject: [PATCH 148/279] Improved ammo menu versatility - Both ACF.CreateAmmoMenu and ACF.UpdateAmmoMenu functions will now take a second Settings table argument. - Added clientside ACF_SetupAmmoMenuSettings hook to allow external settings for the ammo menu. Ammo types will also be able to use the Ammo:SetupAmmoMenuSettings function to accomplish the same behavior. - Developers will be able to modify the preview model panel by using the ACF_AddAmmoPreview hook. Ammo types can also call Ammo:AddAmmoPreview for the same result. - Developers will be able to add more controls to the ammo menu by using the ACF_AddAmmoControls hook. Ammo types can also call Ammo:AddAmmoControls for the same behavior. - Developers will be able to add more information panels to the ammo menu by using the ACF_AddAmmoInformation hook. Ammo types can also call Ammo:AddAmmoInformation for the same behavior. - Updated all ammo types that were previously using the Ammo:MenuAction function. - AP ammo will now restrict Grenade Launchers. - APRC ammo will now allow Rotary Autocannons. - APDS ammo will now allow Rotary Autocannons. - APHE ammo will now restrict Grenade Launchers and Smoothbore Cannons. - FL ammo will now restrict Mortars, Semiautomatic Cannons and Smoothbore Cannons. - HE ammo will now restrict Smoothbore Cannons and Smoke Launchers. - HEAT ammo will now restrict Mortars. - HP ammo will now be only available for Machineguns. - Refill ammo will now show an ammo box as display model. --- lua/acf/client/cl_ammo_menu.lua | 169 ++++++++++++++++++--------- lua/acf/shared/ammo_types/ap.lua | 44 +++---- lua/acf/shared/ammo_types/apcr.lua | 3 +- lua/acf/shared/ammo_types/apds.lua | 3 +- lua/acf/shared/ammo_types/aphe.lua | 68 +++++------ lua/acf/shared/ammo_types/fl.lua | 57 ++++----- lua/acf/shared/ammo_types/he.lua | 58 +++------ lua/acf/shared/ammo_types/heat.lua | 91 +++++++-------- lua/acf/shared/ammo_types/hp.lua | 63 +++++----- lua/acf/shared/ammo_types/refill.lua | 13 ++- lua/acf/shared/ammo_types/smoke.lua | 44 +++---- 11 files changed, 285 insertions(+), 328 deletions(-) diff --git a/lua/acf/client/cl_ammo_menu.lua b/lua/acf/client/cl_ammo_menu.lua index 23439f445..bbaf1b912 100644 --- a/lua/acf/client/cl_ammo_menu.lua +++ b/lua/acf/client/cl_ammo_menu.lua @@ -1,7 +1,7 @@ local ACF = ACF local AmmoTypes = ACF.Classes.AmmoTypes -local CurrentAmmo, AmmoData +local Ammo, BulletData local function GetAmmoList(Class) local Result = {} @@ -16,75 +16,136 @@ local function GetAmmoList(Class) return Result end -function ACF.GetCurrentAmmoData() - return AmmoData +local function AddPreview(Base, Settings, ToolData) + if Settings.SupressPreview then return end + + local Preview = Base:AddModelPreview() + Preview:SetCamPos(Vector(45, 45, 30)) + Preview:SetHeight(120) + Preview:SetFOV(50) + + if Ammo.AddAmmoPreview then + Ammo:AddAmmoPreview(Preview, ToolData, BulletData) + end + + hook.Run("ACF_AddAmmoPreview", Preview, ToolData, Ammo, BulletData) end -function ACF.UpdateAmmoMenu(Menu) - local Ammo = CurrentAmmo +local function AddControls(Base, Settings, ToolData) + if Settings.SupressControls then return end - if not Ammo then return end + local RoundLength = Base:AddLabel() + RoundLength:TrackDataVar("Projectile", "SetText") + RoundLength:TrackDataVar("Propellant") + RoundLength:TrackDataVar("Tracer") + RoundLength:SetValueFunction(function() + local Text = "Round Length: %s / %s cm" + local CurLength = BulletData.ProjLength + BulletData.PropLength + BulletData.Tracer + local MaxLength = BulletData.MaxRoundLength - local ToolData = ACF.GetToolData() - local Base = Menu.AmmoBase + return Text:format(CurLength, MaxLength) + end) - AmmoData = Ammo:ClientConvert(ToolData) + local Projectile = Base:AddSlider("Projectile Length", 0, BulletData.MaxRoundLength, 2) + Projectile:SetDataVar("Projectile", "OnValueChanged") + Projectile:SetValueFunction(function(Panel, IsTracked) + ToolData.Projectile = ACF.ReadNumber("Projectile") - Menu:ClearTemporal(Base) - Menu:StartTemporal(Base) + if not IsTracked then + BulletData.Priority = "Projectile" + end - if not Ammo.SupressDefaultMenu then - local RoundLength = Base:AddLabel() - RoundLength:TrackDataVar("Projectile", "SetText") - RoundLength:TrackDataVar("Propellant") - RoundLength:TrackDataVar("Tracer") - RoundLength:SetValueFunction(function() - local Text = "Round Length: %s / %s cm" - local CurLength = AmmoData.ProjLength + AmmoData.PropLength + AmmoData.Tracer - local MaxLength = AmmoData.MaxRoundLength - - return Text:format(CurLength, MaxLength) - end) + Ammo:UpdateRoundData(ToolData, BulletData) - local Projectile = Base:AddSlider("Projectile Length", 0, AmmoData.MaxRoundLength, 2) - Projectile:SetDataVar("Projectile", "OnValueChanged") - Projectile:SetValueFunction(function(Panel, IsTracked) - ToolData.Projectile = ACF.ReadNumber("Projectile") + ACF.WriteValue("Propellant", BulletData.PropLength) - if not IsTracked then - AmmoData.Priority = "Projectile" - end + Panel:SetValue(BulletData.ProjLength) - Ammo:UpdateRoundData(ToolData, AmmoData) + return BulletData.ProjLength + end) - ACF.WriteValue("Propellant", AmmoData.PropLength) + local Propellant = Base:AddSlider("Propellant Length", 0, BulletData.MaxRoundLength, 2) + Propellant:SetDataVar("Propellant", "OnValueChanged") + Propellant:SetValueFunction(function(Panel, IsTracked) + ToolData.Propellant = ACF.ReadNumber("Propellant") - Panel:SetValue(AmmoData.ProjLength) + if not IsTracked then + BulletData.Priority = "Propellant" + end - return AmmoData.ProjLength - end) + Ammo:UpdateRoundData(ToolData, BulletData) + + ACF.WriteValue("Projectile", BulletData.ProjLength) - local Propellant = Base:AddSlider("Propellant Length", 0, AmmoData.MaxRoundLength, 2) - Propellant:SetDataVar("Propellant", "OnValueChanged") - Propellant:SetValueFunction(function(Panel, IsTracked) - ToolData.Propellant = ACF.ReadNumber("Propellant") + Panel:SetValue(BulletData.PropLength) - if not IsTracked then - AmmoData.Priority = "Propellant" - end + return BulletData.PropLength + end) + + if Ammo.AddAmmoControls then + Ammo:AddAmmoControls(Base, ToolData, BulletData) + end - Ammo:UpdateRoundData(ToolData, AmmoData) + hook.Run("ACF_AddAmmoControls", Base, ToolData, Ammo, BulletData) - ACF.WriteValue("Projectile", AmmoData.ProjLength) + -- We'll create the tracer checkbox after all the other controls + if not Settings.SuppressTracer then + local Tracer = Base:AddCheckBox("Tracer") + Tracer:SetDataVar("Tracer", "OnChange") + Tracer:SetValueFunction(function(Panel) + ToolData.Tracer = ACF.ReadBool("Tracer") - Panel:SetValue(AmmoData.PropLength) + Ammo:UpdateRoundData(ToolData, BulletData) - return AmmoData.PropLength + ACF.WriteValue("Projectile", BulletData.ProjLength) + ACF.WriteValue("Propellant", BulletData.PropLength) + + Panel:SetText("Tracer : " .. BulletData.Tracer .. " cm") + Panel:SetValue(ToolData.Tracer) + + return ToolData.Tracer end) + else + ACF.WriteValue("Tracer", false) -- Disabling the tracer, as it takes up spaces on ammo. + end +end + +local function AddInformation(Base, Settings, ToolData) + if Settings.SuppressInformation then return end + + if Ammo.AddAmmoInformation then + Ammo:AddAmmoInformation(Base, ToolData, BulletData) end - if Ammo.MenuAction then - Ammo:MenuAction(Base, ToolData, AmmoData) + hook.Run("ACF_AddAmmoInformation", Base, ToolData, Ammo, BulletData) +end + +function ACF.GetCurrentAmmoData() + return BulletData +end + +function ACF.UpdateAmmoMenu(Menu, Settings) + if not Ammo then return end + + local ToolData = ACF.GetToolData() + local Base = Menu.AmmoBase + + BulletData = Ammo:ClientConvert(ToolData) + Settings = Settings or {} + + if Ammo.SetupAmmoMenuSettings then + Ammo:SetupAmmoMenuSettings(Settings, ToolData, BulletData) + end + + hook.Run("ACF_SetupAmmoMenuSettings", Settings, ToolData, Ammo, BulletData) + + Menu:ClearTemporal(Base) + Menu:StartTemporal(Base) + + if not Settings.SuppressMenu then + AddPreview(Base, Settings, ToolData) + AddControls(Base, Settings, ToolData) + AddInformation(Base, Settings, ToolData) end Base:AddLabel("This entity can be fully parented.") @@ -92,7 +153,7 @@ function ACF.UpdateAmmoMenu(Menu) Menu:EndTemporal(Base) end -function ACF.CreateAmmoMenu(Menu) +function ACF.CreateAmmoMenu(Menu, Settings) Menu:AddTitle("Ammo Settings") local List = Menu:AddComboBox() @@ -130,11 +191,6 @@ function ACF.CreateAmmoMenu(Menu) local Base = Menu:AddCollapsible("Ammo Information") local Desc = Base:AddLabel() - local Preview = Base:AddModelPreview() - Preview:SetCamPos(Vector(45, 45, 30)) - Preview:SetHeight(120) - Preview:SetFOV(50) - function List:LoadEntries(Class) ACF.LoadSortedList(self, GetAmmoList(Class), "Name") end @@ -145,14 +201,13 @@ function ACF.CreateAmmoMenu(Menu) self.ListData.Index = Index self.Selected = Data - CurrentAmmo = Data + Ammo = Data ACF.WriteValue("AmmoType", Data.ID) Desc:SetText(Data.Description) - Preview:SetModel(Data.Model) - ACF.UpdateAmmoMenu(Menu) + ACF.UpdateAmmoMenu(Menu, Settings) end Menu.AmmoBase = Base diff --git a/lua/acf/shared/ammo_types/ap.lua b/lua/acf/shared/ammo_types/ap.lua index ad6a655de..cf390355d 100644 --- a/lua/acf/shared/ammo_types/ap.lua +++ b/lua/acf/shared/ammo_types/ap.lua @@ -5,6 +5,7 @@ function Ammo:OnLoaded() self.Model = "models/munitions/round_100mm_shot.mdl" self.Description = "A shell made out of a solid piece of steel, meant to penetrate armor." self.Blacklist = { + GL = true, MO = true, SB = true, SL = true, @@ -181,6 +182,9 @@ else return Data end + function Ammo:AddAmmoPreview(Preview) + Preview:SetModel(self.Model) + end function Ammo:ImpactEffect(_, Bullet) local Effect = EffectData() @@ -216,51 +220,35 @@ else util.Effect("ACF_Ricochet", Effect) end - function Ammo:MenuAction(Menu, ToolData, Data) - local Tracer = Menu:AddCheckBox("Tracer") - Tracer:SetDataVar("Tracer", "OnChange") - Tracer:SetValueFunction(function(Panel) - ToolData.Tracer = ACF.ReadBool("Tracer") - - self:UpdateRoundData(ToolData, Data) - - ACF.WriteValue("Projectile", Data.ProjLength) - ACF.WriteValue("Propellant", Data.PropLength) - - Panel:SetText("Tracer : " .. Data.Tracer .. " cm") - Panel:SetValue(ToolData.Tracer) - - return ToolData.Tracer - end) - - local RoundStats = Menu:AddLabel() + function Ammo:AddAmmoInformation(Base, ToolData, BulletData) + local RoundStats = Base:AddLabel() RoundStats:TrackDataVar("Projectile", "SetText") RoundStats:TrackDataVar("Propellant") RoundStats:SetValueFunction(function() - self:UpdateRoundData(ToolData, Data) + self:UpdateRoundData(ToolData, BulletData) local Text = "Muzzle Velocity : %s m/s\nProjectile Mass : %s\nPropellant Mass : %s" - local MuzzleVel = math.Round(Data.MuzzleVel * ACF.Scale, 2) - local ProjMass = ACF.GetProperMass(Data.ProjMass) - local PropMass = ACF.GetProperMass(Data.PropMass) + local MuzzleVel = math.Round(BulletData.MuzzleVel * ACF.Scale, 2) + local ProjMass = ACF.GetProperMass(BulletData.ProjMass) + local PropMass = ACF.GetProperMass(BulletData.PropMass) return Text:format(MuzzleVel, ProjMass, PropMass) end) - local PenStats = Menu:AddLabel() + local PenStats = Base:AddLabel() PenStats:TrackDataVar("Projectile", "SetText") PenStats:TrackDataVar("Propellant") PenStats:SetValueFunction(function() - self:UpdateRoundData(ToolData, Data) + self:UpdateRoundData(ToolData, BulletData) local Text = "Penetration : %s mm RHA\nAt 300m : %s mm RHA @ %s m/s\nAt 800m : %s mm RHA @ %s m/s" - local MaxPen = math.Round(Data.MaxPen, 2) - local R1V, R1P = ACF.PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 300) - local R2V, R2P = ACF.PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 800) + local MaxPen = math.Round(BulletData.MaxPen, 2) + local R1V, R1P = ACF.PenRanging(BulletData.MuzzleVel, BulletData.DragCoef, BulletData.ProjMass, BulletData.PenArea, BulletData.LimitVel, 300) + local R2V, R2P = ACF.PenRanging(BulletData.MuzzleVel, BulletData.DragCoef, BulletData.ProjMass, BulletData.PenArea, BulletData.LimitVel, 800) return Text:format(MaxPen, R1P, R1V, R2P, R2V) end) - Menu:AddLabel("Note: The penetration range data is an approximation and may not be entirely accurate.") + Base:AddLabel("Note: The penetration range data is an approximation and may not be entirely accurate.") end end diff --git a/lua/acf/shared/ammo_types/apcr.lua b/lua/acf/shared/ammo_types/apcr.lua index b730779dc..1e330cf36 100644 --- a/lua/acf/shared/ammo_types/apcr.lua +++ b/lua/acf/shared/ammo_types/apcr.lua @@ -6,11 +6,12 @@ function Ammo:OnLoaded() self.Name = "Armor Piercing Composite Rigid" self.Description = "A hardened core munition designed for weapons in the 1940s." self.Blacklist = ACF.GetWeaponBlacklist({ + C = true, AL = true, AC = true, SA = true, SC = true, - C = true, + RAC = true, }) end diff --git a/lua/acf/shared/ammo_types/apds.lua b/lua/acf/shared/ammo_types/apds.lua index 31e26d8e3..9308ede4b 100644 --- a/lua/acf/shared/ammo_types/apds.lua +++ b/lua/acf/shared/ammo_types/apds.lua @@ -6,10 +6,11 @@ function Ammo:OnLoaded() self.Name = "Armor Piercing Discarging Sabot" self.Description = "A subcaliber munition designed to trade damage for penetration. Loses energy quickly over distance." self.Blacklist = ACF.GetWeaponBlacklist({ + C = true, AL = true, AC = true, SA = true, - C = true, + RAC = true, }) end diff --git a/lua/acf/shared/ammo_types/aphe.lua b/lua/acf/shared/ammo_types/aphe.lua index 073a02f32..9c0d7096e 100644 --- a/lua/acf/shared/ammo_types/aphe.lua +++ b/lua/acf/shared/ammo_types/aphe.lua @@ -6,8 +6,10 @@ function Ammo:OnLoaded() self.Name = "Armor Piercing High Explosive" self.Description = "Less capable armor piercing round with an explosive charge inside." self.Blacklist = { + GL = true, MG = true, MO = true, + SB = true, SL = true, RAC = true, } @@ -125,81 +127,67 @@ else util.Effect("ACF_Explosion", Effect) end - function Ammo:MenuAction(Menu, ToolData, Data) - local FillerMass = Menu:AddSlider("Filler Volume", 0, Data.MaxFillerVol, 2) + function Ammo:AddAmmoControls(Base, ToolData, BulletData) + local FillerMass = Base:AddSlider("Filler Volume", 0, BulletData.MaxFillerVol, 2) FillerMass:SetDataVar("FillerMass", "OnValueChanged") FillerMass:TrackDataVar("Projectile") FillerMass:SetValueFunction(function(Panel) ToolData.FillerMass = math.Round(ACF.ReadNumber("FillerMass"), 2) - self:UpdateRoundData(ToolData, Data) + self:UpdateRoundData(ToolData, BulletData) - Panel:SetMax(Data.MaxFillerVol) - Panel:SetValue(Data.FillerVol) + Panel:SetMax(BulletData.MaxFillerVol) + Panel:SetValue(BulletData.FillerVol) - return Data.FillerVol - end) - - local Tracer = Menu:AddCheckBox("Tracer") - Tracer:SetDataVar("Tracer", "OnChange") - Tracer:SetValueFunction(function(Panel) - ToolData.Tracer = ACF.ReadBool("Tracer") - - self:UpdateRoundData(ToolData, Data) - - ACF.WriteValue("Projectile", Data.ProjLength) - ACF.WriteValue("Propellant", Data.PropLength) - - Panel:SetText("Tracer : " .. Data.Tracer .. " cm") - Panel:SetValue(ToolData.Tracer) - - return ToolData.Tracer + return BulletData.FillerVol end) + end - local RoundStats = Menu:AddLabel() + function Ammo:AddAmmoInformation(Base, ToolData, BulletData) + local RoundStats = Base:AddLabel() RoundStats:TrackDataVar("Projectile", "SetText") RoundStats:TrackDataVar("Propellant") RoundStats:TrackDataVar("FillerMass") RoundStats:SetValueFunction(function() - self:UpdateRoundData(ToolData, Data) + self:UpdateRoundData(ToolData, BulletData) local Text = "Muzzle Velocity : %s m/s\nProjectile Mass : %s\nPropellant Mass : %s\nExplosive Mass : %s" - local MuzzleVel = math.Round(Data.MuzzleVel * ACF.Scale, 2) - local ProjMass = ACF.GetProperMass(Data.ProjMass) - local PropMass = ACF.GetProperMass(Data.PropMass) - local Filler = ACF.GetProperMass(Data.FillerMass) + local MuzzleVel = math.Round(BulletData.MuzzleVel * ACF.Scale, 2) + local ProjMass = ACF.GetProperMass(BulletData.ProjMass) + local PropMass = ACF.GetProperMass(BulletData.PropMass) + local Filler = ACF.GetProperMass(BulletData.FillerMass) return Text:format(MuzzleVel, ProjMass, PropMass, Filler) end) - local FillerStats = Menu:AddLabel() + local FillerStats = Base:AddLabel() FillerStats:TrackDataVar("FillerMass", "SetText") FillerStats:SetValueFunction(function() - self:UpdateRoundData(ToolData, Data) + self:UpdateRoundData(ToolData, BulletData) local Text = "Blast Radius : %s m\nFragments : %s\nFragment Mass : %s\nFragment Velocity : %s m/s" - local Blast = math.Round(Data.BlastRadius, 2) - local FragMass = ACF.GetProperMass(Data.FragMass) - local FragVel = math.Round(Data.FragVel, 2) + local Blast = math.Round(BulletData.BlastRadius, 2) + local FragMass = ACF.GetProperMass(BulletData.FragMass) + local FragVel = math.Round(BulletData.FragVel, 2) - return Text:format(Blast, Data.Fragments, FragMass, FragVel) + return Text:format(Blast, BulletData.Fragments, FragMass, FragVel) end) - local PenStats = Menu:AddLabel() + local PenStats = Base:AddLabel() PenStats:TrackDataVar("Projectile", "SetText") PenStats:TrackDataVar("Propellant") PenStats:TrackDataVar("FillerMass") PenStats:SetValueFunction(function() - self:UpdateRoundData(ToolData, Data) + self:UpdateRoundData(ToolData, BulletData) local Text = "Penetration : %s mm RHA\nAt 300m : %s mm RHA @ %s m/s\nAt 800m : %s mm RHA @ %s m/s" - local MaxPen = math.Round(Data.MaxPen, 2) - local R1V, R1P = ACF.PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 300) - local R2V, R2P = ACF.PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 800) + local MaxPen = math.Round(BulletData.MaxPen, 2) + local R1V, R1P = ACF.PenRanging(BulletData.MuzzleVel, BulletData.DragCoef, BulletData.ProjMass, BulletData.PenArea, BulletData.LimitVel, 300) + local R2V, R2P = ACF.PenRanging(BulletData.MuzzleVel, BulletData.DragCoef, BulletData.ProjMass, BulletData.PenArea, BulletData.LimitVel, 800) return Text:format(MaxPen, R1P, R1V, R2P, R2V) end) - Menu:AddLabel("Note: The penetration range data is an approximation and may not be entirely accurate.") + Base:AddLabel("Note: The penetration range data is an approximation and may not be entirely accurate.") end end \ No newline at end of file diff --git a/lua/acf/shared/ammo_types/fl.lua b/lua/acf/shared/ammo_types/fl.lua index 2b8d5990b..a10026e04 100644 --- a/lua/acf/shared/ammo_types/fl.lua +++ b/lua/acf/shared/ammo_types/fl.lua @@ -10,6 +10,9 @@ function Ammo:OnLoaded() AC = true, GL = true, MG = true, + MO = true, + SA = true, + SB = true, SL = true, HMG = true, RAC = true, @@ -191,59 +194,45 @@ if SERVER then else ACF.RegisterAmmoDecal("FL", "damage/ap_pen", "damage/ap_rico") - function Ammo:MenuAction(Menu, ToolData, Data) - local Flechettes = Menu:AddSlider("Flechette Amount", Data.MinFlechettes, Data.MaxFlechettes) + function Ammo:AddAmmoControls(Base, ToolData, BulletData) + local Flechettes = Base:AddSlider("Flechette Amount", BulletData.MinFlechettes, BulletData.MaxFlechettes) Flechettes:SetDataVar("Flechettes", "OnValueChanged") Flechettes:SetValueFunction(function(Panel) ToolData.Flechettes = math.floor(ACF.ReadNumber("Flechettes")) - Ammo:UpdateRoundData(ToolData, Data) + Ammo:UpdateRoundData(ToolData, BulletData) - Panel:SetValue(Data.Flechettes) + Panel:SetValue(BulletData.Flechettes) - return Data.Flechettes + return BulletData.Flechettes end) - local Spread = Menu:AddSlider("Flechette Spread", Data.MinSpread, Data.MaxSpread, 2) + local Spread = Base:AddSlider("Flechette Spread", BulletData.MinSpread, BulletData.MaxSpread, 2) Spread:SetDataVar("Spread", "OnValueChanged") Spread:SetValueFunction(function(Panel) ToolData.Spread = ACF.ReadNumber("Spread") - Ammo:UpdateRoundData(ToolData, Data) + Ammo:UpdateRoundData(ToolData, BulletData) - Panel:SetValue(Data.FlechetteSpread) + Panel:SetValue(BulletData.FlechetteSpread) - return Data.FlechetteSpread - end) - - local Tracer = Menu:AddCheckBox("Tracer") - Tracer:SetDataVar("Tracer", "OnChange") - Tracer:SetValueFunction(function(Panel) - ToolData.Tracer = ACF.ReadBool("Tracer") - - self:UpdateRoundData(ToolData, Data) - - ACF.WriteValue("Projectile", Data.ProjLength) - ACF.WriteValue("Propellant", Data.PropLength) - - Panel:SetText("Tracer : " .. Data.Tracer .. " cm") - Panel:SetValue(ToolData.Tracer) - - return ToolData.Tracer + return BulletData.FlechetteSpread end) + end + function Ammo:AddAmmoInformation(Menu, ToolData, BulletData) local RoundStats = Menu:AddLabel() RoundStats:TrackDataVar("Projectile", "SetText") RoundStats:TrackDataVar("Propellant") RoundStats:TrackDataVar("Flechettes") RoundStats:SetValueFunction(function() - self:UpdateRoundData(ToolData, Data) + self:UpdateRoundData(ToolData, BulletData) local Text = "Muzzle Velocity : %s m/s\nProjectile Mass : %s\nPropellant Mass : %s\nFlechette Mass : %s" - local MuzzleVel = math.Round(Data.MuzzleVel * ACF.Scale, 2) - local ProjMass = ACF.GetProperMass(Data.ProjMass) - local PropMass = ACF.GetProperMass(Data.PropMass) - local FLMass = ACF.GetProperMass(Data.FlechetteMass) + local MuzzleVel = math.Round(BulletData.MuzzleVel * ACF.Scale, 2) + local ProjMass = ACF.GetProperMass(BulletData.ProjMass) + local PropMass = ACF.GetProperMass(BulletData.PropMass) + local FLMass = ACF.GetProperMass(BulletData.FlechetteMass) return Text:format(MuzzleVel, ProjMass, PropMass, FLMass) end) @@ -253,12 +242,12 @@ else PenStats:TrackDataVar("Propellant") PenStats:TrackDataVar("Flechettes") PenStats:SetValueFunction(function() - self:UpdateRoundData(ToolData, Data) + self:UpdateRoundData(ToolData, BulletData) local Text = "Penetration : %s mm RHA\nAt 300m : %s mm RHA @ %s m/s\nAt 800m : %s mm RHA @ %s m/s" - local MaxPen = math.Round(Data.MaxPen, 2) - local R1V, R1P = ACF.PenRanging(Data.MuzzleVel, Data.FlechetteDragCoef, Data.FlechetteMass, Data.FlechettePenArea, Data.LimitVel, 300) - local R2V, R2P = ACF.PenRanging(Data.MuzzleVel, Data.FlechetteDragCoef, Data.FlechetteMass, Data.FlechettePenArea, Data.LimitVel, 800) + local MaxPen = math.Round(BulletData.MaxPen, 2) + local R1V, R1P = ACF.PenRanging(BulletData.MuzzleVel, BulletData.FlechetteDragCoef, BulletData.FlechetteMass, BulletData.FlechettePenArea, BulletData.LimitVel, 300) + local R2V, R2P = ACF.PenRanging(BulletData.MuzzleVel, BulletData.FlechetteDragCoef, BulletData.FlechetteMass, BulletData.FlechettePenArea, BulletData.LimitVel, 800) return Text:format(MaxPen, R1P, R1V, R2P, R2V) end) diff --git a/lua/acf/shared/ammo_types/he.lua b/lua/acf/shared/ammo_types/he.lua index e7f475d75..452493cf1 100644 --- a/lua/acf/shared/ammo_types/he.lua +++ b/lua/acf/shared/ammo_types/he.lua @@ -7,6 +7,8 @@ function Ammo:OnLoaded() self.Description = "A shell filled with explosives, detonates on impact." self.Blacklist = { MG = true, + SB = true, + SL = true, RAC = true, } end @@ -104,64 +106,34 @@ if SERVER then else ACF.RegisterAmmoDecal("HE", "damage/he_pen", "damage/he_rico") - function Ammo:MenuAction(Menu, ToolData, Data) - local FillerMass = Menu:AddSlider("Filler Volume", 0, Data.MaxFillerVol, 2) - FillerMass:SetDataVar("FillerMass", "OnValueChanged") - FillerMass:TrackDataVar("Projectile") - FillerMass:SetValueFunction(function(Panel) - ToolData.FillerMass = math.Round(ACF.ReadNumber("FillerMass"), 2) - - self:UpdateRoundData(ToolData, Data) - - Panel:SetMax(Data.MaxFillerVol) - Panel:SetValue(Data.FillerVol) - - return Data.FillerVol - end) - - local Tracer = Menu:AddCheckBox("Tracer") - Tracer:SetDataVar("Tracer", "OnChange") - Tracer:SetValueFunction(function(Panel) - ToolData.Tracer = ACF.ReadBool("Tracer") - - self:UpdateRoundData(ToolData, Data) - - ACF.WriteValue("Projectile", Data.ProjLength) - ACF.WriteValue("Propellant", Data.PropLength) - - Panel:SetText("Tracer : " .. Data.Tracer .. " cm") - Panel:SetValue(ToolData.Tracer) - - return ToolData.Tracer - end) - - local RoundStats = Menu:AddLabel() + function Ammo:AddAmmoInformation(Base, ToolData, BulletData) + local RoundStats = Base:AddLabel() RoundStats:TrackDataVar("Projectile", "SetText") RoundStats:TrackDataVar("Propellant") RoundStats:TrackDataVar("FillerMass") RoundStats:SetValueFunction(function() - self:UpdateRoundData(ToolData, Data) + self:UpdateRoundData(ToolData, BulletData) local Text = "Muzzle Velocity : %s m/s\nProjectile Mass : %s\nPropellant Mass : %s\nExplosive Mass : %s" - local MuzzleVel = math.Round(Data.MuzzleVel * ACF.Scale, 2) - local ProjMass = ACF.GetProperMass(Data.ProjMass) - local PropMass = ACF.GetProperMass(Data.PropMass) - local Filler = ACF.GetProperMass(Data.FillerMass) + local MuzzleVel = math.Round(BulletData.MuzzleVel * ACF.Scale, 2) + local ProjMass = ACF.GetProperMass(BulletData.ProjMass) + local PropMass = ACF.GetProperMass(BulletData.PropMass) + local Filler = ACF.GetProperMass(BulletData.FillerMass) return Text:format(MuzzleVel, ProjMass, PropMass, Filler) end) - local FillerStats = Menu:AddLabel() + local FillerStats = Base:AddLabel() FillerStats:TrackDataVar("FillerMass", "SetText") FillerStats:SetValueFunction(function() - self:UpdateRoundData(ToolData, Data) + self:UpdateRoundData(ToolData, BulletData) local Text = "Blast Radius : %s m\nFragments : %s\nFragment Mass : %s\nFragment Velocity : %s m/s" - local Blast = math.Round(Data.BlastRadius, 2) - local FragMass = ACF.GetProperMass(Data.FragMass) - local FragVel = math.Round(Data.FragVel, 2) + local Blast = math.Round(BulletData.BlastRadius, 2) + local FragMass = ACF.GetProperMass(BulletData.FragMass) + local FragVel = math.Round(BulletData.FragVel, 2) - return Text:format(Blast, Data.Fragments, FragMass, FragVel) + return Text:format(Blast, BulletData.Fragments, FragMass, FragVel) end) end end \ No newline at end of file diff --git a/lua/acf/shared/ammo_types/heat.lua b/lua/acf/shared/ammo_types/heat.lua index 699b4564c..d0691d223 100644 --- a/lua/acf/shared/ammo_types/heat.lua +++ b/lua/acf/shared/ammo_types/heat.lua @@ -8,6 +8,7 @@ function Ammo:OnLoaded() self.Blacklist = { AC = true, MG = true, + MO = true, SB = true, SL = true, HMG = true, @@ -304,118 +305,104 @@ else util.Effect("ACF_Ricochet", Effect) end - function Ammo:MenuAction(Menu, ToolData, Data) - local LinerAngle = Menu:AddSlider("Liner Angle", Data.MinConeAng, Data.MaxConeAng, 2) + function Ammo:AddAmmoControls(Base, ToolData, BulletData) + local LinerAngle = Base:AddSlider("Liner Angle", BulletData.MinConeAng, BulletData.MaxConeAng, 2) LinerAngle:SetDataVar("LinerAngle", "OnValueChanged") LinerAngle:TrackDataVar("Projectile") LinerAngle:SetValueFunction(function(Panel) ToolData.LinerAngle = math.Round(ACF.ReadNumber("LinerAngle"), 2) - self:UpdateRoundData(ToolData, Data) + self:UpdateRoundData(ToolData, BulletData) - Panel:SetMax(Data.MaxConeAng) - Panel:SetValue(Data.ConeAng) + Panel:SetMax(BulletData.MaxConeAng) + Panel:SetValue(BulletData.ConeAng) - return Data.ConeAng + return BulletData.ConeAng end) - local FillerMass = Menu:AddSlider("Filler Volume", 0, Data.MaxFillerVol, 2) + local FillerMass = Base:AddSlider("Filler Volume", 0, BulletData.MaxFillerVol, 2) FillerMass:SetDataVar("FillerMass", "OnValueChanged") FillerMass:TrackDataVar("Projectile") FillerMass:TrackDataVar("LinerAngle") FillerMass:SetValueFunction(function(Panel) ToolData.FillerMass = math.Round(ACF.ReadNumber("FillerMass"), 2) - self:UpdateRoundData(ToolData, Data) + self:UpdateRoundData(ToolData, BulletData) - Panel:SetMax(Data.MaxFillerVol) - Panel:SetValue(Data.FillerVol) + Panel:SetMax(BulletData.MaxFillerVol) + Panel:SetValue(BulletData.FillerVol) - return Data.FillerVol - end) - - local Tracer = Menu:AddCheckBox("Tracer") - Tracer:SetDataVar("Tracer", "OnChange") - Tracer:SetValueFunction(function(Panel) - ToolData.Tracer = ACF.ReadBool("Tracer") - - self:UpdateRoundData(ToolData, Data) - - ACF.WriteValue("Projectile", Data.ProjLength) - ACF.WriteValue("Propellant", Data.PropLength) - - Panel:SetText("Tracer : " .. Data.Tracer .. " cm") - Panel:SetValue(ToolData.Tracer) - - return ToolData.Tracer + return BulletData.FillerVol end) + end - local RoundStats = Menu:AddLabel() + function Ammo:AddAmmoInformation(Base, ToolData, BulletData) + local RoundStats = Base:AddLabel() RoundStats:TrackDataVar("Projectile", "SetText") RoundStats:TrackDataVar("Propellant") RoundStats:TrackDataVar("FillerMass") RoundStats:TrackDataVar("LinerAngle") RoundStats:SetValueFunction(function() - self:UpdateRoundData(ToolData, Data) + self:UpdateRoundData(ToolData, BulletData) local Text = "Muzzle Velocity : %s m/s\nProjectile Mass : %s\nPropellant Mass : %s\nExplosive Mass : %s" - local MuzzleVel = math.Round(Data.MuzzleVel * ACF.Scale, 2) - local ProjMass = ACF.GetProperMass(Data.ProjMass) - local PropMass = ACF.GetProperMass(Data.PropMass) - local Filler = ACF.GetProperMass(Data.FillerMass) + local MuzzleVel = math.Round(BulletData.MuzzleVel * ACF.Scale, 2) + local ProjMass = ACF.GetProperMass(BulletData.ProjMass) + local PropMass = ACF.GetProperMass(BulletData.PropMass) + local Filler = ACF.GetProperMass(BulletData.FillerMass) return Text:format(MuzzleVel, ProjMass, PropMass, Filler) end) - local FillerStats = Menu:AddLabel() + local FillerStats = Base:AddLabel() FillerStats:TrackDataVar("FillerMass", "SetText") FillerStats:TrackDataVar("LinerAngle") FillerStats:SetValueFunction(function() - self:UpdateRoundData(ToolData, Data) + self:UpdateRoundData(ToolData, BulletData) local Text = "Blast Radius : %s m\nFragments : %s\nFragment Mass : %s\nFragment Velocity : %s m/s" - local Blast = math.Round(Data.BlastRadius, 2) - local FragMass = ACF.GetProperMass(Data.FragMass) - local FragVel = math.Round(Data.FragVel, 2) + local Blast = math.Round(BulletData.BlastRadius, 2) + local FragMass = ACF.GetProperMass(BulletData.FragMass) + local FragVel = math.Round(BulletData.FragVel, 2) - return Text:format(Blast, Data.Fragments, FragMass, FragVel) + return Text:format(Blast, BulletData.Fragments, FragMass, FragVel) end) - local Penetrator = Menu:AddLabel() + local Penetrator = Base:AddLabel() Penetrator:TrackDataVar("Projectile", "SetText") Penetrator:TrackDataVar("Propellant") Penetrator:TrackDataVar("FillerMass") Penetrator:TrackDataVar("LinerAngle") Penetrator:SetValueFunction(function() - self:UpdateRoundData(ToolData, Data) + self:UpdateRoundData(ToolData, BulletData) local Text = "Penetrator Caliber : %s mm\nPenetrator Mass : %s\nPenetrator Velocity : %s m/s" - local Caliber = math.Round(Data.SlugCaliber * 10, 2) - local Mass = ACF.GetProperMass(Data.SlugMassUsed) - local Velocity = math.Round(Data.MuzzleVel + Data.SlugMV, 2) + local Caliber = math.Round(BulletData.SlugCaliber * 10, 2) + local Mass = ACF.GetProperMass(BulletData.SlugMassUsed) + local Velocity = math.Round(BulletData.MuzzleVel + BulletData.SlugMV, 2) return Text:format(Caliber, Mass, Velocity) end) - local PenStats = Menu:AddLabel() + local PenStats = Base:AddLabel() PenStats:TrackDataVar("Projectile", "SetText") PenStats:TrackDataVar("Propellant") PenStats:TrackDataVar("FillerMass") PenStats:TrackDataVar("LinerAngle") PenStats:SetValueFunction(function() - self:UpdateRoundData(ToolData, Data) + self:UpdateRoundData(ToolData, BulletData) local Text = "Penetration : %s mm RHA\nAt 300m : %s mm RHA @ %s m/s\nAt 800m : %s mm RHA @ %s m/s" - local MaxPen = math.Round(Data.MaxPen, 2) - local R1V, R1P = ACF.PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 300) - local R2V, R2P = ACF.PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 800) + local MaxPen = math.Round(BulletData.MaxPen, 2) + local R1V, R1P = ACF.PenRanging(BulletData.MuzzleVel, BulletData.DragCoef, BulletData.ProjMass, BulletData.PenArea, BulletData.LimitVel, 300) + local R2V, R2P = ACF.PenRanging(BulletData.MuzzleVel, BulletData.DragCoef, BulletData.ProjMass, BulletData.PenArea, BulletData.LimitVel, 800) - R1P = math.Round((ACF_Kinetic((R1V + Data.SlugMV) * 39.37, Data.SlugMassUsed, 999999).Penetration / Data.SlugPenArea) * ACF.KEtoRHA, 2) - R2P = math.Round((ACF_Kinetic((R2V + Data.SlugMV) * 39.37, Data.SlugMassUsed, 999999).Penetration / Data.SlugPenArea) * ACF.KEtoRHA, 2) + R1P = math.Round((ACF_Kinetic((R1V + BulletData.SlugMV) * 39.37, BulletData.SlugMassUsed, 999999).Penetration / BulletData.SlugPenArea) * ACF.KEtoRHA, 2) + R2P = math.Round((ACF_Kinetic((R2V + BulletData.SlugMV) * 39.37, BulletData.SlugMassUsed, 999999).Penetration / BulletData.SlugPenArea) * ACF.KEtoRHA, 2) return Text:format(MaxPen, R1P, R1V, R2P, R2V) end) - Menu:AddLabel("Note: The penetration range data is an approximation and may not be entirely accurate.") + Base:AddLabel("Note: The penetration range data is an approximation and may not be entirely accurate.") end end \ No newline at end of file diff --git a/lua/acf/shared/ammo_types/hp.lua b/lua/acf/shared/ammo_types/hp.lua index 3028953e6..94e0407d7 100644 --- a/lua/acf/shared/ammo_types/hp.lua +++ b/lua/acf/shared/ammo_types/hp.lua @@ -5,6 +5,9 @@ function Ammo:OnLoaded() self.Name = "Hollow Point" self.Description = "A round with a hollow cavity, meant to flatten against surfaces on impact." + self.Blacklist = ACF.GetWeaponBlacklist({ + MG = true, + }) end function Ammo:GetDisplayData(Data) @@ -101,81 +104,67 @@ if SERVER then else ACF.RegisterAmmoDecal("HP", "damage/ap_pen", "damage/ap_rico") - function Ammo:MenuAction(Menu, ToolData, Data) - local HollowCavity = Menu:AddSlider("Cavity Volume", Data.MinCavVol, Data.MaxCavVol, 2) + function Ammo:AddAmmoControls(Base, ToolData, BulletData) + local HollowCavity = Base:AddSlider("Cavity Volume", BulletData.MinCavVol, BulletData.MaxCavVol, 2) HollowCavity:SetDataVar("HollowCavity", "OnValueChanged") HollowCavity:TrackDataVar("Projectile") HollowCavity:SetValueFunction(function(Panel) ToolData.HollowCavity = math.Round(ACF.ReadNumber("HollowCavity"), 2) - self:UpdateRoundData(ToolData, Data) + self:UpdateRoundData(ToolData, BulletData) - Panel:SetMax(Data.MaxCavVol) - Panel:SetValue(Data.CavVol) + Panel:SetMax(BulletData.MaxCavVol) + Panel:SetValue(BulletData.CavVol) - return Data.CavVol - end) - - local Tracer = Menu:AddCheckBox("Tracer") - Tracer:SetDataVar("Tracer", "OnChange") - Tracer:SetValueFunction(function(Panel) - ToolData.Tracer = ACF.ReadBool("Tracer") - - self:UpdateRoundData(ToolData, Data) - - ACF.WriteValue("Projectile", Data.ProjLength) - ACF.WriteValue("Propellant", Data.PropLength) - - Panel:SetText("Tracer : " .. Data.Tracer .. " cm") - Panel:SetValue(ToolData.Tracer) - - return ToolData.Tracer + return BulletData.CavVol end) + end - local RoundStats = Menu:AddLabel() + function Ammo:AddAmmoInformation(Base, ToolData, BulletData) + local RoundStats = Base:AddLabel() RoundStats:TrackDataVar("Projectile", "SetText") RoundStats:TrackDataVar("Propellant") RoundStats:TrackDataVar("HollowCavity") RoundStats:SetValueFunction(function() - self:UpdateRoundData(ToolData, Data) + self:UpdateRoundData(ToolData, BulletData) local Text = "Muzzle Velocity : %s m/s\nProjectile Mass : %s\nPropellant Mass : %s" - local MuzzleVel = math.Round(Data.MuzzleVel * ACF.Scale, 2) - local ProjMass = ACF.GetProperMass(Data.ProjMass) - local PropMass = ACF.GetProperMass(Data.PropMass) + local MuzzleVel = math.Round(BulletData.MuzzleVel * ACF.Scale, 2) + local ProjMass = ACF.GetProperMass(BulletData.ProjMass) + local PropMass = ACF.GetProperMass(BulletData.PropMass) return Text:format(MuzzleVel, ProjMass, PropMass) end) - local HollowStats = Menu:AddLabel() + local HollowStats = Base:AddLabel() HollowStats:TrackDataVar("Projectile", "SetText") HollowStats:TrackDataVar("Propellant") HollowStats:TrackDataVar("HollowCavity") HollowStats:SetValueFunction(function() - self:UpdateRoundData(ToolData, Data) + self:UpdateRoundData(ToolData, BulletData) local Text = "Expanded Caliber : %s mm\nTransfered Energy : %s KJ" - local Caliber = math.Round(Data.ExpCaliber * 10, 2) - local Energy = math.Round(Data.MaxKETransfert, 2) + local Caliber = math.Round(BulletData.ExpCaliber * 10, 2) + local Energy = math.Round(BulletData.MaxKETransfert, 2) return Text:format(Caliber, Energy) end) - local PenStats = Menu:AddLabel() + local PenStats = Base:AddLabel() PenStats:TrackDataVar("Projectile", "SetText") PenStats:TrackDataVar("Propellant") PenStats:TrackDataVar("HollowCavity") PenStats:SetValueFunction(function() - self:UpdateRoundData(ToolData, Data) + self:UpdateRoundData(ToolData, BulletData) local Text = "Penetration : %s mm RHA\nAt 300m : %s mm RHA @ %s m/s\nAt 800m : %s mm RHA @ %s m/s" - local MaxPen = math.Round(Data.MaxPen, 2) - local R1V, R1P = ACF.PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 300) - local R2V, R2P = ACF.PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 800) + local MaxPen = math.Round(BulletData.MaxPen, 2) + local R1V, R1P = ACF.PenRanging(BulletData.MuzzleVel, BulletData.DragCoef, BulletData.ProjMass, BulletData.PenArea, BulletData.LimitVel, 300) + local R2V, R2P = ACF.PenRanging(BulletData.MuzzleVel, BulletData.DragCoef, BulletData.ProjMass, BulletData.PenArea, BulletData.LimitVel, 800) return Text:format(MaxPen, R1P, R1V, R2P, R2V) end) - Menu:AddLabel("Note: The penetration range data is an approximation and may not be entirely accurate.") + Base:AddLabel("Note: The penetration range data is an approximation and may not be entirely accurate.") end end \ No newline at end of file diff --git a/lua/acf/shared/ammo_types/refill.lua b/lua/acf/shared/ammo_types/refill.lua index 6fe5bfc0b..17904fd44 100644 --- a/lua/acf/shared/ammo_types/refill.lua +++ b/lua/acf/shared/ammo_types/refill.lua @@ -1,11 +1,10 @@ local Ammo = ACF.RegisterAmmoType("Refill", "AP") function Ammo:OnLoaded() - self.Name = "Refill" - self.Model = "models/Items/BoxSRounds.mdl" - self.Description = "Provides supplies to other ammo crates." - self.Blacklist = {} - self.SupressDefaultMenu = true + self.Name = "Refill" + self.Model = "models/Items/BoxSRounds.mdl" + self.Description = "Provides supplies to other ammo crates." + self.Blacklist = {} end function Ammo:GetDisplayData() @@ -156,6 +155,8 @@ if SERVER then return "" end else - function Ammo:MenuAction() + function Ammo:SetupAmmoMenuSettings(Settings) + Settings.SupressControls = true + Settings.SuppressInformation = true end end diff --git a/lua/acf/shared/ammo_types/smoke.lua b/lua/acf/shared/ammo_types/smoke.lua index bb2d29933..dbd69762b 100644 --- a/lua/acf/shared/ammo_types/smoke.lua +++ b/lua/acf/shared/ammo_types/smoke.lua @@ -188,8 +188,8 @@ else util.Effect("ACF_Smoke", Effect) end - function Ammo:MenuAction(Menu, ToolData, Data) - local SmokeFiller = Menu:AddSlider("Smoke Filler", Data.MinFillerVol, Data.MaxFillerVol, 2) + function Ammo:AddAmmoControls(Base, ToolData, BulletData) + local SmokeFiller = Base:AddSlider("Smoke Filler", BulletData.MinFillerVol, BulletData.MaxFillerVol, 2) SmokeFiller:SetDataVar("SmokeFiller", "OnValueChanged") SmokeFiller:TrackDataVar("Projectile") SmokeFiller:TrackDataVar("WPFiller") @@ -197,18 +197,18 @@ else ToolData.SmokeFiller = math.Round(ACF.ReadNumber("SmokeFiller"), 2) if not IsTracked then - Data.FillerPriority = "Smoke" + BulletData.FillerPriority = "Smoke" end - self:UpdateRoundData(ToolData, Data) + self:UpdateRoundData(ToolData, BulletData) - Panel:SetMax(Data.MaxFillerVol) - Panel:SetValue(Data.FillerVol) + Panel:SetMax(BulletData.MaxFillerVol) + Panel:SetValue(BulletData.FillerVol) - return Data.FillerVol + return BulletData.FillerVol end) - local WPFiller = Menu:AddSlider("WP Filler", Data.MinFillerVol, Data.MaxFillerVol, 2) + local WPFiller = Base:AddSlider("WP Filler", BulletData.MinFillerVol, BulletData.MaxFillerVol, 2) WPFiller:SetDataVar("WPFiller", "OnValueChanged") WPFiller:TrackDataVar("SmokeFiller") WPFiller:TrackDataVar("Projectile") @@ -216,33 +216,19 @@ else ToolData.WPFiller = math.Round(ACF.ReadNumber("WPFiller"), 2) if not IsTracked then - Data.FillerPriority = "WP" + BulletData.FillerPriority = "WP" end - self:UpdateRoundData(ToolData, Data) - - Panel:SetMax(Data.MaxFillerVol) - Panel:SetValue(Data.WPVol) - - return Data.WPVol - end) - - local Tracer = Menu:AddCheckBox("Tracer") - Tracer:SetDataVar("Tracer", "OnChange") - Tracer:SetValueFunction(function(Panel) - ToolData.Tracer = ACF.ReadBool("Tracer") - - self:UpdateRoundData(ToolData, Data) + self:UpdateRoundData(ToolData, BulletData) - ACF.WriteValue("Projectile", Data.ProjLength) - ACF.WriteValue("Propellant", Data.PropLength) + Panel:SetMax(BulletData.MaxFillerVol) + Panel:SetValue(BulletData.WPVol) - Panel:SetText("Tracer : " .. Data.Tracer .. " cm") - Panel:SetValue(ToolData.Tracer) - - return ToolData.Tracer + return BulletData.WPVol end) + end + function Ammo:AddAmmoInformation(Menu, ToolData, Data) local RoundStats = Menu:AddLabel() RoundStats:TrackDataVar("Projectile", "SetText") RoundStats:TrackDataVar("Propellant") From cfd6c741216f41adb91a1ec17208318cef31bfb6 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Thu, 19 Nov 2020 00:18:37 -0300 Subject: [PATCH 149/279] Fixed typo - Fixed a few instances where the word Suppress was written as Supress. --- lua/acf/client/cl_ammo_menu.lua | 4 ++-- lua/acf/shared/ammo_types/refill.lua | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lua/acf/client/cl_ammo_menu.lua b/lua/acf/client/cl_ammo_menu.lua index bbaf1b912..01039d8a7 100644 --- a/lua/acf/client/cl_ammo_menu.lua +++ b/lua/acf/client/cl_ammo_menu.lua @@ -17,7 +17,7 @@ local function GetAmmoList(Class) end local function AddPreview(Base, Settings, ToolData) - if Settings.SupressPreview then return end + if Settings.SuppressPreview then return end local Preview = Base:AddModelPreview() Preview:SetCamPos(Vector(45, 45, 30)) @@ -32,7 +32,7 @@ local function AddPreview(Base, Settings, ToolData) end local function AddControls(Base, Settings, ToolData) - if Settings.SupressControls then return end + if Settings.SuppressControls then return end local RoundLength = Base:AddLabel() RoundLength:TrackDataVar("Projectile", "SetText") diff --git a/lua/acf/shared/ammo_types/refill.lua b/lua/acf/shared/ammo_types/refill.lua index 17904fd44..608b395c0 100644 --- a/lua/acf/shared/ammo_types/refill.lua +++ b/lua/acf/shared/ammo_types/refill.lua @@ -156,7 +156,7 @@ if SERVER then end else function Ammo:SetupAmmoMenuSettings(Settings) - Settings.SupressControls = true + Settings.SuppressControls = true Settings.SuppressInformation = true end end From ec161d850f1d281df6b46a75152d31fb61babf8e Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Thu, 19 Nov 2020 00:43:54 -0300 Subject: [PATCH 150/279] Fixed settings overriding - Fixed ammo menu settings being overridden. Now a copy of said settings table is provided for the other functions and hooks to use. --- lua/acf/client/cl_ammo_menu.lua | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/lua/acf/client/cl_ammo_menu.lua b/lua/acf/client/cl_ammo_menu.lua index 01039d8a7..cbab3d810 100644 --- a/lua/acf/client/cl_ammo_menu.lua +++ b/lua/acf/client/cl_ammo_menu.lua @@ -3,6 +3,18 @@ local ACF = ACF local AmmoTypes = ACF.Classes.AmmoTypes local Ammo, BulletData +local function CopySettings(Settings) + local Copy = {} + + if Settings then + for K, V in pairs(Settings) do + Copy[K] = V + end + end + + return Copy +end + local function GetAmmoList(Class) local Result = {} @@ -131,7 +143,7 @@ function ACF.UpdateAmmoMenu(Menu, Settings) local Base = Menu.AmmoBase BulletData = Ammo:ClientConvert(ToolData) - Settings = Settings or {} + Settings = CopySettings(Settings) if Ammo.SetupAmmoMenuSettings then Ammo:SetupAmmoMenuSettings(Settings, ToolData, BulletData) From 6774001a10f429b25baf75219406450055f46e3b Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Fri, 20 Nov 2020 00:21:06 -0300 Subject: [PATCH 151/279] Updated E2 functions - Updated E2 library to not use deprecated information, along with updating certain functions that were not working entirely. - Updated weapons and engines to properly support e:acfSoundPath() --- lua/entities/acf_engine/init.lua | 28 +-- lua/entities/acf_gun/init.lua | 19 +- .../core/custom/acffunctions.lua | 217 ++++++++---------- lua/weapons/gmod_tool/stools/acfsound.lua | 85 +++---- 4 files changed, 156 insertions(+), 193 deletions(-) diff --git a/lua/entities/acf_engine/init.lua b/lua/entities/acf_engine/init.lua index c83cda173..5f652854d 100644 --- a/lua/entities/acf_engine/init.lua +++ b/lua/entities/acf_engine/init.lua @@ -279,6 +279,7 @@ do -- Spawn and Update functions Entity.PeakMaxRPM = EngineData.RPM.PeakMax Entity.LimitRPM = EngineData.RPM.Limit Entity.FlywheelOverride = EngineData.RPM.Override + Entity.FlywheelMass = EngineData.FlywheelMass Entity.Inertia = EngineData.FlywheelMass * 3.1416 ^ 2 Entity.IsElectric = EngineData.IsElectric Entity.IsTrans = EngineData.IsTrans -- driveshaft outputs to the side @@ -341,19 +342,20 @@ do -- Spawn and Update functions Player:AddCleanup("acfmenu", Engine) Player:AddCount(Limit, Engine) - Engine.Owner = Player -- MUST be stored on ent for PP - Engine.Active = false - Engine.Gearboxes = {} - Engine.FuelTanks = {} - Engine.LastThink = 0 - Engine.MassRatio = 1 - Engine.FuelUsage = 0 - Engine.Throttle = 0 - Engine.FlyRPM = 0 - Engine.SoundPath = EngineData.Sound - Engine.Inputs = WireLib.CreateInputs(Engine, { "Active", "Throttle" }) - Engine.Outputs = WireLib.CreateOutputs(Engine, { "RPM", "Torque", "Power", "Fuel Use", "Entity [ENTITY]", "Mass", "Physical Mass" }) - Engine.DataStore = ACF.GetEntityArguments("acf_engine") + Engine.Owner = Player -- MUST be stored on ent for PP + Engine.Active = false + Engine.Gearboxes = {} + Engine.FuelTanks = {} + Engine.LastThink = 0 + Engine.MassRatio = 1 + Engine.FuelUsage = 0 + Engine.Throttle = 0 + Engine.FlyRPM = 0 + Engine.SoundPath = EngineData.Sound + Engine.DefaultSound = EngineData.Sound + Engine.Inputs = WireLib.CreateInputs(Engine, { "Active", "Throttle" }) + Engine.Outputs = WireLib.CreateOutputs(Engine, { "RPM", "Torque", "Power", "Fuel Use", "Entity [ENTITY]", "Mass", "Physical Mass" }) + Engine.DataStore = ACF.GetEntityArguments("acf_engine") WireLib.TriggerOutput(Engine, "Entity", Engine) diff --git a/lua/entities/acf_gun/init.lua b/lua/entities/acf_gun/init.lua index 5f6b2990b..7e861a441 100644 --- a/lua/entities/acf_gun/init.lua +++ b/lua/entities/acf_gun/init.lua @@ -147,15 +147,16 @@ do -- Spawn and Update functions -------------------------------- Gun:SetPos(Pos) Gun:Spawn() - Gun.Owner = Player -- MUST be stored on ent for PP - Gun.Outputs = WireLib.CreateOutputs(Gun, { "Ready", "Status [STRING]", "Total Ammo", "Entity [ENTITY]", "Shots Left", "Rate of Fire", "Reload Time", "Projectile Mass", "Muzzle Velocity" }) - Gun.Sound = Class.Sound - Gun.BarrelFilter = { Gun } - Gun.State = "Empty" - Gun.Crates = {} - Gun.CurrentShot = 0 - Gun.BulletData = { Type = "Empty", PropMass = 0, ProjMass = 0, Tracer = 0 } - Gun.DataStore = ACF.GetEntityArguments("acf_gun") + Gun.Owner = Player -- MUST be stored on ent for PP + Gun.Outputs = WireLib.CreateOutputs(Gun, { "Ready", "Status [STRING]", "Total Ammo", "Entity [ENTITY]", "Shots Left", "Rate of Fire", "Reload Time", "Projectile Mass", "Muzzle Velocity" }) + Gun.SoundPath = Class.Sound + Gun.DefaultSound = Class.Sound + Gun.BarrelFilter = { Gun } + Gun.State = "Empty" + Gun.Crates = {} + Gun.CurrentShot = 0 + Gun.BulletData = { Type = "Empty", PropMass = 0, ProjMass = 0, Tracer = 0 } + Gun.DataStore = ACF.GetEntityArguments("acf_gun") Gun:SetNWString("Sound", Class.Sound) diff --git a/lua/entities/gmod_wire_expression2/core/custom/acffunctions.lua b/lua/entities/gmod_wire_expression2/core/custom/acffunctions.lua index c640f2168..454c416f7 100644 --- a/lua/entities/gmod_wire_expression2/core/custom/acffunctions.lua +++ b/lua/entities/gmod_wire_expression2/core/custom/acffunctions.lua @@ -11,13 +11,14 @@ E2Lib.RegisterExtension("acf", true) -- Local Variables and Helper Functions --===============================================================================================-- -local RestrictInfoConVar = GetConVar("acf_restrict_info") +local Restrict = GetConVar("acf_restrict_info") +local ACF = ACF local AllLinkSources = ACF.GetAllLinkSources -local LinkSource = ACF.GetLinkSource -local RoundTypes = ACF.RoundTypes -- REPLACE -local match = string.match -local floor = math.floor -local Round = math.Round +local LinkSource = ACF.GetLinkSource +local AmmoTypes = ACF.Classes.AmmoTypes +local match = string.match +local floor = math.floor +local Round = math.Round local function IsACFEntity(Entity) if not validPhysics(Entity) then return false end @@ -28,7 +29,7 @@ local function IsACFEntity(Entity) end local function RestrictInfo(Player, Entity) - if not RestrictInfoConVar:GetBool() then return false end + if not Restrict:GetBool() then return false end return not isOwner(Player, Entity) end @@ -102,7 +103,7 @@ end -- Returns 1 if functions returning sensitive info are restricted to owned props e2function number acfInfoRestricted() - return RestrictInfoConVar:GetBool() and 1 or 0 + return Restrict:GetBool() and 1 or 0 end __e2setcost(5) @@ -112,17 +113,7 @@ e2function string entity:acfName() if not IsACFEntity(this) then return "" end if RestrictInfo(self, this) then return "" end - if not this.Name then - if not this.BulletData then return "" end -- If not a a rack - if not this.BulletData.Id then return "" end - - local GunData = ACF.Weapons.Guns[this.BulletData.Id] - if not GunData then return "" end - - return GunData.name or "" - end - - return this.Name + return this.Name or "" end -- Returns the short name of an ACF entity @@ -221,9 +212,10 @@ e2function number entity:acfPropHealth() if not validPhysics(this) then return 0 end if RestrictInfo(self, this) then return 0 end if not ACF_Check(this) then return 0 end - if not this.ACF.Health then return 0 end - return Round(this.ACF.Health, 2) + local Health = this.ACF.Health + + return Health and Round(Health, 2) or 0 end -- Returns the current armor of an entity @@ -231,9 +223,10 @@ e2function number entity:acfPropArmor() if not validPhysics(this) then return 0 end if RestrictInfo(self, this) then return 0 end if not ACF_Check(this) then return 0 end - if not this.ACF.Armour then return 0 end - return Round(this.ACF.Armour, 2) + local Armor = this.ACF.Armour + + return Armor and Round(Armor, 2) or 0 end -- Returns the max health of an entity @@ -241,9 +234,10 @@ e2function number entity:acfPropHealthMax() if not validPhysics(this) then return 0 end if RestrictInfo(self, this) then return 0 end if not ACF_Check(this) then return 0 end - if not this.ACF.MaxHealth then return 0 end - return Round(this.ACF.MaxHealth, 2) + local MaxHealth = this.ACF.MaxHealth + + return MaxHealth and Round(MaxHealth, 2) or 0 end -- Returns the max armor of an entity @@ -252,7 +246,9 @@ e2function number entity:acfPropArmorMax() if RestrictInfo(self, this) then return 0 end if not ACF_Check(this) then return 0 end - return Round(this.ACF.MaxArmour or 0, 2) + local MaxArmor = this.ACF.MaxArmour + + return MaxArmor and Round(MaxArmor, 2) or 0 end -- Returns the ductility of an entity @@ -260,9 +256,10 @@ e2function number entity:acfPropDuctility() if not validPhysics(this) then return 0 end if RestrictInfo(self, this) then return 0 end if not ACF_Check(this) then return 0 end - if not this.ACF.Ductility then return 0 end - return this.ACF.Ductility * 100 + local Ductility = this.ACF.Ductility + + return Ductility and Ductility * 100 or 0 end __e2setcost(10) @@ -277,11 +274,11 @@ e2function number ranger:acfEffectiveArmor() if not (this and validPhysics(this.Entity)) then return 0 end if RestrictInfo(self, this.Entity) then return 0 end if not ACF_Check(this.Entity) then return 0 end - if not this.Entity.ACF.Armour then return 0 end + local Armor = this.Entity.ACF.Armour local HitAngle = ACF_GetHitAngle(this.HitNormal , this.HitPos - this.StartPos) - return Round(this.Entity.ACF.Armour / math.abs(math.cos(math.rad(HitAngle))), 2) + return Round(Armor / math.abs(math.cos(math.rad(HitAngle))), 2) end __e2setcost(20) @@ -291,7 +288,7 @@ e2function number entity:acfHitClip(vector HitPos) if not validPhysics(this) then return 0 end if RestrictInfo(self, this) then return 0 end - return ACF_CheckClips(this, HitPos) and 1 or 0 + return ACF.CheckClips(this, HitPos) and 1 or 0 end -- Returns all the linked entities @@ -461,18 +458,20 @@ end e2function number entity:acfRPM() if not IsACFEntity(this) then return 0 end if RestrictInfo(self, this) then return 0 end - if not this.FlyRPM then return 0 end - return floor(this.FlyRPM) + local FlyRPM = this.FlyRPM + + return FlyRPM and floor(FlyRPM) or 0 end -- Returns the current torque of an ACF engine e2function number entity:acfTorque() if not IsACFEntity(this) then return 0 end if RestrictInfo(self, this) then return 0 end - if not this.Torque then return 0 end - return floor(this.Torque) + local Torque = this.Torque + + return Torque and floor(Torque) or 0 end -- Returns the inertia of an ACF engine's flywheel @@ -487,9 +486,8 @@ end e2function number entity:acfFlyMass() if not IsACFEntity(this) then return 0 end if RestrictInfo(self, this) then return 0 end - if not this.Inertia then return 0 end - return (this.Inertia / 3.1416) * (this.Inertia / 3.1416) + return this.FlywheelMass or 0 end -- Returns the current power of an ACF engine @@ -531,9 +529,10 @@ end e2function number entity:acfThrottle() if not IsACFEntity(this) then return 0 end if RestrictInfo(self, this) then return 0 end - if not this.Throttle then return 0 end - return this.Throttle * 100 + local Throttle = this.Throttle + + return Throttle and Throttle * 100 or 0 end -- Sets the throttle value for an ACF engine @@ -557,16 +556,15 @@ e2function number entity:acfNumGears() if not IsACFEntity(this) then return 0 end if RestrictInfo(self, this) then return 0 end - return this.Gears or 0 + return this.GearCount or 0 end -- Returns the final ratio for an ACF gearbox e2function number entity:acfFinalRatio() if not IsACFEntity(this) then return 0 end if RestrictInfo(self, this) then return 0 end - if not this.GearTable then return 0 end - return this.GearTable.Final or 0 + return this.FinalDrive or 0 end -- Returns the total ratio (current gear * final) for an ACF gearbox @@ -590,16 +588,17 @@ e2function number entity:acfIsDual() if not IsACFEntity(this) then return 0 end if RestrictInfo(self, this) then return 0 end - return this.Dual and 1 or 0 + return this.DualClutch and 1 or 0 end -- Returns the time in ms an ACF gearbox takes to change gears e2function number entity:acfShiftTime() if not IsACFEntity(this) then return 0 end if RestrictInfo(self, this) then return 0 end - if not this.SwitchTime then return 0 end - return this.SwitchTime * 1000 + local Time = this.SwitchTime + + return Time and Time * 1000 or 0 end -- Returns 1 if an ACF gearbox is in gear @@ -614,12 +613,11 @@ end e2function number entity:acfGearRatio(number Gear) if not IsACFEntity(this) then return 0 end if RestrictInfo(self, this) then return 0 end - if not this.GearTable then return 0 end if not this.Gears then return 0 end - local GearNum = math.Clamp(floor(Gear), 1, this.Gears) + local Index = math.Clamp(floor(Gear), 0, this.GearCount) - return this.GearTable[GearNum] or 0 + return this.Gears[Index] end -- Returns the current torque output for an ACF gearbox @@ -675,7 +673,7 @@ end e2function void entity:acfBrakeLeft(number Brake) if not IsACFEntity(this) then return end if not isOwner(self, this) then return end - if not this.Dual then return end + if not this.DualClutch then return end this:TriggerInput("Left Brake", Brake) end @@ -684,7 +682,7 @@ end e2function void entity:acfBrakeRight(number Brake) if not IsACFEntity(this) then return end if not isOwner(self, this) then return end - if not this.Dual then return end + if not this.DualClutch then return end this:TriggerInput("Right Brake", Brake) end @@ -701,7 +699,7 @@ end e2function void entity:acfClutchLeft(number Clutch) if not IsACFEntity(this) then return end if not isOwner(self, this) then return end - if not this.Dual then return end + if not this.DualClutch then return end this:TriggerInput("Left Clutch", Clutch) end @@ -710,7 +708,7 @@ end e2function void entity:acfClutchRight(number Clutch) if not IsACFEntity(this) then return end if not isOwner(self, this) then return end - if not this.Dual then return end + if not this.DualClutch then return end this:TriggerInput("Right Clutch", Clutch) end @@ -728,7 +726,7 @@ end e2function void entity:acfHoldGear(number Hold) if not IsACFEntity(this) then return end if not isOwner(self, this) then return end - if not this.Auto then return end + if not this.Automatic then return end this:TriggerInput("Hold Gear", Hold) end @@ -737,7 +735,7 @@ end e2function void entity:acfShiftPointScale(number Scale) if not IsACFEntity(this) then return end if not isOwner(self, this) then return end - if not this.Auto then return end + if not this.Automatic then return end this:TriggerInput("Shift Speed Scale", Scale) end @@ -961,135 +959,114 @@ e2function string entity:acfRoundType() if not IsACFEntity(this) then return "" end if RestrictInfo(self, this) then return "" end - return this.AmmoType or "" + local BulletData = this.BulletData + + return BulletData and BulletData.Id or "" end -- Returns the type of ammo in a crate or gun e2function string entity:acfAmmoType() if not IsACFEntity(this) then return "" end if RestrictInfo(self, this) then return "" end - if not this.BulletData then return "" end - return this.BulletData.Type or "" + local BulletData = this.BulletData + + return BulletData and BulletData.Type or "" end --- Returns the caliber of an ammo, gun or rack +-- Returns the caliber of an ammo e2function number entity:acfCaliber() if not IsACFEntity(this) then return 0 end if RestrictInfo(self, this) then return 0 end - if not this.Caliber then -- If not a gun or ammo crate - if not this.BulletData then return 0 end -- If not a a rack - if not this.BulletData.Id then return 0 end - - local GunData = ACF.Weapons.Guns[this.BulletData.Id] - if not GunData then return 0 end + local Caliber = this.Caliber - return GunData.caliber * 10 or 0 - end - - return this.Caliber * 10 + return Caliber and Caliber * 10 or 0 end -- Returns the muzzle velocity of the ammo in a crate or gun e2function number entity:acfMuzzleVel() if not IsACFEntity(this) then return 0 end if RestrictInfo(self, this) then return 0 end - if not this.BulletData then return 0 end - if not this.BulletData.MuzzleVel then return 0 end - return this.BulletData.MuzzleVel * ACF.Scale + local BulletData = this.BulletData + local MuzzleVel = BulletData and BulletData.MuzzleVel + + return MuzzleVel and MuzzleVel * ACF.Scale or 0 end -- Returns the mass of the projectile in a crate or gun e2function number entity:acfProjectileMass() if not IsACFEntity(this) then return 0 end if RestrictInfo(self, this) then return 0 end - if not this.BulletData then return 0 end - if not this.BulletData.ProjMass then return 0 end - return this.BulletData.ProjMass + local BulletData = this.BulletData + + return BulletData and BulletData.ProjMass or 0 end e2function number entity:acfDragCoef() if not IsACFEntity(this) then return 0 end if RestrictInfo(self, this) then return 0 end - if not this.BulletData then return 0 end - if not this.BulletData.DragCoef then return 0 end - return this.BulletData.DragCoef / ACF.DragDiv + local BulletData = BulletData + local DragCoef = BulletData and BulletData.DragCoef + + return DragCoef and DragCoef / ACF.DragDiv or 0 end -- Returns the fin multiplier of the missile/bomb e2function number entity:acfFinMul() if not IsACFEntity(this) then return 0 end if RestrictInfo(self, this) then return 0 end - if not this.BulletData then return 0 end - if not this.BulletData.Id then return 0 end - - local GunData = ACF.Weapons.Guns[this.BulletData.Id] - if not GunData then return 0 end - if not GunData.round then return 0 end - - return GunData.round.finmul or 0 + return this.FinMultiplier or 0 end -- Returns the weight of the missile e2function number entity:acfMissileWeight() if not IsACFEntity(this) then return 0 end if RestrictInfo(self, this) then return 0 end - if not this.BulletData then return 0 end - if not this.BulletData.Id then return 0 end - - local GunData = ACF.Weapons.Guns[this.BulletData.Id] - if not GunData then return 0 end - - return GunData.weight or 0 + return this.ForcedMass or 0 end -- Returns the length of the missile e2function number entity:acfMissileLength() if not IsACFEntity(this) then return 0 end if RestrictInfo(self, this) then return 0 end - if not this.BulletData then return 0 end - if not this.BulletData.Id then return 0 end - - local GunData = ACF.Weapons.Guns[this.BulletData.Id] - - if not GunData then return 0 end - return GunData.length or 0 + return this.Length or 0 end -- Returns the number of projectiles in a flechette round e2function number entity:acfFLSpikes() if not IsACFEntity(this) then return 0 end if RestrictInfo(self, this) then return 0 end - if not this.BulletData then return 0 end - return this.BulletData.Flechettes or 0 + local BulletData = this.BulletData + + return BulletData and BulletData.Flechettes or 0 end -- Returns the mass of a single spike in a FL round in a crate or gun e2function number entity:acfFLSpikeMass() if not IsACFEntity(this) then return 0 end if RestrictInfo(self, this) then return 0 end - if not this.BulletData then return 0 end - if not this.BulletData.FlechetteMass then return 0 end - return this.BulletData.FlechetteMass + local BulletData = this.BulletData + + return BulletData and BulletData.FlechetteMass or 0 end -- Returns the radius of the spikes in a flechette round in mm e2function number entity:acfFLSpikeRadius() if not IsACFEntity(this) then return 0 end if RestrictInfo(self, this) then return 0 end - if not this.BulletData then return 0 end - if not this.BulletData.FlechetteRadius then return 0 end - return Round(this.BulletData.FlechetteRadius * 10, 2) + local Radius = this.BulletData and this.BulletData.FlechetteRadius + + return Radius and Round(Radius * 10, 2) or 0 end __e2setcost(10) @@ -1098,38 +1075,32 @@ __e2setcost(10) e2function number entity:acfPenetration() if not IsACFEntity(this) then return 0 end if RestrictInfo(self, this) then return 0 end - if not this.BulletData then return 0 end - if not this.BulletData.Type then return 0 end local BulletData = this.BulletData - local RoundData = RoundTypes[BulletData.Type] + local AmmoType = BulletData and AmmoTypes[BulletData.Type] - if not RoundData then return 0 end + if not AmmoType then return 0 end - local DisplayData = RoundData.getDisplayData(BulletData) + local DisplayData = AmmoType:GetDisplayData(BulletData) + local MaxPen = DisplayData and DisplayData.MaxPen - if not DisplayData.MaxPen then return 0 end - - return Round(DisplayData.MaxPen, 2) + return MaxPen and Round(MaxPen, 2) or 0 end -- Returns the blast radius of an ACF round e2function number entity:acfBlastRadius() if not IsACFEntity(this) then return 0 end if RestrictInfo(self, this) then return 0 end - if not this.BulletData then return 0 end - if not this.BulletData.Type then return 0 end local BulletData = this.BulletData - local RoundData = RoundTypes[BulletData.Type] - - if not RoundData then return 0 end + local AmmoType = BulletData and AmmoTypes[BulletData.Type] - local DisplayData = RoundData.getDisplayData(BulletData) + if not AmmoType then return 0 end - if not DisplayData.BlastRadius then return 0 end + local DisplayData = AmmoType:GetDisplayData(BulletData) + local Radius = DisplayData and DisplayData.BlastRadius - return Round(DisplayData.BlastRadius, 2) + return Radius and Round(Radius, 2) or 0 end --Returns the number of rounds in active ammo crates linked to an ACF weapon diff --git a/lua/weapons/gmod_tool/stools/acfsound.lua b/lua/weapons/gmod_tool/stools/acfsound.lua index 843a788e3..0f2b001c0 100644 --- a/lua/weapons/gmod_tool/stools/acfsound.lua +++ b/lua/weapons/gmod_tool/stools/acfsound.lua @@ -11,54 +11,43 @@ if CLIENT then language.Add("Tool.acfsound.0", "Left click to apply sound. Right click to copy sound. Reload to set default sound. Use an empty sound path to disable sound.") end -ACF.SoundToolSupport = { - acf_gun = { - GetSound = function(ent) - return { - Sound = ent.Sound - } - end, - SetSound = function(ent, soundData) - ent.Sound = soundData.Sound - ent:SetNWString("Sound", soundData.Sound) - end, - ResetSound = function(ent) - local Class = ent.Class - local Classes = ACF.Classes - - local soundData = { - Sound = Classes["GunClass"][Class]["sound"] -- REPLACE - } - - local setSound = ACF.SoundToolSupport["acf_gun"].SetSound - setSound(ent, soundData) - end - }, - acf_engine = { - GetSound = function(ent) - return { - Sound = ent.SoundPath, - Pitch = ent.SoundPitch - } - end, - SetSound = function(ent, soundData) - ent.SoundPath = soundData.Sound - ent.SoundPitch = soundData.Pitch - end, - ResetSound = function(ent) - local Id = ent.Id - local List = ACF.Weapons - local pitch = List["Mobility"][Id]["pitch"] or 1 - - local soundData = { - Sound = List["Mobility"][Id]["sound"], - Pitch = pitch - } - - local setSound = ACF.SoundToolSupport["acf_engine"].SetSound - setSound(ent, soundData) - end - } +ACF.SoundToolSupport = ACF.SoundToolSupport or {} + +local Sounds = ACF.SoundToolSupport + +Sounds.acf_gun = { + GetSound = function(ent) + return { + Sound = ent.SoundPath + } + end, + SetSound = function(ent, soundData) + ent.SoundPath = soundData.Sound + ent:SetNWString("Sound", soundData.Sound) + end, + ResetSound = function(ent) + local setSound = Sounds.acf_gun.SetSound + + setSound(ent, { Sound = ent.DefaultSound }) + end +} + +Sounds.acf_engine = { + GetSound = function(ent) + return { + Sound = ent.SoundPath, + Pitch = ent.SoundPitch + } + end, + SetSound = function(ent, soundData) + ent.SoundPath = soundData.Sound + ent.SoundPitch = soundData.Pitch + end, + ResetSound = function(ent) + local setSound = Sounds.acf_engine.SetSound + + setSound(ent, { Sound = ent.DefaultSound }) + end } local function ReplaceSound(_, Entity, data) From 5f51f22edbd8ee594dac574ddaedf072377bb044 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Fri, 20 Nov 2020 02:21:52 -0300 Subject: [PATCH 152/279] Removed old functions - Removed old, and now unused, ACF functions. - Old registration functions will now display a message whenever they're called. --- lua/acf/base/acf_globals.lua | 49 +- lua/acf/base/sh_classes.lua | 54 +- lua/acf/base/sh_traceline.lua | 22 +- lua/acf/base/sv_validation.lua | 1 + lua/acf/client/sk_menu.lua | 497 -------- lua/acf/server/ballistics.lua | 1 - lua/acf/shared/acfcratelist.lua | 399 ------- lua/acf/shared/ammo_types/fl.lua | 27 +- lua/acf/shared/engines/b4.lua | 68 -- lua/acf/shared/engines/b6.lua | 69 -- lua/acf/shared/engines/electric.lua | 133 --- lua/acf/shared/engines/i2.lua | 36 - lua/acf/shared/engines/i3.lua | 106 -- lua/acf/shared/engines/i4.lua | 106 -- lua/acf/shared/engines/i5.lua | 72 -- lua/acf/shared/engines/i6.lua | 106 -- lua/acf/shared/engines/radial.lua | 69 -- lua/acf/shared/engines/rotary.lua | 51 - lua/acf/shared/engines/single.lua | 51 - lua/acf/shared/engines/special.lua | 189 ---- lua/acf/shared/engines/turbine.lua | 242 ---- lua/acf/shared/engines/v10.lua | 51 - lua/acf/shared/engines/v12.lua | 123 -- lua/acf/shared/engines/v2.lua | 51 - lua/acf/shared/engines/v4.lua | 36 - lua/acf/shared/engines/v6.lua | 85 -- lua/acf/shared/engines/v8.lua | 106 -- lua/acf/shared/fueltanks/basic.lua | 355 ------ lua/acf/shared/gearboxes/3-auto.lua | 2 +- lua/acf/shared/gearboxes/4-speed.lua | 302 ----- lua/acf/shared/gearboxes/6-speed.lua | 331 ------ lua/acf/shared/gearboxes/8-speed.lua | 361 ------ lua/acf/shared/gearboxes/automatic.lua | 1059 ------------------ lua/acf/shared/gearboxes/clutch.lua | 70 -- lua/acf/shared/gearboxes/cvt.lua | 313 ------ lua/acf/shared/gearboxes/differential.lua | 218 ---- lua/acf/shared/gearboxes/doublediff.lua | 60 - lua/acf/shared/gearboxes/transfer.lua | 118 -- lua/acf/shared/guns/autocannon.lua | 88 -- lua/acf/shared/guns/autoloader.lua | 107 -- lua/acf/shared/guns/cannon.lua | 121 -- lua/acf/shared/guns/grenadelauncher.lua | 31 - lua/acf/shared/guns/heavymachinegun.lua | 97 -- lua/acf/shared/guns/howitzer.lua | 117 -- lua/acf/shared/guns/machinegun.lua | 72 -- lua/acf/shared/guns/mortar.lua | 104 -- lua/acf/shared/guns/rotaryautocannon.lua | 70 -- lua/acf/shared/guns/semiauto.lua | 112 -- lua/acf/shared/guns/shortcannon.lua | 106 -- lua/acf/shared/guns/smokelauncher.lua | 53 - lua/acf/shared/guns/smoothbore.lua | 73 -- lua/acf/shared/rounds/acf_roundfunctions.lua | 63 -- lua/acf/shared/rounds/ap.lua | 211 ---- lua/acf/shared/rounds/apcr.lua | 216 ---- lua/acf/shared/rounds/apds.lua | 223 ---- lua/acf/shared/rounds/apfsds.lua | 223 ---- lua/acf/shared/rounds/aphe.lua | 246 ---- lua/acf/shared/rounds/fl.lua | 317 ------ lua/acf/shared/rounds/he.lua | 218 ---- lua/acf/shared/rounds/heat.lua | 379 ------- lua/acf/shared/rounds/heatfs.lua | 405 ------- lua/acf/shared/rounds/hp.lua | 151 --- lua/acf/shared/rounds/refill.lua | 85 -- lua/acf/shared/rounds/smoke.lua | 243 ---- lua/acf/shared/tool_operations/acf_menu.lua | 1 + lua/autorun/acf_loader.lua | 95 -- lua/effects/acf_bullet_effect.lua | 1 + lua/entities/acf_engine/cl_init.lua | 52 - lua/entities/acf_fueltank/cl_init.lua | 108 -- lua/entities/acf_gearbox/cl_init.lua | 230 ---- lua/entities/acf_gun/cl_init.lua | 32 - lua/entities/base_scalable_box/init.lua | 2 +- lua/starfall/libs_sv/acffunctions.lua | 26 +- lua/weapons/acf_base/init.lua | 36 +- lua/weapons/acf_base/shared.lua | 4 +- lua/weapons/gmod_tool/stools/acfmenu.lua | 232 ---- 76 files changed, 92 insertions(+), 10847 deletions(-) delete mode 100644 lua/acf/client/sk_menu.lua delete mode 100644 lua/acf/shared/acfcratelist.lua delete mode 100644 lua/acf/shared/fueltanks/basic.lua delete mode 100644 lua/acf/shared/gearboxes/automatic.lua delete mode 100644 lua/acf/shared/rounds/acf_roundfunctions.lua delete mode 100644 lua/acf/shared/rounds/ap.lua delete mode 100644 lua/acf/shared/rounds/apcr.lua delete mode 100644 lua/acf/shared/rounds/apds.lua delete mode 100644 lua/acf/shared/rounds/apfsds.lua delete mode 100644 lua/acf/shared/rounds/aphe.lua delete mode 100644 lua/acf/shared/rounds/fl.lua delete mode 100644 lua/acf/shared/rounds/he.lua delete mode 100644 lua/acf/shared/rounds/heat.lua delete mode 100644 lua/acf/shared/rounds/heatfs.lua delete mode 100644 lua/acf/shared/rounds/hp.lua delete mode 100644 lua/acf/shared/rounds/refill.lua delete mode 100644 lua/acf/shared/rounds/smoke.lua delete mode 100644 lua/weapons/gmod_tool/stools/acfmenu.lua diff --git a/lua/acf/base/acf_globals.lua b/lua/acf/base/acf_globals.lua index 77a58d332..5cde2a62b 100644 --- a/lua/acf/base/acf_globals.lua +++ b/lua/acf/base/acf_globals.lua @@ -1,9 +1,8 @@ do -- ACF global vars ACF.AmmoTypes = ACF.AmmoTypes or {} ACF.AmmoCrates = ACF.AmmoCrates or {} + ACF.Classes = ACF.Classes or {} ACF.FuelTanks = ACF.FuelTanks or {} - ACF.MenuFunc = ACF.MenuFunc or {} - ACF.AmmoBlacklist = ACF.AmmoBlacklist or {} ACF.Repositories = ACF.Repositories or {} -- Misc @@ -95,43 +94,6 @@ do -- ACF global vars ACF.CuIToLiter = 0.0163871 -- cubic inches to liters ACF.RefillDistance = 300 --Distance in which ammo crate starts refilling. ACF.RefillSpeed = 700 -- (ACF.RefillSpeed / RoundMass) / Distance - - -- DELETE - ACF.FuelDensity = { - Diesel = 0.832, - Petrol = 0.745, - Electric = 3.89 -- li-ion - } - - -- DELETE - ACF.Efficiency = { - GenericPetrol = 0.304, -- kg per kw hr - GenericDiesel = 0.243, - Turbine = 0.375, - Wankel = 0.335, - Radial = 0.4, -- 0.38 to 0.53 - Electric = 0.2125 --percent efficiency converting chemical kw into mechanical kw - } - - -- DELETE - ACF.TorqueScale = { - GenericPetrol = 0.25, - GenericDiesel = 0.35, - Turbine = 0.2, - Wankel = 0.2, - Radial = 0.3, - Electric = 0.5 - } - - -- DELETE - ACF.EngineHPMult = { - GenericPetrol = 0.2, - GenericDiesel = 0.5, - Turbine = 0.125, - Wankel = 0.125, - Radial = 0.3, - Electric = 0.75 - } end do -- ACF Convars/Callbacks ------------------------ @@ -182,7 +144,6 @@ do -- ACF Convars/Callbacks ------------------------ game.AddParticles("particles/acf_muzzleflashes.pcf") game.AddParticles("particles/explosion1.pcf") game.AddParticles("particles/rocket_motor.pcf") - game.AddDecal("GunShot1", "decals/METAL/shot5") end if SERVER then @@ -195,7 +156,6 @@ if SERVER then CreateConVar("acf_enable_workshop_extras", 0, FCVAR_ARCHIVE, "Enable extra workshop content download for clients. Requires server restart on change.", 0, 1) CreateConVar("acf_gamemode", 1, FCVAR_ARCHIVE + FCVAR_NOTIFY, "Sets the ACF gamemode of the server. 0 = Sandbox, 1 = Classic, 2 = Competitive", 0, 2) CreateConVar("acf_restrict_info", 1, FCVAR_ARCHIVE, "If enabled, players will be only allowed to get info from entities they're allowed to mess with.", 0, 1) - CreateConVar("acf_hepush", 1, FCVAR_ARCHIVE, "Whether or not HE pushes on entities", 0, 1) CreateConVar("acf_kepush", 1, FCVAR_ARCHIVE, "Whether or not kinetic force pushes on entities", 0, 1) CreateConVar("acf_recoilpush", 1, FCVAR_ARCHIVE, "Whether or not ACF guns apply recoil", 0, 1) @@ -262,13 +222,6 @@ elseif CLIENT then --------------------------------------------- end --- DELETE -timer.Simple(0, function() - for _, Table in pairs(ACF.Classes.GunClass) do - PrecacheParticleSystem(Table["muzzleflash"]) - end -end) - function switch(cases, arg) local Var = cases[arg] diff --git a/lua/acf/base/sh_classes.lua b/lua/acf/base/sh_classes.lua index a385183dc..50db1fd7a 100644 --- a/lua/acf/base/sh_classes.lua +++ b/lua/acf/base/sh_classes.lua @@ -233,10 +233,6 @@ do -- Weapon registration functions Class.Destiny = "Weapons" - if not Class.EntClass then - Class.EntClass = "acf_gun" - end - if Class.MuzzleFlash then PrecacheParticleSystem(Class.MuzzleFlash) end @@ -251,13 +247,7 @@ do -- Ammo crate registration function local Crates = ACF.Classes.Crates function ACF.RegisterCrate(ID, Data) - local Class = AddSimpleClass(ID, Crates, Data) - - if not Class.EntClass then - Class.EntClass = "acf_ammo" - end - - return Class + return AddSimpleClass(ID, Crates, Data) end end @@ -294,13 +284,7 @@ do -- Engine registration functions end function ACF.RegisterEngine(ID, ClassID, Data) - local Class = AddGroupedClass(ID, ClassID, Engines, Data) - - if not Class.EntClass then - Class.EntClass = "acf_engine" - end - - return Class + return AddGroupedClass(ID, ClassID, Engines, Data) end end @@ -338,10 +322,6 @@ do -- Fuel tank registration functions function ACF.RegisterFuelTank(ID, ClassID, Data) local Class = AddGroupedClass(ID, ClassID, FuelTanks, Data) - if not Class.EntClass then - Class.EntClass = "acf_engine" - end - if Class.IsExplosive == nil then Class.IsExplosive = true end @@ -384,10 +364,6 @@ do -- Gearbox registration functions function ACF.RegisterGearbox(ID, ClassID, Data) local Class = AddGroupedClass(ID, ClassID, Gearboxes, Data) - if not Class.EntClass then - Class.EntClass = "acf_gearbox" - end - if not Class.Sound then Class.Sound = "vehicles/junker/jnk_fourth_cruise_loop2.wav" end @@ -530,3 +506,29 @@ do -- Entity class registration function return List end end + +do -- Discontinued functions + function ACF_defineGunClass(ID) + print("Attempted to register weapon class " .. ID .. " with a discontinued function. Use ACF.RegisterWeaponClass instead.") + end + + function ACF_defineGun(ID) + print("Attempted to register weapon " .. ID .. " with a discontinued function. Use ACF.RegisterWeapon instead.") + end + + function ACF_DefineEngine(ID) + print("Attempted to register engine " .. ID .. " with a discontinued function. Use ACF.RegisterEngine instead.") + end + + function ACF_DefineGearbox(ID) + print("Attempted to register gearbox " .. ID .. " with a discontinued function. Use ACF.RegisterGearbox instead.") + end + + function ACF_DefineFuelTank(ID) + print("Attempted to register fuel tank type " .. ID .. " with a discontinued function. Use ACF.RegisterFuelTankClass instead.") + end + + function ACF_DefineFuelTankSize(ID) + print("Attempted to register fuel tank " .. ID .. " with a discontinued function. Use ACF.RegisterFuelTank instead.") + end +end diff --git a/lua/acf/base/sh_traceline.lua b/lua/acf/base/sh_traceline.lua index eafbb2246..7d7b11cf5 100644 --- a/lua/acf/base/sh_traceline.lua +++ b/lua/acf/base/sh_traceline.lua @@ -12,19 +12,19 @@ -- Known issues: -- MASK_SHOT ignores all entities. -if not util.LegacyTraceLine then - local Hull = util.TraceHull - local Zero = Vector() +local Hull = util.TraceHull +local Zero = Vector() - -- Available for use, just in case +-- Available for use, just in case +if not util.LegacyTraceLine then util.LegacyTraceLine = util.TraceLine +end - function util.TraceLine(TraceData, ...) - if istable(TraceData) then - TraceData.mins = Zero - TraceData.maxs = Zero - end - - return Hull(TraceData, ...) +function util.TraceLine(TraceData, ...) + if istable(TraceData) then + TraceData.mins = Zero + TraceData.maxs = Zero end + + return Hull(TraceData, ...) end diff --git a/lua/acf/base/sv_validation.lua b/lua/acf/base/sv_validation.lua index 4b65dfc43..30132f112 100644 --- a/lua/acf/base/sv_validation.lua +++ b/lua/acf/base/sv_validation.lua @@ -148,6 +148,7 @@ function ACF_Activate(Entity, Recalc) end -- TODO: Figure out what are the 6.45 and 0.52505066107 multipliers for + -- NOTE: Why are we applying multipliers to the stored surface area? local SurfaceArea = PhysObj:GetSurfaceArea() if SurfaceArea then -- Normal collisions diff --git a/lua/acf/client/sk_menu.lua b/lua/acf/client/sk_menu.lua deleted file mode 100644 index 3a3aef5f2..000000000 --- a/lua/acf/client/sk_menu.lua +++ /dev/null @@ -1,497 +0,0 @@ --- DELETE -function PANEL:Init() - acfmenupanel = self.Panel - -- height - self:SetTall(surface.ScreenHeight() - 120) - --Weapon Select - self.WeaponSelect = vgui.Create("DTree", self) - self.WeaponData = ACF.Weapons - local Classes = ACF.Classes - self.Classes = {} - - for ID, Table in pairs(Classes) do - self.Classes[ID] = {} - - for ClassID, Class in pairs(Table) do - Class.id = ClassID - table.insert(self.Classes[ID], Class) - end - - table.sort(self.Classes[ID], function(a, b) return a.id < b.id end) - end - - local WeaponDisplay = ACF.Weapons - self.WeaponDisplay = {} - - for ID, Table in pairs(WeaponDisplay) do - self.WeaponDisplay[ID] = {} - - for _, Data in pairs(Table) do - table.insert(self.WeaponDisplay[ID], Data) - end - - if ID == "Guns" then - table.sort(self.WeaponDisplay[ID], function(a, b) - if a.gunclass == b.gunclass then - return a.caliber < b.caliber - else - return a.gunclass < b.gunclass - end - end) - else - table.sort(self.WeaponDisplay[ID], function(a, b) return a.id < b.id end) - end - end - - local HomeNode = self.WeaponSelect:AddNode("ACF Home", "icon16/newspaper.png") - local OldSelect = HomeNode.OnNodeSelected - HomeNode.mytable = {} - - HomeNode.mytable.guicreate = (function(_, Table) - ACFHomeGUICreate(Table) - end or nil) - - function HomeNode:OnNodeSelected(Node) - acfmenupanel:UpdateDisplay(self.mytable) - - OldSelect(self, Node) - end - - self.WeaponSelect:SetSelectedItem(HomeNode) - - local RoundAttribs = ACF.RoundTypes - self.RoundAttribs = {} - - for ID, Table in pairs(RoundAttribs) do - Table.id = ID - table.insert(self.RoundAttribs, Table) - end - - table.sort(self.RoundAttribs, function(a, b) return a.id < b.id end) - local Guns = self.WeaponSelect:AddNode("Guns") - - for _, Class in pairs(self.Classes["GunClass"]) do - local SubNode = Guns:AddNode(Class.name or "No Name") - - for _, Ent in pairs(self.WeaponDisplay["Guns"]) do - if Ent.gunclass == Class.id then - local EndNode = SubNode:AddNode(Ent.name or "No Name") - EndNode.mytable = Ent - - function EndNode:DoClick() - RunConsoleCommand("acfmenu_type", self.mytable.type) - acfmenupanel:UpdateDisplay(self.mytable) - end - - EndNode.Icon:SetImage("icon16/newspaper.png") - end - end - end - - local Ammo = self.WeaponSelect:AddNode("Ammo") - - for _, AmmoTable in pairs(self.RoundAttribs) do - local EndNode = Ammo:AddNode(AmmoTable.name or "No Name") - EndNode.mytable = AmmoTable - - function EndNode:DoClick() - RunConsoleCommand("acfmenu_type", self.mytable.type) - acfmenupanel:UpdateDisplay(self.mytable) - end - - EndNode.Icon:SetImage("icon16/newspaper.png") - end - - local Mobility = self.WeaponSelect:AddNode("Mobility") - local Engines = Mobility:AddNode("Engines") - local Gearboxes = Mobility:AddNode("Gearboxes") - local FuelTanks = Mobility:AddNode("Fuel Tanks") - local EngineSubcats = {} - - for _, MobilityTable in pairs(self.WeaponDisplay["Mobility"]) do - local NodeAdd = Mobility - - if (MobilityTable.ent == "acf_engine") then - NodeAdd = Engines - elseif (MobilityTable.ent == "acf_gearbox") then - NodeAdd = Gearboxes - elseif (MobilityTable.ent == "acf_fueltank") then - NodeAdd = FuelTanks - end - - if ((EngineSubcats["misce"] == nil) and (EngineSubcats["miscg"] == nil)) then - EngineSubcats["misce"] = Engines:AddNode("Miscellaneous") - EngineSubcats["miscg"] = Gearboxes:AddNode("Miscellaneous") - end - - if MobilityTable.category and not EngineSubcats[MobilityTable.category] then - EngineSubcats[MobilityTable.category] = NodeAdd:AddNode(MobilityTable.category) - end - end - - for _, MobilityTable in pairs(self.WeaponDisplay["Mobility"]) do - local NodeAdd = Mobility - - if MobilityTable.ent == "acf_engine" then - NodeAdd = Engines - - if (MobilityTable.category) then - NodeAdd = EngineSubcats[MobilityTable.category] - else - NodeAdd = EngineSubcats["misce"] - end - elseif MobilityTable.ent == "acf_gearbox" then - NodeAdd = Gearboxes - - if (MobilityTable.category) then - NodeAdd = EngineSubcats[MobilityTable.category] - else - NodeAdd = EngineSubcats["miscg"] - end - elseif MobilityTable.ent == "acf_fueltank" then - NodeAdd = FuelTanks - - if (MobilityTable.category) then - NodeAdd = EngineSubcats[MobilityTable.category] - end - end - - local EndNode = NodeAdd:AddNode(MobilityTable.name or "No Name") - EndNode.mytable = MobilityTable - - function EndNode:DoClick() - RunConsoleCommand("acfmenu_type", self.mytable.type) - acfmenupanel:UpdateDisplay(self.mytable) - end - - EndNode.Icon:SetImage("icon16/newspaper.png") - end - --[[local Missiles = self.WeaponSelect:AddNode( "Missiles" ) - for MisID, MisTable in pairs(self.WeaponDisplay["Missiles"]) do - - local EndNode = Missiles:AddNode( MisTable.name or "No Name" ) - - EndNode.mytable = MisTable - function EndNode:DoClick() - RunConsoleCommand( "acfmenu_type", self.mytable.type ) - acfmenupanel:UpdateDisplay( self.mytable ) - end - - EndNode.Icon:SetImage( "icon16/newspaper.png") - - end]] - -- local Sensors = self.WeaponSelect:AddNode( "Sensors" ) - -- for SensorsID,SensorsTable in pairs(self.WeaponDisplay["Sensors"]) do - -- local EndNode = Sensors:AddNode( SensorsTable.name or "No Name" ) - -- EndNode.mytable = SensorsTable - -- function EndNode:DoClick() - -- RunConsoleCommand( "acfmenu_type", self.mytable.type ) - -- acfmenupanel:UpdateDisplay( self.mytable ) - -- end - -- EndNode.Icon:SetImage( "icon16/newspaper.png" ) - -- end -end - --- DELETE -function PANEL:Think() -end - --- DELETE -function PANEL:UpdateDisplay(Table) - RunConsoleCommand("acfmenu_id", Table.id or 0) - - --If a previous display exists, erase it - if (acfmenupanel.CustomDisplay) then - acfmenupanel.CustomDisplay:Clear(true) - acfmenupanel.CustomDisplay = nil - acfmenupanel.CData = nil - end - - --Create the space to display the custom data - acfmenupanel.CustomDisplay = vgui.Create("DPanelList", acfmenupanel) - acfmenupanel.CustomDisplay:SetSpacing(10) - acfmenupanel.CustomDisplay:EnableHorizontal(false) - acfmenupanel.CustomDisplay:EnableVerticalScrollbar(false) - acfmenupanel.CustomDisplay:SetSize(acfmenupanel:GetWide(), acfmenupanel:GetTall()) - - if not acfmenupanel["CData"] then - --Create a table for the display to store data - acfmenupanel["CData"] = {} - end - - acfmenupanel.CreateAttribs = Table.guicreate - acfmenupanel.UpdateAttribs = Table.guiupdate - acfmenupanel:CreateAttribs(Table) - acfmenupanel:PerformLayout() -end - --- DELETE -function PANEL:PerformLayout() - --Starting positions - local vspacing = 10 - local ypos = 0 - --Selection Tree panel - acfmenupanel.WeaponSelect:SetPos(0, ypos) - acfmenupanel.WeaponSelect:SetSize(acfmenupanel:GetWide(), ScrH() * 0.4) - ypos = acfmenupanel.WeaponSelect.Y + acfmenupanel.WeaponSelect:GetTall() + vspacing - - if acfmenupanel.CustomDisplay then - --Custom panel - acfmenupanel.CustomDisplay:SetPos(0, ypos) - acfmenupanel.CustomDisplay:SetSize(acfmenupanel:GetWide(), acfmenupanel:GetTall() - acfmenupanel.WeaponSelect:GetTall() - 10) - ypos = acfmenupanel.CustomDisplay.Y + acfmenupanel.CustomDisplay:GetTall() + vspacing - end -end - --- DELETE -function ACFHomeGUICreate() - if not acfmenupanel.CustomDisplay then return end - - local Display = acfmenupanel.CustomDisplay - local CData = acfmenupanel.CData - - local Text = "%s Status\n\nVersion: %s\nBranch: %s\nStatus: %s\n\n" - local Repo = ACF.GetVersion("ACF-3") - local Server = Repo.Server - local SVCode = Server and Server.Code or "Unable to Retrieve" - local SVHead = Server and Server.Head or "Unable to Retrieve" - local SVStatus = Server and Server.Status or "Unable to Retrieve" - - if not Repo.Status then - ACF.GetVersionStatus("ACF-3") - end - - CData.Header = vgui.Create("DLabel") - CData.Header:SetText("ACF Version Status\n") - CData.Header:SetFont("ACF_Title") - CData.Header:SetDark(true) - CData.Header:SizeToContents() - Display:AddItem(CData.Header) - - CData.ServerStatus = vgui.Create("DLabel") - CData.ServerStatus:SetText(Text:format("Server", SVCode, SVHead, SVStatus)) - CData.ServerStatus:SetFont("ACF_Label") - CData.ServerStatus:SetDark(true) - CData.ServerStatus:SizeToContents() - Display:AddItem(CData.ServerStatus) - - CData.ClientStatus = vgui.Create("DLabel") - CData.ClientStatus:SetText(Text:format("Client", Repo.Code, Repo.Head, Repo.Status)) - CData.ClientStatus:SetFont("ACF_Label") - CData.ClientStatus:SetDark(true) - CData.ClientStatus:SizeToContents() - Display:AddItem(CData.ClientStatus) -end - --- DELETE -function PANEL:AmmoSelect(Blacklist) - if not acfmenupanel.CustomDisplay then return end - - local AmmoData = acfmenupanel.AmmoData - - if not Blacklist then - Blacklist = {} - end - - if not AmmoData then - AmmoData = { - Id = "Ammo2x4x4", - Type = "Ammo", - Data = acfmenupanel.WeaponData.Guns["12.7mmMG"].round - } - - acfmenupanel.AmmoData = AmmoData - end - - --Creating the ammo crate selection - --[[ - acfmenupanel.CData.CrateSelect = vgui.Create("DComboBox", acfmenupanel.CustomDisplay) --Every display and slider is placed in the Round table so it gets trashed when selecting a new round type - acfmenupanel.CData.CrateSelect:SetSize(100, 30) - - for Key, Value in pairs(acfmenupanel.WeaponDisplay["Ammo"]) do - acfmenupanel.CData.CrateSelect:AddChoice(Value.id, Key) - end - - acfmenupanel.CData.CrateSelect.OnSelect = function(_, _, data) - RunConsoleCommand("acfmenu_id", data) - acfmenupanel.AmmoData["Id"] = data - self:UpdateAttribs() - end - - acfmenupanel.CData.CrateSelect:SetText(acfmenupanel.AmmoData["Id"]) - acfmenupanel.CustomDisplay:AddItem(acfmenupanel.CData.CrateSelect) - ]]-- - - RunConsoleCommand("acfmenu_id", AmmoData.Id) - --Create the caliber selection display - acfmenupanel.CData.CaliberSelect = vgui.Create("DComboBox", acfmenupanel.CustomDisplay) - acfmenupanel.CData.CaliberSelect:SetSize(100, 30) - - for Key, Value in pairs(acfmenupanel.WeaponDisplay["Guns"]) do - if (not table.HasValue(Blacklist, Value.gunclass)) then - acfmenupanel.CData.CaliberSelect:AddChoice(Value.id, Key) - end - end - - acfmenupanel.CData.CaliberSelect.OnSelect = function(_, _, data) - AmmoData.Data = acfmenupanel.WeaponData.Guns[data].round - - self:UpdateAttribs() - self:UpdateAttribs() --Note : this is intentional - end - - acfmenupanel.CData.CaliberSelect:SetText(AmmoData.Data.id) - acfmenupanel.CustomDisplay:AddItem(acfmenupanel.CData.CaliberSelect) - - -- Create ammo crate scale sliders - local X = AmmoData["Ammo Scale X"] or 24 - local Y = AmmoData["Ammo Scale Y"] or 24 - local Z = AmmoData["Ammo Scale Z"] or 24 - - acfmenupanel:AmmoSlider("Ammo Scale X", X, 6, 96, 3, "Crate X scale") - acfmenupanel:AmmoSlider("Ammo Scale Y", Y, 6, 96, 3, "Crate Y scale") - acfmenupanel:AmmoSlider("Ammo Scale Z", Z, 6, 96, 3, "Crate Z scale") - - acfmenupanel["CData"]["Ammo Scale X"].OnValueChanged = function(_, val) - if AmmoData["Ammo Scale X"] ~= val then - AmmoData["Ammo Scale X"] = val - - self:UpdateAttribs("Ammo Scale X") - - RunConsoleCommand("acfmenu_data11", val) - end - end - - acfmenupanel["CData"]["Ammo Scale Y"].OnValueChanged = function(_, val) - if AmmoData["Ammo Scale Y"] ~= val then - AmmoData["Ammo Scale Y"] = val - - self:UpdateAttribs("Ammo Scale Y") - - RunConsoleCommand("acfmenu_data12", val) - end - end - - acfmenupanel["CData"]["Ammo Scale Z"].OnValueChanged = function(_, val) - if AmmoData["Ammo Scale Z"] ~= val then - AmmoData["Ammo Scale Z"] = val - - self:UpdateAttribs("Ammo Scale Z") - - RunConsoleCommand("acfmenu_data13", val) - end - end -end - --- DELETE -function PANEL:AmmoUpdate() - local AmmoData = acfmenupanel.AmmoData - - acfmenupanel:AmmoSlider("Ammo Scale X", AmmoData["Ammo Scale X"], 6, 96, 3, "Crate X scale") - acfmenupanel:AmmoSlider("Ammo Scale Y", AmmoData["Ammo Scale Y"], 6, 96, 3, "Crate Y scale") - acfmenupanel:AmmoSlider("Ammo Scale Z", AmmoData["Ammo Scale Z"], 6, 96, 3, "Crate Z scale") -end - --- DELETE -function PANEL:AmmoSlider(Name, Value, Min, Max, Decimals, Title, Desc) - local Panels = acfmenupanel.CData - - if not Panels[Name] then - Panels[Name] = vgui.Create("DNumSlider", acfmenupanel.CustomDisplay) - Panels[Name].Label:SetSize(0) --Note : this is intentional - Panels[Name]:SetTall(50) -- make the slider taller to fit the new label - Panels[Name]:SetMin(Min) - Panels[Name]:SetMax(Max) - Panels[Name]:SetDecimals(Decimals) - Panels[Name .. "_label"] = vgui.Create("DLabel", Panels[Name]) -- recreating the label - Panels[Name .. "_label"]:SetPos(0, 0) - Panels[Name .. "_label"]:SetText(Title) - Panels[Name .. "_label"]:SizeToContents() - Panels[Name .. "_label"]:SetDark(true) - - Panels[Name].OnValueChanged = function(_, val) - if acfmenupanel.AmmoData[Name] ~= val then - acfmenupanel.AmmoData[Name] = val - self:UpdateAttribs(Name) - end - end - - local OldValue = acfmenupanel.AmmoData[Name] - - if OldValue then - Panels[Name]:SetValue(OldValue) - end - - acfmenupanel.CustomDisplay:AddItem(Panels[Name]) - end - - Panels[Name]:SetMin(Min) - Panels[Name]:SetMax(Max) - Panels[Name]:SetValue(Value) - - if Desc then - if not Panels[Name .. "_text"] then - Panels[Name .. "_text"] = vgui.Create("DLabel") - Panels[Name .. "_text"]:SetText(Desc) - Panels[Name .. "_text"]:SetDark(true) - Panels[Name .. "_text"]:SetTall(20) - acfmenupanel.CustomDisplay:AddItem(Panels[Name .. "_text"]) - end - - Panels[Name .. "_text"]:SetText(Desc) - Panels[Name .. "_text"]:SetSize(acfmenupanel.CustomDisplay:GetWide(), 10) - Panels[Name .. "_text"]:SizeToContentsX() - end -end - --- DELETE -function PANEL:AmmoCheckbox(Name, Title, Desc) - if not acfmenupanel["CData"][Name] then - acfmenupanel["CData"][Name] = vgui.Create("DCheckBoxLabel") - acfmenupanel["CData"][Name]:SetText(Title or "") - acfmenupanel["CData"][Name]:SetDark(true) - acfmenupanel["CData"][Name]:SizeToContents() - - if acfmenupanel.AmmoData[Name] ~= nil then - acfmenupanel["CData"][Name]:SetChecked(acfmenupanel.AmmoData[Name]) - else - acfmenupanel.AmmoData[Name] = false - end - - acfmenupanel["CData"][Name].OnChange = function(_, bval) - acfmenupanel.AmmoData[Name] = bval - self:UpdateAttribs({Name, bval}) - end - - acfmenupanel.CustomDisplay:AddItem(acfmenupanel["CData"][Name]) - end - - acfmenupanel["CData"][Name]:SetText(Title) - - if not acfmenupanel["CData"][Name .. "_text"] and Desc then - acfmenupanel["CData"][Name .. "_text"] = vgui.Create("DLabel") - acfmenupanel["CData"][Name .. "_text"]:SetText(Desc or "") - acfmenupanel["CData"][Name .. "_text"]:SetDark(true) - acfmenupanel.CustomDisplay:AddItem(acfmenupanel["CData"][Name .. "_text"]) - end - - acfmenupanel["CData"][Name .. "_text"]:SetText(Desc) - acfmenupanel["CData"][Name .. "_text"]:SetSize(acfmenupanel.CustomDisplay:GetWide(), 10) - acfmenupanel["CData"][Name .. "_text"]:SizeToContentsX() -end - --- DELETE -function PANEL:CPanelText(Name, Desc) - if not acfmenupanel["CData"][Name .. "_text"] then - acfmenupanel["CData"][Name .. "_text"] = vgui.Create("DLabel") - acfmenupanel["CData"][Name .. "_text"]:SetText(Desc or "") - acfmenupanel["CData"][Name .. "_text"]:SetDark(true) - acfmenupanel["CData"][Name .. "_text"]:SetWrap(true) - acfmenupanel["CData"][Name .. "_text"]:SetAutoStretchVertical(true) - acfmenupanel.CustomDisplay:AddItem(acfmenupanel["CData"][Name .. "_text"]) - end - - acfmenupanel["CData"][Name .. "_text"]:SetText(Desc) - acfmenupanel["CData"][Name .. "_text"]:SetSize(acfmenupanel.CustomDisplay:GetWide(), 10) - acfmenupanel["CData"][Name .. "_text"]:SizeToContentsY() -end \ No newline at end of file diff --git a/lua/acf/server/ballistics.lua b/lua/acf/server/ballistics.lua index 4b14bcdad..e680bb628 100644 --- a/lua/acf/server/ballistics.lua +++ b/lua/acf/server/ballistics.lua @@ -294,7 +294,6 @@ function ACF.DoBulletsFlight(Index, Bullet) ACF.BulletClient(Index, Bullet, "Update", 1, FlightRes.HitPos) - --RoundData.endflight(Index, Bullet, FlightRes.HitPos, FlightRes.HitNormal) RoundData:OnFlightEnd(Index, Bullet, FlightRes.HitPos, FlightRes.HitNormal) end elseif FlightRes.HitWorld then diff --git a/lua/acf/shared/acfcratelist.lua b/lua/acf/shared/acfcratelist.lua deleted file mode 100644 index 9240d452d..000000000 --- a/lua/acf/shared/acfcratelist.lua +++ /dev/null @@ -1,399 +0,0 @@ -local AmmoTable = {} --Start ammo containers listing - -AmmoTable["AmmoSmall"] = { - id = "AmmoSmall", - ent = "acf_ammo", - type = "Ammo", - name = "Small Ammo Crate", - desc = "Small ammo crate\n", - model = "models/ammocrate_small.mdl", - Size = Vector(20.44, 7.93, 13.77), - Offset = Vector(-0.36, -0.01, 7.01) -} - -AmmoTable["AmmoMedCube"] = { - id = "AmmoMedCube", - ent = "acf_ammo", - type = "Ammo", - name = "Medium cubic ammo crate", - desc = "Medium cubic ammo crate\n", - model = "models/ammocrate_medium_small.mdl", - Size = Vector(26.27, 25.9, 26.3), - Offset = Vector(-0.03, 0.42, 13.1) -} - -AmmoTable["AmmoMedium"] = { - id = "AmmoMedium", - ent = "acf_ammo", - type = "Ammo", - name = "Medium Ammo Crate", - desc = "Medium ammo crate\n", - model = "models/ammocrate_medium.mdl", - Size = Vector(51.9, 26.27, 25.9), - Offset = Vector(-0.12, 0.42, 13.1) -} - -AmmoTable["AmmoLarge"] = { - id = "AmmoLarge", - ent = "acf_ammo", - type = "Ammo", - name = "Large Ammo Crate", - desc = "Large ammo crate\n", - model = "models/ammocrate_large.mdl", - Size = Vector(52.17, 52.06, 51.92), - Offset = Vector(-0.05, -0.38, 26.06) -} - -AmmoTable["Ammo1x1x8"] = { - id = "Ammo1x1x8", - ent = "acf_ammo", - type = "Ammo", - name = "Modular Ammo Crate", - desc = "Modular Ammo Crate 1x1x8 Size\n", - model = "models/ammocrates/ammo_1x1x8.mdl", - Size = Vector(11.09, 89.15, 11.13), - Offset = Vector(0, -0.02, -0.12) -} - -AmmoTable["Ammo1x1x6"] = { - id = "Ammo1x1x6", - ent = "acf_ammo", - type = "Ammo", - name = "Modular Ammo Crate", - desc = "Modular Ammo Crate 1x1x6 Size\n", - model = "models/ammocrates/ammo_1x1x6.mdl", - Size = Vector(11.2, 66.51, 11.14), - Offset = Vector(0, 0.02, -0.14) -} - -AmmoTable["Ammo1x1x4"] = { - id = "Ammo1x1x4", - ent = "acf_ammo", - type = "Ammo", - name = "Modular Ammo Crate", - desc = "Modular Ammo Crate 1x1x4 Size\n", - model = "models/ammocrates/ammo_1x1x4.mdl", - Size = Vector(11.16, 45.06, 11.11), - Offset = Vector(0, 0.16, -0.17) -} - -AmmoTable["Ammo1x1x2"] = { - id = "Ammo1x1x2", - ent = "acf_ammo", - type = "Ammo", - name = "Modular Ammo Crate", - desc = "Modular Ammo Crate 1x1x2 Size\n", - model = "models/ammocrates/ammo_1x1x2.mdl", - Size = Vector(11.16, 22.43, 11.11), - Offset = Vector(0, 0.05, -0.17) -} - -AmmoTable["Ammo2x2x1"] = { - id = "Ammo2x2x1", - ent = "acf_ammo", - type = "Ammo", - name = "Modular Ammo Crate", - desc = "Modular Ammo Crate 2x2x1 Size\n", - model = "models/ammocrates/ammocrate_2x2x1.mdl", - Size = Vector(20.06, 8.06, 20.06), - Offset = Vector(-0.52, 0, 10.19) -} - -AmmoTable["Ammo2x2x2"] = { - id = "Ammo2x2x2", - ent = "acf_ammo", - type = "Ammo", - name = "Modular Ammo Crate", - desc = "Modular Ammo Crate 2x2x2 Size\n", - model = "models/ammocrates/ammocrate_2x2x2.mdl", - Size = Vector(20.06, 20.06, 20.06), - Offset = Vector(-0.09, 0.51, 10.51) -} - -AmmoTable["Ammo2x2x4"] = { - id = "Ammo2x2x4", - ent = "acf_ammo", - type = "Ammo", - name = "Modular Ammo Crate", - desc = "Modular Ammo Crate 2x2x4 Size\n", - model = "models/ammocrates/ammocrate_2x2x4.mdl", - Size = Vector(20.06, 45.06, 20.06), - Offset = Vector(-0.71, 0, 10.18) -} - -AmmoTable["Ammo2x2x6"] = { - id = "Ammo2x2x6", - ent = "acf_ammo", - type = "Ammo", - name = "Modular Ammo Crate", - desc = "Modular Ammo Crate 2x2x6 Size\n", - model = "models/ammocrates/ammo_2x2x6.mdl", - Size = Vector(22.45, 66.59, 22.33), - Offset = Vector(0, 0, -0.1) -} - -AmmoTable["Ammo2x2x8"] = { - id = "Ammo2x2x8", - ent = "acf_ammo", - type = "Ammo", - name = "Modular Ammo Crate", - desc = "Modular Ammo Crate 2x2x8 Size\n", - model = "models/ammocrates/ammo_2x2x8.mdl", - Size = Vector(22.46, 90.1, 22.82), - Offset = Vector(0, 0, -0.14) -} - -AmmoTable["Ammo2x3x1"] = { - id = "Ammo2x3x1", - ent = "acf_ammo", - type = "Ammo", - name = "Modular Ammo Crate", - desc = "Modular Ammo Crate 2x3x1 Size\n", - model = "models/ammocrates/ammocrate_2x3x1.mdl", - Size = Vector(32.06, 8.06, 20.06), - Offset = Vector(-0.64, 0, 10.19) -} - -AmmoTable["Ammo2x3x2"] = { - id = "Ammo2x3x2", - ent = "acf_ammo", - type = "Ammo", - name = "Modular Ammo Crate", - desc = "Modular Ammo Crate 2x3x2 Size\n", - model = "models/ammocrates/ammocrate_2x3x2.mdl", - Size = Vector(32.06, 20.06, 20.06), - Offset = Vector(-0.64, 0, 10.19) -} - -AmmoTable["Ammo2x3x4"] = { - id = "Ammo2x3x4", - ent = "acf_ammo", - type = "Ammo", - name = "Modular Ammo Crate", - desc = "Modular Ammo Crate 2x3x4 Size\n", - model = "models/ammocrates/ammocrate_2x3x4.mdl", - Size = Vector(32.06, 45.06, 20.06), - Offset = Vector(-0.79, 0, 10) -} - -AmmoTable["Ammo2x3x6"] = { - id = "Ammo2x3x6", - ent = "acf_ammo", - type = "Ammo", - name = "Modular Ammo Crate", - desc = "Modular Ammo Crate 2x3x6 Size\n", - model = "models/ammocrates/ammocrate_2x3x6.mdl", - Size = Vector(31.94, 68.04, 20.1), - Offset = Vector(-0.79, -0.04, 10.02) -} - -AmmoTable["Ammo2x3x8"] = { - id = "Ammo2x3x8", - ent = "acf_ammo", - type = "Ammo", - name = "Modular Ammo Crate", - desc = "Modular Ammo Crate 2x3x8 Size\n", - model = "models/ammocrates/ammocrate_2x3x8.mdl", - Size = Vector(31.94, 90.1, 20.1), - Offset = Vector(-0.79, 0, 10.02) -} - -AmmoTable["Ammo2x4x1"] = { - id = "Ammo2x4x1", - ent = "acf_ammo", - type = "Ammo", - name = "Modular Ammo Crate", - desc = "Modular Ammo Crate 2x4x1 Size\n", - model = "models/ammocrates/ammocrate_2x4x1.mdl", - Size = Vector(45.06, 8.06, 20.06), - Offset = Vector(-0.64, 0, 10.19) -} - -AmmoTable["Ammo2x4x2"] = { - id = "Ammo2x4x2", - ent = "acf_ammo", - type = "Ammo", - name = "Modular Ammo Crate", - desc = "Modular Ammo Crate 2x4x2 Size\n", - model = "models/ammocrates/ammocrate_2x4x2.mdl", - Size = Vector(45.06, 20.06, 20.06), - Offset = Vector(-0.2, 0.71, 10.18) -} - -AmmoTable["Ammo2x4x4"] = { - id = "Ammo2x4x4", - ent = "acf_ammo", - type = "Ammo", - name = "Modular Ammo Crate", - desc = "Modular Ammo Crate 2x4x4 Size\n", - model = "models/ammocrates/ammocrate_2x4x4.mdl", - Size = Vector(45.06, 45.06, 20.06), - Offset = Vector(-0.79, 0, 10) -} - -AmmoTable["Ammo2x4x6"] = { - id = "Ammo2x4x6", - ent = "acf_ammo", - type = "Ammo", - name = "Modular Ammo Crate", - desc = "Modular Ammo Crate 2x4x6 Size\n", - model = "models/ammocrates/ammocrate_2x4x6.mdl", - Size = Vector(45.06, 68.06, 20.06), - Offset = Vector(-0.79, 0, 10) -} - -AmmoTable["Ammo2x4x8"] = { - id = "Ammo2x4x8", - ent = "acf_ammo", - type = "Ammo", - name = "Modular Ammo Crate", - desc = "Modular Ammo Crate 2x4x8 Size\n", - model = "models/ammocrates/ammocrate_2x4x8.mdl", - Size = Vector(45.06, 90.06, 20.06), - Offset = Vector(-0.79, 0, 10) -} - -AmmoTable["Ammo3x4x1"] = { - id = "Ammo3x4x1", - ent = "acf_ammo", - type = "Ammo", - name = "Modular Ammo Crate", - desc = "Modular Ammo Crate 3x4x1 Size\n", - model = "models/ammocrates/ammocrate_3x4x1.mdl", - Size = Vector(45.06, 8.06, 32.06), - Offset = Vector(-0.64, 0, 16.25) -} - -AmmoTable["Ammo3x4x2"] = { - id = "Ammo3x4x2", - ent = "acf_ammo", - type = "Ammo", - name = "Modular Ammo Crate", - desc = "Modular Ammo Crate 3x4x2 Size\n", - model = "models/ammocrates/ammocrate_3x4x2.mdl", - Size = Vector(45.06, 20.06, 32.06), - Offset = Vector(-0.2, 0.71, 16.26) -} - -AmmoTable["Ammo3x4x4"] = { - id = "Ammo3x4x4", - ent = "acf_ammo", - type = "Ammo", - name = "Modular Ammo Crate", - desc = "Modular Ammo Crate 3x4x4 Size\n", - model = "models/ammocrates/ammocrate_3x4x4.mdl", - Size = Vector(45.06, 45.06, 32.06), - Offset = Vector(-0.79, 0, 16) -} - -AmmoTable["Ammo3x4x6"] = { - id = "Ammo3x4x6", - ent = "acf_ammo", - type = "Ammo", - name = "Modular Ammo Crate", - desc = "Modular Ammo Crate 3x4x6 Size\n", - model = "models/ammocrates/ammocrate_3x4x6.mdl", - Size = Vector(45.06, 68.06, 32.06), - Offset = Vector(-0.79, 0, 16) -} - -AmmoTable["Ammo3x4x8"] = { - id = "Ammo3x4x8", - ent = "acf_ammo", - type = "Ammo", - name = "Modular Ammo Crate", - desc = "Modular Ammo Crate 3x4x8 Size\n", - model = "models/ammocrates/ammocrate_3x4x8.mdl", - Size = Vector(45.06, 90.06, 32.06), - Offset = Vector(0.15, 0, 16) -} - -AmmoTable["Ammo4x4x1"] = { - id = "Ammo4x4x1", - ent = "acf_ammo", - type = "Ammo", - name = "Modular Ammo Crate", - desc = "Modular Ammo Crate 4x4x1 Size\n", - model = "models/ammocrates/ammo_4x4x1.mdl", - Size = Vector(45.06, 45.06, 11.51), - Offset = Vector(0, 0, -0.06) -} - -AmmoTable["Ammo4x4x2"] = { - id = "Ammo4x4x2", - ent = "acf_ammo", - type = "Ammo", - name = "Modular Ammo Crate", - desc = "Modular Ammo Crate 4x4x2 Size\n", - model = "models/ammocrates/ammocrate_4x4x2.mdl", - Size = Vector(45.06, 20.06, 45.06), - Offset = Vector(-0.14, 0.71, 22.5) -} - -AmmoTable["Ammo4x4x4"] = { - id = "Ammo4x4x4", - ent = "acf_ammo", - type = "Ammo", - name = "Modular Ammo Crate", - desc = "Modular Ammo Crate 4x4x4 Size\n", - model = "models/ammocrates/ammocrate_4x4x4.mdl", - Size = Vector(45.06, 45.06, 45.06), - Offset = Vector(0.15, 0, 22.5) -} - -AmmoTable["Ammo4x4x6"] = { - id = "Ammo4x4x6", - ent = "acf_ammo", - type = "Ammo", - name = "Modular Ammo Crate", - desc = "Modular Ammo Crate 4x4x6 Size\n", - model = "models/ammocrates/ammocrate_4x4x6.mdl", - Size = Vector(45.06, 68.06, 45.06), - Offset = Vector(0.15, 0.06, 22.5) -} - -AmmoTable["Ammo4x4x8"] = { - id = "Ammo4x4x8", - ent = "acf_ammo", - type = "Ammo", - name = "Modular Ammo Crate", - desc = "Modular Ammo Crate 4x4x8 Size\n", - model = "models/ammocrates/ammocrate_4x4x8.mdl", - Size = Vector(45.06, 90.06, 45.06), - Offset = Vector(0.15, -0.01, 22.5) -} - -AmmoTable["Ammo4x6x8"] = { - id = "Ammo4x6x8", - ent = "acf_ammo", - type = "Ammo", - name = "Modular Ammo Crate", - desc = "Modular Ammo Crate 4x6x8 Size\n", - model = "models/ammocrates/ammo_4x6x8.mdl", - Size = Vector(67.56, 89.98, 44.99), - Offset = Vector(0, 0, -0.07) -} - -AmmoTable["Ammo4x6x6"] = { - id = "Ammo4x6x6", - ent = "acf_ammo", - type = "Ammo", - name = "Modular Ammo Crate", - desc = "Modular Ammo Crate 4x6x6 Size\n", - model = "models/ammocrates/ammo_4x6x6.mdl", - Size = Vector(67.56, 67.35, 45), - Offset = Vector(0, 0, -0.02) -} - -AmmoTable["Ammo4x8x8"] = { - id = "Ammo4x8x8", - ent = "acf_ammo", - type = "Ammo", - name = "Modular Ammo Crate", - desc = "Modular Ammo Crate 4x8x8 Size\n", - model = "models/ammocrates/ammo_4x8x8.mdl", - Size = Vector(90.21, 90.13, 45.19), - Offset = Vector(0, 0, -0.15) -} - -ACF.Weapons.Ammo = AmmoTable --end ammo containers listing diff --git a/lua/acf/shared/ammo_types/fl.lua b/lua/acf/shared/ammo_types/fl.lua index a10026e04..895e7fe22 100644 --- a/lua/acf/shared/ammo_types/fl.lua +++ b/lua/acf/shared/ammo_types/fl.lua @@ -61,18 +61,8 @@ end function Ammo:BaseConvert(ToolData) local Data, GUIData = ACF.RoundBaseGunpowder(ToolData, { LengthAdj = 0.5 }) - local GunClass = ToolData.WeaponClass - - if GunClass == "SA" then - Data.MaxFlechettes = math.Clamp(math.floor(Data.Caliber * 3 - 4.5), 1, 32) - elseif GunClass == "MO" then - Data.MaxFlechettes = math.Clamp(math.floor(Data.Caliber * 4) - 12, 1, 32) - elseif GunClass == "HW" then - Data.MaxFlechettes = math.Clamp(math.floor(Data.Caliber * 4) - 10, 1, 32) - else - Data.MaxFlechettes = math.Clamp(math.floor(Data.Caliber * 4) - 8, 1, 32) - end + Data.MaxFlechettes = math.Clamp(math.floor(Data.Caliber * 4) - 8, 1, 32) Data.MinFlechettes = math.min(6, Data.MaxFlechettes) --force bigger guns to have higher min count Data.MinSpread = 0.25 Data.MaxSpread = 30 @@ -178,16 +168,11 @@ if SERVER then end function Ammo:GetCrateText(BulletData) - local Text = "Muzzle Velocity: %s m/s\nMax Penetration: %s mm\nMax Spread: %s degrees" - local Data = self:GetDisplayData(BulletData) - local Gun = ACF.Weapons.Guns[BulletData.Id] - local Spread = 0 - - if Gun then - local GunClass = ACF.Classes.GunClass[Gun.gunclass] -- REPLACE - - Spread = GunClass and (GunClass.spread * ACF.GunInaccuracyScale) or 0 - end + local Text = "Muzzle Velocity: %s m/s\nMax Penetration: %s mm\nMax Spread: %s degrees" + local Data = self:GetDisplayData(BulletData) + local Destiny = ACF.FindWeaponrySource(BulletData.Id) + local Class = ACF.GetClassGroup(Destiny, BulletData.Id) + local Spread = Class.Spread * ACF.GunInaccuracyScale return Text:format(math.Round(BulletData.MuzzleVel, 2), math.Round(Data.MaxPen, 2), math.Round(BulletData.FlechetteSpread + Spread, 2)) end diff --git a/lua/acf/shared/engines/b4.lua b/lua/acf/shared/engines/b4.lua index edc11896e..36acf5bc0 100644 --- a/lua/acf/shared/engines/b4.lua +++ b/lua/acf/shared/engines/b4.lua @@ -1,74 +1,6 @@ -- Flat 4 engines -ACF_DefineEngine( "1.4-B4", { - name = "1.4L Flat 4 Petrol", - desc = "Small air cooled flat four, most commonly found in nazi insects", - model = "models/engines/b4small.mdl", - sound = "acf_base/engines/b4_petrolsmall.wav", - category = "B4", - fuel = "Petrol", - enginetype = "GenericPetrol", - weight = 60, - torque = 131, - flywheelmass = 0.06, - idlerpm = 600, - peakminrpm = 2600, - peakmaxrpm = 4200, - limitrpm = 4500 -} ) - -ACF_DefineEngine( "2.1-B4", { - name = "2.1L Flat 4 Petrol", - desc = "Tuned up flat four, probably find this in things that go fast in a desert.", - model = "models/engines/b4small.mdl", - sound = "acf_base/engines/b4_petrolmedium.wav", - category = "B4", - fuel = "Petrol", - enginetype = "GenericPetrol", - weight = 125, - torque = 225, - flywheelmass = 0.15, - idlerpm = 700, - peakminrpm = 3000, - peakmaxrpm = 4800, - limitrpm = 5000 -} ) - -ACF_DefineEngine( "3.2-B4", { - name = "3.2L Flat 4 Petrol", - desc = "Bored out fuckswindleton batshit flat four. Fuck yourself.", - model = "models/engines/b4med.mdl", - sound = "acf_base/engines/b4_petrollarge.wav", - category = "B4", - fuel = "Petrol", - enginetype = "GenericPetrol", - weight = 210, - torque = 315, - flywheelmass = 0.15, - idlerpm = 900, - peakminrpm = 3400, - peakmaxrpm = 5500, - limitrpm = 6500 -} ) - -ACF_DefineEngine( "2.4-B4", { - name = "2.4L Flat 4 Multifuel", - desc = "Tiny military-grade multifuel. Heavy, but grunts hard.", - model = "models/engines/b4small.mdl", - sound = "acf_extra/vehiclefx/engines/coh/ba11.wav", - category = "B4", - fuel = "Multifuel", - enginetype = "GenericDiesel", - weight = 135, - torque = 310, - flywheelmass = 0.4, - idlerpm = 550, - peakminrpm = 1250, - peakmaxrpm = 2650, - limitrpm = 2800 -} ) - ACF.RegisterEngineClass("B4", { Name = "Flat 4 Engine", }) diff --git a/lua/acf/shared/engines/b6.lua b/lua/acf/shared/engines/b6.lua index 969fc47ef..14033107f 100644 --- a/lua/acf/shared/engines/b6.lua +++ b/lua/acf/shared/engines/b6.lua @@ -1,75 +1,6 @@ -- Flat 6 engines -ACF_DefineEngine( "2.8-B6", { - name = "2.8L Flat 6 Petrol", - desc = "Car sized flat six engine, sporty and light", - model = "models/engines/b6small.mdl", - sound = "acf_base/engines/b6_petrolsmall.wav", - category = "B6", - fuel = "Petrol", - enginetype = "GenericPetrol", - weight = 100, - torque = 170, - flywheelmass = 0.08, - idlerpm = 750, - peakminrpm = 4300, - peakmaxrpm = 6950, - limitrpm = 7250 -} ) - -ACF_DefineEngine( "5.0-B6", { - name = "5.0L Flat 6 Petrol", - desc = "Sports car grade flat six, renown for their smooth operation and light weight", - model = "models/engines/b6med.mdl", - sound = "acf_base/engines/b6_petrolmedium.wav", - category = "B6", - fuel = "Petrol", - enginetype = "GenericPetrol", - weight = 240, - torque = 412, - flywheelmass = 0.11, - idlerpm = 900, - peakminrpm = 3500, - peakmaxrpm = 6000, - limitrpm = 6800 -} ) - -ACF_DefineEngine( "8.3-B6", { - name = "8.3L Flat 6 Multifuel", - desc = "Military-grade multifuel boxer engine. Although heavy, it is compact, durable, and has excellent performance under adverse conditions.", - model = "models/engines/b6med.mdl", - sound = "acf_base/engines/v8_diesel.wav", - category = "B6", - fuel = "Multifuel", - enginetype = "GenericDiesel", - weight = 480, - torque = 706, - flywheelmass = 0.65, - idlerpm = 500, - peakminrpm = 1900, - peakmaxrpm = 3600, - limitrpm = 4200 -} ) - - -ACF_DefineEngine( "15.8-B6", { - name = "15.8L Flat 6 Petrol", - desc = "Monstrous aircraft-grade boxer with a high rev range biased powerband", - model = "models/engines/b6large.mdl", - sound = "acf_base/engines/b6_petrollarge.wav", - category = "B6", - fuel = "Petrol", - enginetype = "GenericPetrol", - weight = 725, - torque = 1375, - flywheelmass = 1, - idlerpm = 620, - peakminrpm = 2500, - peakmaxrpm = 4275, - limitrpm = 4900 -} ) - ACF.RegisterEngineClass("B6", { Name = "Flat 6 Engine", }) diff --git a/lua/acf/shared/engines/electric.lua b/lua/acf/shared/engines/electric.lua index 3168445d4..e5df57765 100644 --- a/lua/acf/shared/engines/electric.lua +++ b/lua/acf/shared/engines/electric.lua @@ -1,139 +1,6 @@ -- Electric motors -ACF_DefineEngine( "Electric-Small", { - name = "Electric motor, Small", - desc = "A small electric motor, loads of torque, but low power\n\nElectric motors provide huge amounts of torque, but are very heavy", - model = "models/engines/emotorsmall.mdl", - sound = "acf_base/engines/electric_small.wav", - category = "Electric", - fuel = "Electric", - enginetype = "Electric", - weight = 250, - torque = 480, - flywheelmass = 0.3, - idlerpm = 10, - peakminrpm = 1, - peakmaxrpm = 1, - limitrpm = 10000, - iselec = true, - flywheeloverride = 5000 -} ) - -ACF_DefineEngine( "Electric-Medium", { - name = "Electric motor, Medium", - desc = "A medium electric motor, loads of torque, but low power\n\nElectric motors provide huge amounts of torque, but are very heavy", - model = "models/engines/emotormed.mdl", - sound = "acf_base/engines/electric_medium.wav", - category = "Electric", - fuel = "Electric", - enginetype = "Electric", - weight = 850, - torque = 1440, - flywheelmass = 1.5, - idlerpm = 10, - peakminrpm = 1, - peakmaxrpm = 1, - limitrpm = 7000, - iselec = true, - flywheeloverride = 8000 -} ) - -ACF_DefineEngine( "Electric-Large", { - name = "Electric motor, Large", - desc = "A huge electric motor, loads of torque, but low power\n\nElectric motors provide huge amounts of torque, but are very heavy", - model = "models/engines/emotorlarge.mdl", - sound = "acf_base/engines/electric_large.wav", - category = "Electric", - fuel = "Electric", - enginetype = "Electric", - weight = 1900, - torque = 4200, - flywheelmass = 11.2, - idlerpm = 10, - peakminrpm = 1, - peakmaxrpm = 1, - limitrpm = 4500, - iselec = true, - flywheeloverride = 6000 -} ) - -ACF_DefineEngine( "Electric-Tiny-NoBatt", { - name = "Electric motor, Tiny, Standalone", - desc = "A pint-size electric motor, for the lightest of light utility work. Can power electric razors, desk fans, or your hopes and dreams\n\nElectric motors provide huge amounts of torque, but are very heavy.\n\nStandalone electric motors don't have integrated batteries, saving on weight and volume, but require you to supply your own batteries.", - model = "models/engines/emotor-standalone-tiny.mdl", - sound = "acf_base/engines/electric_small.wav", - category = "Electric", - fuel = "Electric", - enginetype = "Electric", - weight = 50, --250 - torque = 40, - flywheelmass = 0.025, - idlerpm = 10, - peakminrpm = 1, - peakmaxrpm = 1, - limitrpm = 10000, - iselec = true, - flywheeloverride = 500 -} ) - -ACF_DefineEngine( "Electric-Small-NoBatt", { - name = "Electric motor, Small, Standalone", - desc = "A small electric motor, loads of torque, but low power\n\nElectric motors provide huge amounts of torque, but are very heavy.\n\nStandalone electric motors don't have integrated batteries, saving on weight and volume, but require you to supply your own batteries.", - model = "models/engines/emotor-standalone-sml.mdl", - sound = "acf_base/engines/electric_small.wav", - category = "Electric", - fuel = "Electric", - enginetype = "Electric", - weight = 125, --250 - torque = 384, - flywheelmass = 0.3, - idlerpm = 10, - peakminrpm = 1, - peakmaxrpm = 1, - limitrpm = 10000, - iselec = true, - flywheeloverride = 5000 -} ) - -ACF_DefineEngine( "Electric-Medium-NoBatt", { - name = "Electric motor, Medium, Standalone", - desc = "A medium electric motor, loads of torque, but low power\n\nElectric motors provide huge amounts of torque, but are very heavy.\n\nStandalone electric motors don't have integrated batteries, saving on weight and volume, but require you to supply your own batteries.", - model = "models/engines/emotor-standalone-mid.mdl", - sound = "acf_base/engines/electric_medium.wav", - category = "Electric", - fuel = "Electric", - enginetype = "Electric", - weight = 575, --800 - torque = 1152, - flywheelmass = 1.5, - idlerpm = 10, - peakminrpm = 1, - peakmaxrpm = 1, - limitrpm = 7000, - iselec = true, - flywheeloverride = 8000 -} ) - -ACF_DefineEngine( "Electric-Large-NoBatt", { - name = "Electric motor, Large, Standalone", - desc = "A huge electric motor, loads of torque, but low power\n\nElectric motors provide huge amounts of torque, but are very heavy.\n\nStandalone electric motors don't have integrated batteries, saving on weight and volume, but require you to supply your own batteries.", - model = "models/engines/emotor-standalone-big.mdl", - sound = "acf_base/engines/electric_large.wav", - category = "Electric", - fuel = "Electric", - enginetype = "Electric", - weight = 1500, --1900 - torque = 3360, - flywheelmass = 11.2, - idlerpm = 10, - peakminrpm = 1, - peakmaxrpm = 1, - limitrpm = 4500, - iselec = true, - flywheeloverride = 6000 -} ) - do -- Electric Motors ACF.RegisterEngineClass("EL", { Name = "Electric Motor", diff --git a/lua/acf/shared/engines/i2.lua b/lua/acf/shared/engines/i2.lua index 7f44cb103..4c754c7c9 100644 --- a/lua/acf/shared/engines/i2.lua +++ b/lua/acf/shared/engines/i2.lua @@ -1,42 +1,6 @@ -- Inline 2 engines -ACF_DefineEngine( "0.8L-I2", { - name = "0.8L I2 Diesel", - desc = "For when a 3 banger is still too bulky for your micro-needs", - model = "models/engines/inline2s.mdl", - sound = "acf_base/engines/i4_diesel2.wav", - category = "I2", - fuel = "Diesel", - enginetype = "GenericDiesel", - weight = 45, - torque = 131, - flywheelmass = 0.12, - idlerpm = 500, - peakminrpm = 750, - peakmaxrpm = 2450, - limitrpm = 2950 -} ) - - - -ACF_DefineEngine( "10.0-I2", { - name = "10.0L I2 Diesel", - desc = "TORQUE.", - model = "models/engines/inline2b.mdl", - sound = "acf_base/engines/vtwin_large.wav", - category = "I2", - fuel = "Diesel", - enginetype = "GenericDiesel", - weight = 800, - torque = 2500, - flywheelmass = 7, - idlerpm = 350, - peakminrpm = 450, - peakmaxrpm = 900, - limitrpm = 1200 -} ) - ACF.RegisterEngineClass("I2", { Name = "Inline 2 Engine", }) diff --git a/lua/acf/shared/engines/i3.lua b/lua/acf/shared/engines/i3.lua index 921a9c0c0..5bde7973a 100644 --- a/lua/acf/shared/engines/i3.lua +++ b/lua/acf/shared/engines/i3.lua @@ -1,112 +1,6 @@ -- Inline 3 engines --- Petrol - -ACF_DefineEngine( "1.2-I3", { - name = "1.2L I3 Petrol", - desc = "Tiny microcar engine, efficient but weak", - model = "models/engines/inline3s.mdl", - sound = "acf_base/engines/i4_petrolsmall2.wav", - category = "I3", - fuel = "Petrol", - enginetype = "GenericPetrol", - weight = 40, - torque = 118, - flywheelmass = 0.05, - idlerpm = 1100, - peakminrpm = 3300, - peakmaxrpm = 5400, - limitrpm = 6000 -} ) - -ACF_DefineEngine( "3.4-I3", { - name = "3.4L I3 Petrol", - desc = "Short block engine for light utility use", - model = "models/engines/inline3m.mdl", - sound = "acf_base/engines/i4_petrolmedium2.wav", - category = "I3", - fuel = "Petrol", - enginetype = "GenericPetrol", - weight = 170, - torque = 243, - flywheelmass = 0.2, - idlerpm = 900, - peakminrpm = 3500, - peakmaxrpm = 6600, - limitrpm = 6800 -} ) - -ACF_DefineEngine( "13.5-I3", { - name = "13.5L I3 Petrol", - desc = "Short block light tank engine, likes sideways mountings", - model = "models/engines/inline3b.mdl", - sound = "acf_base/engines/i4_petrollarge.wav", - category = "I3", - fuel = "Petrol", - enginetype = "GenericPetrol", - weight = 500, - torque = 893, - flywheelmass = 3.7, - idlerpm = 500, - peakminrpm = 1900, - peakmaxrpm = 3500, - limitrpm = 3900 -} ) - --- Diesel - -ACF_DefineEngine( "1.1-I3", { - name = "1.1L I3 Diesel", - desc = "ATV grade 3-banger, enormous rev band but a choppy idle, great for light utility work", - model = "models/engines/inline3s.mdl", - sound = "acf_base/engines/i4_diesel2.wav", - category = "I3", - fuel = "Diesel", - enginetype = "GenericDiesel", - weight = 65, - torque = 187, - flywheelmass = 0.2, - idlerpm = 550, - peakminrpm = 800, - peakmaxrpm = 2500, - limitrpm = 3000 -} ) - -ACF_DefineEngine( "2.8-I3", { - name = "2.8L I3 Diesel", - desc = "Medium utility grade I3 diesel, for tractors", - model = "models/engines/inline3m.mdl", - sound = "acf_base/engines/i4_dieselmedium.wav", - category = "I3", - fuel = "Diesel", - enginetype = "GenericDiesel", - weight = 200, - torque = 362, - flywheelmass = 1, - idlerpm = 600, - peakminrpm = 1200, - peakmaxrpm = 3600, - limitrpm = 3800 -} ) - -ACF_DefineEngine( "11.0-I3", { - name = "11.0L I3 Diesel", - desc = "Light tank duty engine, compact yet grunts hard", - model = "models/engines/inline3b.mdl", - sound = "acf_base/engines/i4_diesellarge.wav", - category = "I3", - fuel = "Diesel", - enginetype = "GenericDiesel", - weight = 650, - torque = 1500, - flywheelmass = 5, - idlerpm = 550, - peakminrpm = 650, - peakmaxrpm = 1800, - limitrpm = 2000 -} ) - ACF.RegisterEngineClass("I3", { Name = "Inline 3 Engine", }) diff --git a/lua/acf/shared/engines/i4.lua b/lua/acf/shared/engines/i4.lua index 88fe25b0b..541e29edb 100644 --- a/lua/acf/shared/engines/i4.lua +++ b/lua/acf/shared/engines/i4.lua @@ -1,112 +1,6 @@ -- Inline 4 engines --- Petrol - -ACF_DefineEngine( "1.5-I4", { - name = "1.5L I4 Petrol", - desc = "Small car engine, not a whole lot of git", - model = "models/engines/inline4s.mdl", - sound = "acf_base/engines/i4_petrolsmall2.wav", - category = "I4", - fuel = "Petrol", - enginetype = "GenericPetrol", - weight = 50, - torque = 112, - flywheelmass = 0.06, - idlerpm = 900, - peakminrpm = 4000, - peakmaxrpm = 6500, - limitrpm = 7500 -} ) - -ACF_DefineEngine( "3.7-I4", { - name = "3.7L I4 Petrol", - desc = "Large inline 4, sees most use in light trucks", - model = "models/engines/inline4m.mdl", - sound = "acf_base/engines/i4_petrolmedium2.wav", - category = "I4", - fuel = "Petrol", - enginetype = "GenericPetrol", - weight = 200, - torque = 300, - flywheelmass = 0.2, - idlerpm = 900, - peakminrpm = 3700, - peakmaxrpm = 6000, - limitrpm = 6500 -} ) - -ACF_DefineEngine( "16.0-I4", { - name = "16.0L I4 Petrol", - desc = "Giant, thirsty I4 petrol, most commonly used in boats", - model = "models/engines/inline4l.mdl", - sound = "acf_base/engines/i4_petrollarge.wav", - category = "I4", - fuel = "Petrol", - enginetype = "GenericPetrol", - weight = 600, - torque = 1062, - flywheelmass = 4, - idlerpm = 500, - peakminrpm = 1750, - peakmaxrpm = 3250, - limitrpm = 3500 -} ) - --- Diesel - -ACF_DefineEngine( "1.6-I4", { - name = "1.6L I4 Diesel", - desc = "Small and light diesel, for low power applications requiring a wide powerband", - model = "models/engines/inline4s.mdl", - sound = "acf_base/engines/i4_diesel2.wav", - category = "I4", - fuel = "Diesel", - enginetype = "GenericDiesel", - weight = 90, - torque = 187, - flywheelmass = 0.2, - idlerpm = 650, - peakminrpm = 1000, - peakmaxrpm = 3000, - limitrpm = 5000 -} ) - -ACF_DefineEngine( "3.1-I4", { - name = "3.1L I4 Diesel", - desc = "Light truck duty diesel, good overall grunt", - model = "models/engines/inline4m.mdl", - sound = "acf_base/engines/i4_dieselmedium.wav", - category = "I4", - fuel = "Diesel", - enginetype = "GenericDiesel", - weight = 250, - torque = 400, - flywheelmass = 1, - idlerpm = 500, - peakminrpm = 1150, - peakmaxrpm = 3500, - limitrpm = 4000 -} ) - -ACF_DefineEngine( "15.0-I4", { - name = "15.0L I4 Diesel", - desc = "Small boat sized diesel, with large amounts of torque", - model = "models/engines/inline4l.mdl", - sound = "acf_base/engines/i4_diesellarge.wav", - category = "I4", - fuel = "Diesel", - enginetype = "GenericDiesel", - weight = 800, - torque = 1750, - flywheelmass = 5, - idlerpm = 450, - peakminrpm = 500, - peakmaxrpm = 1800, - limitrpm = 2100 -} ) - ACF.RegisterEngineClass("I4", { Name = "Inline 4 Engine", }) diff --git a/lua/acf/shared/engines/i5.lua b/lua/acf/shared/engines/i5.lua index 75158ba2d..b8fa80a4c 100644 --- a/lua/acf/shared/engines/i5.lua +++ b/lua/acf/shared/engines/i5.lua @@ -1,78 +1,6 @@ -- Inline 5 engines --- Petrol - -ACF_DefineEngine( "2.3-I5", { - name = "2.3L I5 Petrol", - desc = "Sedan-grade 5-cylinder, solid and dependable", - model = "models/engines/inline5s.mdl", - sound = "acf_base/engines/i5_petrolsmall.wav", - category = "I5", - fuel = "Petrol", - enginetype = "GenericPetrol", - weight = 100, - torque = 156, - flywheelmass = 0.12, - idlerpm = 900, - peakminrpm = 3600, - peakmaxrpm = 5900, - limitrpm = 7000 -} ) - -ACF_DefineEngine( "3.9-I5", { - name = "3.9L I5 Petrol", - desc = "Truck sized inline 5, strong with a good balance of revs and torques", - model = "models/engines/inline5m.mdl", - sound = "acf_base/engines/i5_petrolmedium.wav", - category = "I5", - fuel = "Petrol", - enginetype = "GenericPetrol", - weight = 250, - torque = 343, - flywheelmass = 0.25, - idlerpm = 700, - peakminrpm = 3700, - peakmaxrpm = 6000, - limitrpm = 6500 -} ) - --- Diesel - -ACF_DefineEngine( "2.9-I5", { - name = "2.9L I5 Diesel", - desc = "Aging fuel-injected diesel, low in horsepower but very forgiving and durable", - model = "models/engines/inline5s.mdl", - sound = "acf_base/engines/i5_dieselsmall2.wav", - category = "I5", - fuel = "Diesel", - enginetype = "GenericDiesel", - weight = 130, - torque = 225, - flywheelmass = 0.5, - idlerpm = 500, - peakminrpm = 900, - peakmaxrpm = 2800, - limitrpm = 4200 -} ) - -ACF_DefineEngine( "4.1-I5", { - name = "4.1L I5 Diesel", - desc = "Heavier duty diesel, found in things that work hard", - model = "models/engines/inline5m.mdl", - sound = "acf_base/engines/i5_dieselmedium.wav", - category = "I5", - fuel = "Diesel", - enginetype = "GenericDiesel", - weight = 400, - torque = 550, - flywheelmass = 1.5, - idlerpm = 650, - peakminrpm = 1000, - peakmaxrpm = 3200, - limitrpm = 3800 -} ) - ACF.RegisterEngineClass("I5", { Name = "Inline 5 Engine", }) diff --git a/lua/acf/shared/engines/i6.lua b/lua/acf/shared/engines/i6.lua index ce91e652c..8a181b165 100644 --- a/lua/acf/shared/engines/i6.lua +++ b/lua/acf/shared/engines/i6.lua @@ -1,112 +1,6 @@ -- Inline 6 engines --- Petrol - -ACF_DefineEngine( "2.2-I6", { - name = "2.2L I6 Petrol", - desc = "Car sized I6 petrol with power in the high revs", - model = "models/engines/inline6s.mdl", - sound = "acf_base/engines/l6_petrolsmall2.wav", - category = "I6", - fuel = "Petrol", - enginetype = "GenericPetrol", - weight = 120, - torque = 162, - flywheelmass = 0.1, - idlerpm = 800, - peakminrpm = 4000, - peakmaxrpm = 6500, - limitrpm = 7200 -} ) - -ACF_DefineEngine( "4.8-I6", { - name = "4.8L I6 Petrol", - desc = "Light truck duty I6, good for offroad applications", - model = "models/engines/inline6m.mdl", - sound = "acf_base/engines/l6_petrolmedium.wav", - category = "I6", - fuel = "Petrol", - enginetype = "GenericPetrol", - weight = 300, - torque = 450, - flywheelmass = 0.2, - idlerpm = 900, - peakminrpm = 3100, - peakmaxrpm = 5000, - limitrpm = 5500 -} ) - -ACF_DefineEngine( "17.2-I6", { - name = "17.2L I6 Petrol", - desc = "Heavy tractor duty petrol I6, decent overall powerband", - model = "models/engines/inline6l.mdl", - sound = "acf_base/engines/l6_petrollarge2.wav", - category = "I6", - fuel = "Petrol", - enginetype = "GenericPetrol", - weight = 850, - torque = 1200, - flywheelmass = 2.5, - idlerpm = 800, - peakminrpm = 2000, - peakmaxrpm = 4000, - limitrpm = 4250 -} ) - --- Diesel - -ACF_DefineEngine( "3.0-I6", { - name = "3.0L I6 Diesel", - desc = "Car sized I6 diesel, good, wide powerband", - model = "models/engines/inline6s.mdl", - sound = "acf_base/engines/l6_dieselsmall.wav", - category = "I6", - fuel = "Diesel", - enginetype = "GenericDiesel", - weight = 150, - torque = 250, - flywheelmass = 0.5, - idlerpm = 650, - peakminrpm = 1000, - peakmaxrpm = 3000, - limitrpm = 4500 -} ) - -ACF_DefineEngine( "6.5-I6", { - name = "6.5L I6 Diesel", - desc = "Truck duty I6, good overall powerband and torque", - model = "models/engines/inline6m.mdl", - sound = "acf_base/engines/l6_dieselmedium4.wav", - category = "I6", - fuel = "Diesel", - enginetype = "GenericDiesel", - weight = 450, - torque = 650, - flywheelmass = 1.5, - idlerpm = 600, - peakminrpm = 1000, - peakmaxrpm = 3000, - limitrpm = 4000 -} ) - -ACF_DefineEngine( "20.0-I6", { - name = "20.0L I6 Diesel", - desc = "Heavy duty diesel I6, used in generators and heavy movers", - model = "models/engines/inline6l.mdl", - sound = "acf_base/engines/l6_diesellarge2.wav", - category = "I6", - fuel = "Diesel", - enginetype = "GenericDiesel", - weight = 1200, - torque = 2125, - flywheelmass = 8, - idlerpm = 400, - peakminrpm = 650, - peakmaxrpm = 2100, - limitrpm = 2600 -} ) - ACF.RegisterEngineClass("I6", { Name = "Inline 6 Engine", }) diff --git a/lua/acf/shared/engines/radial.lua b/lua/acf/shared/engines/radial.lua index 30156a78d..96f5d9ba7 100644 --- a/lua/acf/shared/engines/radial.lua +++ b/lua/acf/shared/engines/radial.lua @@ -1,75 +1,6 @@ -- Radial engines -ACF_DefineEngine( "3.8-R7", { - name = "3.8L R7 Petrol", - desc = "A tiny, old worn-out radial.", - model = "models/engines/radial7s.mdl", - sound = "acf_base/engines/r7_petrolsmall.wav", - category = "Radial", - fuel = "Petrol", - enginetype = "Radial", - weight = 210, - torque = 387, - flywheelmass = 0.22, - idlerpm = 700, - peakminrpm = 2600, - peakmaxrpm = 4350, - limitrpm = 4800 -} ) - -ACF_DefineEngine( "11.0-R7", { - name = "11.0 R7 Petrol", - desc = "Mid range radial, thirsty and smooth", - model = "models/engines/radial7m.mdl", - sound = "acf_base/engines/r7_petrolmedium.wav", - category = "Radial", - fuel = "Petrol", - enginetype = "Radial", - weight = 385, - torque = 700, - flywheelmass = 0.45, - idlerpm = 600, - peakminrpm = 2300, - peakmaxrpm = 3850, - limitrpm = 4400 -} ) - - -ACF_DefineEngine( "8.0-R7", { - name = "8.0 R7 Diesel", - desc = "Military-grade radial engine, similar to a ZO 02A. Heavy and with a narrow powerband, but efficient, and well-optimized to cruising.", - model = "models/engines/radial7m.mdl", - sound = "acf_base/engines/r7_petrolmedium.wav", - category = "Radial", - fuel = "Multifuel", - enginetype = "GenericDiesel", - weight = 450, - torque = 1000, - flywheelmass = 1.0, - idlerpm = 400, - peakminrpm = 2200, - peakmaxrpm = 2500, - limitrpm = 2800 -} ) - -ACF_DefineEngine( "24.0-R7", { - name = "24.0L R7 Petrol", - desc = "Massive American radial monster, destined for fighter aircraft and heavy tanks.", - model = "models/engines/radial7l.mdl", - sound = "acf_base/engines/r7_petrollarge.wav", - category = "Radial", - fuel = "Petrol", - enginetype = "Radial", - weight = 952, - torque = 2018, - flywheelmass = 3.4, - idlerpm = 750, - peakminrpm = 1900, - peakmaxrpm = 3150, - limitrpm = 3500 -} ) - ACF.RegisterEngineClass("R7", { Name = "Radial 7 Engine", }) diff --git a/lua/acf/shared/engines/rotary.lua b/lua/acf/shared/engines/rotary.lua index 7dee466ec..9aabd8626 100644 --- a/lua/acf/shared/engines/rotary.lua +++ b/lua/acf/shared/engines/rotary.lua @@ -1,57 +1,6 @@ -- Wankel engines -ACF_DefineEngine( "900cc-R", { - name = "0.9L Rotary", - desc = "Small 2-rotor Wankel; suited for yard use\n\nWankels have rather wide powerbands, but are very high strung", - model = "models/engines/wankel_2_small.mdl", - sound = "acf_base/engines/wankel_small.wav", - category = "Rotary", - fuel = "Petrol", - enginetype = "Wankel", - weight = 50, - torque = 97, - flywheelmass = 0.06, - idlerpm = 950, - peakminrpm = 4500, - peakmaxrpm = 9000, - limitrpm = 9200 -} ) - -ACF_DefineEngine( "1.3L-R", { - name = "1.3L Rotary", - desc = "Medium 2-rotor Wankel\n\nWankels have rather wide powerbands, but are very high strung", - model = "models/engines/wankel_2_med.mdl", - sound = "acf_base/engines/wankel_medium.wav", - category = "Rotary", - fuel = "Petrol", - enginetype = "Wankel", - weight = 140, - torque = 155, - flywheelmass = 0.06, - idlerpm = 950, - peakminrpm = 4100, - peakmaxrpm = 8500, - limitrpm = 9000 -} ) - -ACF_DefineEngine( "2.0L-R", { - name = "2.0L Rotary", - desc = "High performance 3-rotor Wankel\n\nWankels have rather wide powerbands, but are very high strung", - model = "models/engines/wankel_3_med.mdl", - sound = "acf_base/engines/wankel_large.wav", - category = "Rotary", - fuel = "Petrol", - enginetype = "Wankel", - weight = 200, - torque = 235, - flywheelmass = 0.1, - idlerpm = 950, - peakminrpm = 4100, - peakmaxrpm = 8500, - limitrpm = 9500 -} ) - ACF.RegisterEngineClass("R", { Name = "Rotary Engine", Description = "Wankels have rather wide powerbands, but are very high strung." diff --git a/lua/acf/shared/engines/single.lua b/lua/acf/shared/engines/single.lua index 5b62aaeca..f0bc73cc7 100644 --- a/lua/acf/shared/engines/single.lua +++ b/lua/acf/shared/engines/single.lua @@ -1,57 +1,6 @@ -- Single-cylinder engines -ACF_DefineEngine( "0.25-I1", { - name = "250cc Single", - desc = "Tiny bike engine", - model = "models/engines/1cylsml.mdl", - sound = "acf_base/engines/i1_small.wav", - category = "Single", - fuel = "Petrol", - enginetype = "GenericPetrol", - weight = 15, - torque = 25, - flywheelmass = 0.005, - idlerpm = 1200, - peakminrpm = 4000, - peakmaxrpm = 6500, - limitrpm = 7500 -} ) - -ACF_DefineEngine( "0.5-I1", { - name = "500cc Single", - desc = "Large single cylinder bike engine", - model = "models/engines/1cylmed.mdl", - sound = "acf_base/engines/i1_medium.wav", - category = "Single", - fuel = "Petrol", - enginetype = "GenericPetrol", - weight = 20, - torque = 50, - flywheelmass = 0.005, - idlerpm = 900, - peakminrpm = 4300, - peakmaxrpm = 7000, - limitrpm = 8000 -} ) - -ACF_DefineEngine( "1.3-I1", { - name = "1300cc Single", - desc = "Ridiculously large single cylinder engine, seriously what the fuck", - model = "models/engines/1cylbig.mdl", - sound = "acf_base/engines/i1_large.wav", - category = "Single", - fuel = "Petrol", - enginetype = "GenericPetrol", - weight = 50, - torque = 112, - flywheelmass = 0.1, - idlerpm = 600, - peakminrpm = 3600, - peakmaxrpm = 6000, - limitrpm = 6700 -} ) - ACF.RegisterEngineClass("I1", { Name = "Single Cylinder Engine", }) diff --git a/lua/acf/shared/engines/special.lua b/lua/acf/shared/engines/special.lua index 40f11f282..7af5d35f1 100644 --- a/lua/acf/shared/engines/special.lua +++ b/lua/acf/shared/engines/special.lua @@ -1,195 +1,6 @@ -- Special engines -ACF_DefineEngine( "0.9L-I2", { - name = "0.9L I2 Petrol", - desc = "Turbocharged inline twin engine that delivers surprising pep for its size.", - model = "models/engines/inline2s.mdl", - sound = "acf_extra/vehiclefx/engines/ponyengine.wav", - category = "Special", - fuel = "Petrol", - enginetype = "GenericPetrol", - weight = 60, - torque = 145, - flywheelmass = 0.085, - idlerpm = 750, - peakminrpm = 3125, - peakmaxrpm = 5100, - limitrpm = 6000 -} ) - -ACF_DefineEngine( "1.0L-I4", { - name = "1.0L I4 Petrol", - desc = "Tiny I4 designed for racing bikes. Doesn't pack much torque, but revs ludicrously high.", - model = "models/engines/inline4s.mdl", - sound = "acf_extra/vehiclefx/engines/l4/mini_onhigh.wav", - pitch = 0.75, - category = "Special", - fuel = "Petrol", - enginetype = "GenericPetrol", - weight = 78, - torque = 85, - flywheelmass = 0.031, - idlerpm = 1200, - peakminrpm = 7500, - peakmaxrpm = 11500, - limitrpm = 12000 -} ) - -ACF_DefineEngine( "1.8L-V4", { - name = "1.8L V4 Petrol", - desc = "Naturally aspirated rally-tuned V4 with enlarged bore and stroke.", - model = "models/engines/v4s.mdl", - sound = "acf_extra/vehiclefx/engines/l4/elan_onlow.wav", - category = "Special", - fuel = "Petrol", - enginetype = "GenericPetrol", - weight = 92, - torque = 156, - flywheelmass = 0.04, - idlerpm = 900, - peakminrpm = 4600, - peakmaxrpm = 7000, - limitrpm = 7500 -} ) - -ACF_DefineEngine( "2.4L-V6", { - name = "2.4L V6 Petrol", - desc = "Although the cast iron engine block is fairly weighty, this tiny v6 makes up for it with impressive power. The unique V angle allows uncharacteristically high RPM for a V6.", - model = "models/engines/v6small.mdl", - sound = "acf_extra/vehiclefx/engines/l6/capri_onmid.wav", - category = "Special", - fuel = "Petrol", - enginetype = "GenericPetrol", - weight = 134, - torque = 215, - flywheelmass = 0.075, - idlerpm = 950, - peakminrpm = 4500, - peakmaxrpm = 7100, - limitrpm = 8000 -} ) - -ACF_DefineEngine( "1.9L-I4", { - name = "1.9L I4 Petrol", - desc = "Supercharged racing 4 cylinder, most of the power in the high revs.", - model = "models/engines/inline4s.mdl", - sound = "acf_base/engines/i4_special.wav", - category = "Special", - fuel = "Petrol", - enginetype = "GenericPetrol", - weight = 150, - torque = 220, - flywheelmass = 0.06, - idlerpm = 950, - peakminrpm = 5200, - peakmaxrpm = 8500, - limitrpm = 9000 -} ) - -ACF_DefineEngine( "2.6L-Wankel", { - name = "2.6L Rotary", - desc = "4 rotor racing Wankel, high revving and high strung.", - model = "models/engines/wankel_4_med.mdl", - sound = "acf_base/engines/wankel_large.wav", - category = "Special", - fuel = "Petrol", - enginetype = "Wankel", - weight = 260, - torque = 312, - flywheelmass = 0.11, - idlerpm = 1200, - peakminrpm = 4500, - peakmaxrpm = 9000, - limitrpm = 9500 -} ) - -ACF_DefineEngine( "2.9-V8", { - name = "2.9L V8 Petrol", - desc = "Racing V8, very high revving and loud", - model = "models/engines/v8s.mdl", - sound = "acf_base/engines/v8_special.wav", - category = "Special", - fuel = "Petrol", - enginetype = "GenericPetrol", - weight = 180, - torque = 250, - flywheelmass = 0.075, - idlerpm = 1000, - peakminrpm = 5500, - peakmaxrpm = 9000, - limitrpm = 10000 -} ) - -ACF_DefineEngine( "3.8-I6", { - name = "3.8L I6 Petrol", - desc = "Large racing straight six, powerful and high revving, but lacking in torque.", - model = "models/engines/inline6m.mdl", - sound = "acf_base/engines/l6_special.wav", - category = "Special", - fuel = "Petrol", - enginetype = "GenericPetrol", - weight = 180, - torque = 280, - flywheelmass = 0.1, - idlerpm = 1100, - peakminrpm = 5200, - peakmaxrpm = 8500, - limitrpm = 9000 -} ) - -ACF_DefineEngine( "5.3-V10", { - name = "5.3L V10 Special", - desc = "Extreme performance v10", - model = "models/engines/v10sml.mdl", - sound = "acf_base/engines/v10_special.wav", - category = "Special", - fuel = "Petrol", - enginetype = "GenericPetrol", - weight = 300, - torque = 400, - flywheelmass = 0.15, - idlerpm = 1100, - peakminrpm = 5750, - peakmaxrpm = 8000, - limitrpm = 9000 -} ) - -ACF_DefineEngine( "7.2-V8", { - name = "7.2L V8 Petrol", - desc = "Very high revving, glorious v8 of ear rapetasticalness.", - model = "models/engines/v8m.mdl", - sound = "acf_base/engines/v8_special2.wav", - category = "Special", - fuel = "Petrol", - enginetype = "GenericPetrol", - weight = 400, - torque = 425, - flywheelmass = 0.15, - idlerpm = 1000, - peakminrpm = 5000, - peakmaxrpm = 8000, - limitrpm = 8500 -} ) - -ACF_DefineEngine( "3.0-V12", { - name = "3.0L V12 Petrol", - desc = "A purpose-built racing v12, not known for longevity.", - model = "models/engines/v12s.mdl", - sound = "acf_extra/vehiclefx/engines/v12/gtb4_onmid.wav", - pitch = 0.85, - category = "Special", - fuel = "Petrol", - enginetype = "GenericPetrol", - weight = 175, - torque = 310, - flywheelmass = 0.1, - idlerpm = 1200, - peakminrpm = 6875, - peakmaxrpm = 11000, - limitrpm = 12500 -} ) - ACF.RegisterEngineClass("SP", { Name = "Special Engine", }) diff --git a/lua/acf/shared/engines/turbine.lua b/lua/acf/shared/engines/turbine.lua index 13df0367d..f9bc76427 100644 --- a/lua/acf/shared/engines/turbine.lua +++ b/lua/acf/shared/engines/turbine.lua @@ -1,248 +1,6 @@ -- Gas turbines -ACF_DefineEngine( "Turbine-Small-Trans", { - name = "Gas Turbine, Small, Transaxial", - desc = "A small gas turbine, high power and a very wide powerband\n\nThese turbines are optimized for aero use, but can be used in other specialized roles, being powerful but suffering from poor throttle response and fuel consumption.\n\nOutputs to the side instead of rear.", - model = "models/engines/turbine_s.mdl", - sound = "acf_base/engines/turbine_small.wav", - category = "Turbine", - fuel = "Multifuel", - enginetype = "Turbine", - weight = 160, - torque = 550, - flywheelmass = 2.3, - idlerpm = 1400, - peakminrpm = 1000, - peakmaxrpm = 1500, - limitrpm = 10000, - iselec = true, - istrans = true, - flywheeloverride = 4167 -} ) - -ACF_DefineEngine( "Turbine-Medium-Trans", { - name = "Gas Turbine, Medium, Transaxial", - desc = "A medium gas turbine, moderate power but a very wide powerband\n\nThese turbines are optimized for aero use, but can be used in other specialized roles, being powerful but suffering from poor throttle response and fuel consumption.\n\nOutputs to the side instead of rear.", - model = "models/engines/turbine_m.mdl", - sound = "acf_base/engines/turbine_medium.wav", - category = "Turbine", - fuel = "Multifuel", - enginetype = "Turbine", - weight = 320, - torque = 812, - flywheelmass = 3.4, - idlerpm = 1800, - peakminrpm = 1200, - peakmaxrpm = 1800, - limitrpm = 12000, - iselec = true, - istrans = true, - flywheeloverride = 5000 -} ) - -ACF_DefineEngine( "Turbine-Large-Trans", { - name = "Gas Turbine, Large, Transaxial", - desc = "A large gas turbine, powerful with a wide powerband\n\nThese turbines are optimized for aero use, but can be used in other specialized roles, being powerful but suffering from poor throttle response and fuel consumption.\n\nOutputs to the side instead of rear.", - model = "models/engines/turbine_l.mdl", - sound = "acf_base/engines/turbine_large.wav", - category = "Turbine", - fuel = "Multifuel", - enginetype = "Turbine", - weight = 880, - torque = 1990, - flywheelmass = 8.4, - idlerpm = 2000, - peakminrpm = 1350, - peakmaxrpm = 2025, - limitrpm = 13500, - iselec = true, - istrans = true, - flywheeloverride = 5625 -} ) - -ACF_DefineEngine( "Turbine-Small", { - name = "Gas Turbine, Small", - desc = "A small gas turbine, high power and a very wide powerband\n\nThese turbines are optimized for aero use, but can be used in other specialized roles, being powerful but suffering from poor throttle response and fuel consumption.", - model = "models/engines/gasturbine_s.mdl", - sound = "acf_base/engines/turbine_small.wav", - category = "Turbine", - fuel = "Multifuel", - enginetype = "Turbine", - weight = 200, - torque = 687, - flywheelmass = 2.9, - idlerpm = 1400, - peakminrpm = 1000, - peakmaxrpm = 1500, - limitrpm = 10000, - iselec = true, - flywheeloverride = 4167 -} ) - -ACF_DefineEngine( "Turbine-Medium", { - name = "Gas Turbine, Medium", - desc = "A medium gas turbine, moderate power but a very wide powerband\n\nThese turbines are optimized for aero use, but can be used in other specialized roles, being powerful but suffering from poor throttle response and fuel consumption.", - model = "models/engines/gasturbine_m.mdl", - sound = "acf_base/engines/turbine_medium.wav", - category = "Turbine", - fuel = "Multifuel", - enginetype = "Turbine", - weight = 400, - torque = 1016, - flywheelmass = 4.3, - idlerpm = 1800, - peakminrpm = 1200, - peakmaxrpm = 1800, - limitrpm = 12000, - iselec = true, - flywheeloverride = 5000 -} ) - -ACF_DefineEngine( "Turbine-Large", { - name = "Gas Turbine, Large", - desc = "A large gas turbine, powerful with a wide powerband\n\nThese turbines are optimized for aero use, but can be used in other specialized roles, being powerful but suffering from poor throttle response and fuel consumption.", - model = "models/engines/gasturbine_l.mdl", - sound = "acf_base/engines/turbine_large.wav", - category = "Turbine", - fuel = "Multifuel", - enginetype = "Turbine", - weight = 1100, - torque = 2487, - flywheelmass = 10.5, - idlerpm = 2000, - peakminrpm = 1350, - peakmaxrpm = 2025, - limitrpm = 13500, - iselec = true, - flywheeloverride = 5625 -} ) - ---Forward facing ground turbines - -ACF_DefineEngine( "Turbine-Ground-Small", { - name = "Ground Gas Turbine, Small", - desc = "A small gas turbine, fitted with ground-use air filters and tuned for ground use.\n\nGround-use turbines have excellent low-rev performance and are deceptively powerful, easily propelling loads that would have equivalent reciprocating engines struggling; however, they have sluggish throttle response, high gearbox demands, high fuel usage, and low tolerance to damage.", - model = "models/engines/gasturbine_s.mdl", - sound = "acf_base/engines/turbine_small.wav", - category = "Turbine", - fuel = "Multifuel", - enginetype = "Radial", - weight = 350, - torque = 1000, - flywheelmass = 14.3, - idlerpm = 700, - peakminrpm = 1000, - peakmaxrpm = 1350, - limitrpm = 3000, - iselec = true, - flywheeloverride = 1667 -} ) - -ACF_DefineEngine( "Turbine-Ground-Medium", { - name = "Ground Gas Turbine, Medium", - desc = "A medium gas turbine, fitted with ground-use air filters and tuned for ground use.\n\nGround-use turbines have excellent low-rev performance and are deceptively powerful, easily propelling loads that would have equivalent reciprocating engines struggling; however, they have sluggish throttle response, high gearbox demands, high fuel usage, and low tolerance to damage.", - model = "models/engines/gasturbine_m.mdl", - sound = "acf_base/engines/turbine_medium.wav", - category = "Turbine", - fuel = "Multifuel", - enginetype = "Radial", --This is done to give proper fuel consumption and make the turbines not instant-torque from idle - weight = 600, - torque = 1500, - flywheelmass = 29.6, - idlerpm = 600, - peakminrpm = 1500, - peakmaxrpm = 2000, - limitrpm = 3000, - iselec = true, - flywheeloverride = 1450, - pitch = 1.15 -} ) - -ACF_DefineEngine( "Turbine-Ground-Large", { - name = "Ground Gas Turbine, Large", - desc = "A large gas turbine, fitted with ground-use air filters and tuned for ground use. Doesn't have the sheer power output of an aero gas turbine, but compensates with an imperial fuckload of torque.\n\nGround-use turbines have excellent low-rev performance and are deceptively powerful, easily propelling loads that would have equivalent reciprocating engines struggling; however, they have sluggish throttle response, high gearbox demands, high fuel usage, and low tolerance to damage.", - model = "models/engines/gasturbine_l.mdl", - sound = "acf_base/engines/turbine_large.wav", - category = "Turbine", - fuel = "Multifuel", - enginetype = "Radial", - weight = 1650, - torque = 5000, - flywheelmass = 75, - idlerpm = 500, - peakminrpm = 1000, - peakmaxrpm = 1250, - limitrpm = 3000, - iselec = true, - flywheeloverride = 1250, - pitch = 1.35 -} ) - ---Transaxial Ground Turbines - -ACF_DefineEngine( "Turbine-Small-Ground-Trans", { - name = "Ground Gas Turbine, Small, Transaxial", - desc = "A small gas turbine, fitted with ground-use air filters and tuned for ground use.\n\nGround-use turbines have excellent low-rev performance and are deceptively powerful, easily propelling loads that would have equivalent reciprocating engines struggling; however, they have sluggish throttle response, high gearbox demands, high fuel usage, and low tolerance to damage. Outputs to the side instead of rear.", - model = "models/engines/turbine_s.mdl", - sound = "acf_base/engines/turbine_small.wav", - category = "Turbine", - fuel = "Multifuel", - enginetype = "Radial", - weight = 280, - torque = 750, - flywheelmass = 11.4, - idlerpm = 700, - peakminrpm = 1000, - peakmaxrpm = 1350, - limitrpm = 3000, - iselec = true, - istrans = true, - flywheeloverride = 1667 -} ) - -ACF_DefineEngine( "Turbine-Medium-Ground-Trans", { - name = "Ground Gas Turbine, Medium, Transaxial", - desc = "A medium gas turbine, fitted with ground-use air filters and tuned for ground use.\n\nGround-use turbines have excellent low-rev performance and are deceptively powerful, easily propelling loads that would have equivalent reciprocating engines struggling; however, they have sluggish throttle response, high gearbox demands, high fuel usage, and low tolerance to damage. Outputs to the side instead of rear.", - model = "models/engines/turbine_m.mdl", - sound = "acf_base/engines/turbine_medium.wav", - category = "Turbine", - fuel = "Multifuel", - enginetype = "Radial", - weight = 480, - torque = 1125, - flywheelmass = 23.7, - idlerpm = 600, - peakminrpm = 1500, - peakmaxrpm = 2000, - limitrpm = 3000, - iselec = true, - istrans = true, - flywheeloverride = 1450, - pitch = 1.15 -} ) - -ACF_DefineEngine( "Turbine-Large-Ground-Trans", { - name = "Ground Gas Turbine, Large, Transaxial", - desc = "A large gas turbine, fitted with ground-use air filters and tuned for ground use. Doesn't have the sheer power output of an aero gas turbine, but compensates with an imperial fuckload of torque.\n\nGround-use turbines have excellent low-rev performance and are deceptively powerful, easily propelling loads that would have equivalent reciprocating engines struggling; however, they have sluggish throttle response, high gearbox demands, high fuel usage, and low tolerance to damage. Outputs to the side instead of rear.", - model = "models/engines/turbine_l.mdl", - sound = "acf_base/engines/turbine_large.wav", - category = "Turbine", - fuel = "Multifuel", - enginetype = "Radial", - weight = 1320, - torque = 3750, - flywheelmass = 60, - idlerpm = 500, - peakminrpm = 1000, - peakmaxrpm = 1250, - limitrpm = 3000, - iselec = true, - istrans = true, - flywheeloverride = 1250, - pitch = 1.35 -} ) - ACF.RegisterEngineClass("GT", { Name = "Gas Turbine", Description = "These turbines are optimized for aero use due to them being powerful but suffering from poor throttle response and fuel consumption." diff --git a/lua/acf/shared/engines/v10.lua b/lua/acf/shared/engines/v10.lua index 71c7276cc..79acd8764 100644 --- a/lua/acf/shared/engines/v10.lua +++ b/lua/acf/shared/engines/v10.lua @@ -1,56 +1,5 @@ --V10s -ACF_DefineEngine( "4.3-V10", { - name = "4.3L V10 Petrol", - desc = "Small-block V-10 gasoline engine, great for powering a hot rod lincoln", - model = "models/engines/v10sml.mdl", - sound = "acf_base/engines/v10_petrolsmall.wav", - category = "V10", - fuel = "Petrol", - enginetype = "GenericPetrol", - weight = 160, - torque = 360, - flywheelmass = 0.2, - idlerpm = 900, - peakminrpm = 3500, - peakmaxrpm = 5800, - limitrpm = 6250 -} ) - -ACF_DefineEngine( "8.0-V10", { - name = "8.0L V10 Petrol", - desc = "Beefy 10-cylinder gas engine, gets 9 kids to soccer practice", - model = "models/engines/v10med.mdl", - sound = "acf_base/engines/v10_petrolmedium.wav", - category = "V10", - fuel = "Petrol", - enginetype = "GenericPetrol", - weight = 300, - torque = 612, - flywheelmass = 0.5, - idlerpm = 750, - peakminrpm = 3400, - peakmaxrpm = 5500, - limitrpm = 6500 -} ) - -ACF_DefineEngine( "22.0-V10", { - name = "22.0L V10 Multifuel", - desc = "Heavy multifuel V-10, gearbox-shredding torque but very heavy.", - model = "models/engines/v10big.mdl", - sound = "acf_base/engines/v10_diesellarge.wav", - category = "V10", - fuel = "Multifuel", - enginetype = "GenericDiesel", - weight = 1600, - torque = 3256, - flywheelmass = 5, - idlerpm = 525, - peakminrpm = 750, - peakmaxrpm = 1900, - limitrpm = 2500 -} ) - ACF.RegisterEngineClass("V10", { Name = "V10 Engine", }) diff --git a/lua/acf/shared/engines/v12.lua b/lua/acf/shared/engines/v12.lua index 4a74a60d0..15973e24d 100644 --- a/lua/acf/shared/engines/v12.lua +++ b/lua/acf/shared/engines/v12.lua @@ -1,129 +1,6 @@ -- V12 engines --- Petrol - -ACF_DefineEngine( "4.6-V12", { - name = "4.6L V12 Petrol", - desc = "An elderly racecar engine; low on torque, but plenty of power", - model = "models/engines/v12s.mdl", - sound = "acf_base/engines/v12_petrolsmall.wav", - category = "V12", - fuel = "Petrol", - enginetype = "GenericPetrol", - weight = 188, - torque = 293, - flywheelmass = 0.2, - idlerpm = 1000, - peakminrpm = 4500, - peakmaxrpm = 7500, - limitrpm = 8000 -} ) - -ACF_DefineEngine( "7.0-V12", { - name = "7.0L V12 Petrol", - desc = "A high end V12; primarily found in very expensive cars", - model = "models/engines/v12m.mdl", - sound = "acf_base/engines/v12_petrolmedium.wav", - category = "V12", - fuel = "Petrol", - enginetype = "GenericPetrol", - weight = 360, - torque = 625, - flywheelmass = 0.45, - idlerpm = 800, - peakminrpm = 3600, - peakmaxrpm = 6000, - limitrpm = 7500 -} ) - -ACF_DefineEngine( "23.0-V12", { - name = "23.0L V12 Petrol", - desc = "A large, thirsty gasoline V12, found in early cold war tanks", - model = "models/engines/v12l.mdl", - sound = "acf_base/engines/v12_petrollarge.wav", - category = "V12", - fuel = "Petrol", - enginetype = "GenericPetrol", - weight = 1350, - torque = 2406, - flywheelmass = 5, - idlerpm = 600, - peakminrpm = 1500, - peakmaxrpm = 3000, - limitrpm = 3250 -} ) - --- Diesel - -ACF_DefineEngine( "4.0-V12", { - name = "4.0L V12 Diesel", - desc = "Reliable truck-duty diesel; a lot of smooth torque", - model = "models/engines/v12s.mdl", - sound = "acf_base/engines/v12_dieselsmall.wav", - category = "V12", - fuel = "Diesel", - enginetype = "GenericDiesel", - weight = 305, - torque = 468, - flywheelmass = 0.475, - idlerpm = 650, - peakminrpm = 1200, - peakmaxrpm = 3800, - limitrpm = 4000 -} ) - -ACF_DefineEngine( "9.2-V12", { - name = "9.2L V12 Diesel", - desc = "High torque light-tank V12, used mainly for vehicles that require balls", - model = "models/engines/v12m.mdl", - sound = "acf_base/engines/v12_dieselmedium.wav", - category = "V12", - fuel = "Diesel", - enginetype = "GenericDiesel", - weight = 600, - torque = 937, - flywheelmass = 2.5, - idlerpm = 675, - peakminrpm = 1100, - peakmaxrpm = 3300, - limitrpm = 3500 -} ) - -ACF_DefineEngine( "21.0-V12", { - name = "21.0L V12 Diesel", - desc = "AVDS-1790-2 tank engine; massively powerful, but enormous and heavy", - model = "models/engines/v12l.mdl", - sound = "acf_base/engines/v12_diesellarge.wav", - category = "V12", - fuel = "Diesel", - enginetype = "GenericDiesel", - weight = 1800, - torque = 4450, - flywheelmass = 7, - idlerpm = 400, - peakminrpm = 500, - peakmaxrpm = 1500, - limitrpm = 2500 -} ) - -ACF_DefineEngine( "13.0-V12", { - name = "13.0L V12 Petrol", - desc = "Thirsty gasoline v12, good torque and power for medium applications.", - model = "models/engines/v12m.mdl", - sound = "acf_base/engines/v12_special.wav", - category = "V12", - fuel = "Petrol", - enginetype = "GenericPetrol", - weight = 520, - torque = 825, - flywheelmass = 1, - idlerpm = 700, - peakminrpm = 2500, - peakmaxrpm = 4000, - limitrpm = 4250 -} ) - ACF.RegisterEngineClass("V12", { Name = "V12 Engine", }) diff --git a/lua/acf/shared/engines/v2.lua b/lua/acf/shared/engines/v2.lua index 48738061e..1d30bdc30 100644 --- a/lua/acf/shared/engines/v2.lua +++ b/lua/acf/shared/engines/v2.lua @@ -1,57 +1,6 @@ -- V-Twin engines -ACF_DefineEngine( "0.6-V2", { - name = "600cc V-Twin", - desc = "Twin cylinder bike engine, torquey for its size", - model = "models/engines/v-twins2.mdl", - sound = "acf_base/engines/vtwin_small.wav", - category = "V-Twin", - fuel = "Petrol", - enginetype = "GenericPetrol", - weight = 30, - torque = 62, - flywheelmass = 0.01, - idlerpm = 900, - peakminrpm = 4000, - peakmaxrpm = 6500, - limitrpm = 7000 -} ) - -ACF_DefineEngine( "1.2-V2", { - name = "1200cc V-Twin", - desc = "Large displacement vtwin engine", - model = "models/engines/v-twinm2.mdl", - sound = "acf_base/engines/vtwin_medium.wav", - category = "V-Twin", - fuel = "Petrol", - enginetype = "GenericPetrol", - weight = 50, - torque = 106, - flywheelmass = 0.02, - idlerpm = 725, - peakminrpm = 3300, - peakmaxrpm = 5500, - limitrpm = 6250 -} ) - -ACF_DefineEngine( "2.4-V2", { - name = "2400cc V-Twin", - desc = "Huge fucking Vtwin 'MURRICA FUCK YEAH", - model = "models/engines/v-twinl2.mdl", - sound = "acf_base/engines/vtwin_large.wav", - category = "V-Twin", - fuel = "Petrol", - enginetype = "GenericPetrol", - weight = 100, - torque = 200, - flywheelmass = 0.075, - idlerpm = 900, - peakminrpm = 3300, - peakmaxrpm = 5500, - limitrpm = 6000 -} ) - ACF.RegisterEngineClass("V2", { Name = "V-Twin Engine", }) diff --git a/lua/acf/shared/engines/v4.lua b/lua/acf/shared/engines/v4.lua index d25bd7c0f..5638c4836 100644 --- a/lua/acf/shared/engines/v4.lua +++ b/lua/acf/shared/engines/v4.lua @@ -1,42 +1,6 @@ --V4 Engines ---Diesel - -ACF_DefineEngine( "1.9L-V4", { - name = "1.9L V4 Diesel", - desc = "Torquey little lunchbox; for those smaller vehicles that don't agree with petrol powerbands", - model = "models/engines/v4s.mdl", - sound = "acf_base/engines/i4_diesel2.wav", - category = "V4", - fuel = "Diesel", - enginetype = "GenericDiesel", - weight = 110, - torque = 206, - flywheelmass = 0.3, - idlerpm = 650, - peakminrpm = 950, - peakmaxrpm = 3000, - limitrpm = 4000 -} ) - -ACF_DefineEngine( "3.3L-V4", { - name = "3.3L V4 Diesel", - desc = "Compact cube of git; for moderate utility applications", - model = "models/engines/v4m.mdl", - sound = "acf_base/engines/i4_dieselmedium.wav", - category = "V4", - fuel = "Diesel", - enginetype = "GenericDiesel", - weight = 275, - torque = 600, - flywheelmass = 1.05, - idlerpm = 600, - peakminrpm = 1050, - peakmaxrpm = 3100, - limitrpm = 3900 -} ) - ACF.RegisterEngineClass("V4", { Name = "V4 Engine", }) diff --git a/lua/acf/shared/engines/v6.lua b/lua/acf/shared/engines/v6.lua index 8db0dbc60..e0dd68e20 100644 --- a/lua/acf/shared/engines/v6.lua +++ b/lua/acf/shared/engines/v6.lua @@ -1,91 +1,6 @@ -- V6 engines -ACF_DefineEngine( "3.6-V6", { - name = "3.6L V6 Petrol", - desc = "Meaty Car sized V6, lots of torque\n\nV6s are more torquey than the Boxer and Inline 6s but suffer in power", - model = "models/engines/v6small.mdl", - sound = "acf_base/engines/v6_petrolsmall.wav", - category = "V6", - fuel = "Petrol", - enginetype = "GenericPetrol", - weight = 190, - torque = 316, - flywheelmass = 0.25, - idlerpm = 700, - peakminrpm = 2200, - peakmaxrpm = 3500, - limitrpm = 5000 -} ) - -ACF_DefineEngine( "6.2-V6", { - name = "6.2L V6 Petrol", - desc = "Heavy duty 6V71 v6, throatier than an LA whore, but loaded with torque\n\nV6s are more torquey than the Boxer and Inline 6s but suffer in power", - model = "models/engines/v6med.mdl", - sound = "acf_base/engines/v6_petrolmedium.wav", - category = "V6", - fuel = "Petrol", - enginetype = "GenericPetrol", - weight = 360, - torque = 590, - flywheelmass = 0.45, - idlerpm = 800, - peakminrpm = 2200, - peakmaxrpm = 3600, - limitrpm = 5000 -} ) - -ACF_DefineEngine( "5.2-V6", { - name = "5.2L V6 Diesel", - desc = "Light AFV-grade two-stroke multifuel, high output but heavy", - model = "models/engines/v6med.mdl", - sound = "acf_base/engines/i5_dieselmedium.wav", - category = "V6", - fuel = "Multifuel", - enginetype = "GenericDiesel", - weight = 520, - torque = 606, - flywheelmass = 0.8, - idlerpm = 650, - peakminrpm = 1800, - peakmaxrpm = 4200, - limitrpm = 4300 -} ) - -ACF_DefineEngine( "12.0-V6", { - name = "12.0L V6 Petrol", - desc = "Fuck duty V6, guts ripped from god himself diluted in salt and shaped into an engine.\n\nV6s are more torquey than the Boxer and Inline 6s but suffer in power", - model = "models/engines/v6large.mdl", - sound = "acf_base/engines/v6_petrollarge.wav", - category = "V6", - fuel = "Petrol", - enginetype = "GenericPetrol", - weight = 675, - torque = 1806, - flywheelmass = 4, - idlerpm = 600, - peakminrpm = 1575, - peakmaxrpm = 2650, - limitrpm = 3800 -} ) - -ACF_DefineEngine( "15.0-V6", { - name = "15.0L V6 Diesel", - desc = "Powerful military-grade large V6, with impressive output. Well suited to moderately-sized AFVs and able to handle multiple fuel types.\n\nV6s are more torquey than the Boxer and Inline 6s but suffer in power", - model = "models/engines/v6large.mdl", - sound = "acf_base/engines/v6_diesellarge.wav", - category = "V6", - fuel = "Multifuel", - enginetype = "GenericDiesel", - weight = 900, - torque = 2208, - flywheelmass = 6.4, - idlerpm = 400, - peakminrpm = 1150, - peakmaxrpm = 1950, - limitrpm = 3100 -} ) - ACF.RegisterEngineClass("V6", { Name = "V6 Engine", Description = "V6s are more torquey than the Boxer and Inline 6s but suffer in power." diff --git a/lua/acf/shared/engines/v8.lua b/lua/acf/shared/engines/v8.lua index ef1daee72..010e4137c 100644 --- a/lua/acf/shared/engines/v8.lua +++ b/lua/acf/shared/engines/v8.lua @@ -1,112 +1,6 @@ -- V8 engines --- Petrol - -ACF_DefineEngine( "5.7-V8", { - name = "5.7L V8 Petrol", - desc = "Car sized petrol engine, good power and mid range torque", - model = "models/engines/v8s.mdl", - sound = "acf_base/engines/v8_petrolsmall.wav", - category = "V8", - fuel = "Petrol", - enginetype = "GenericPetrol", - weight = 260, - torque = 400, - flywheelmass = 0.15, - idlerpm = 800, - peakminrpm = 3000, - peakmaxrpm = 5000, - limitrpm = 6500 -} ) - -ACF_DefineEngine( "9.0-V8", { - name = "9.0L V8 Petrol", - desc = "Thirsty, giant V8, for medium applications", - model = "models/engines/v8m.mdl", - sound = "acf_base/engines/v8_petrolmedium.wav", - category = "V8", - fuel = "Petrol", - enginetype = "GenericPetrol", - weight = 400, - torque = 575, - flywheelmass = 0.25, - idlerpm = 700, - peakminrpm = 3100, - peakmaxrpm = 5000, - limitrpm = 5500 -} ) - -ACF_DefineEngine( "18.0-V8", { - name = "18.0L V8 Petrol", - desc = "American gasoline tank V8, good overall power and torque and fairly lightweight", - model = "models/engines/v8l.mdl", - sound = "acf_base/engines/v8_petrollarge.wav", - category = "V8", - fuel = "Petrol", - enginetype = "GenericPetrol", - weight = 850, - torque = 1822, - flywheelmass = 2.8, - idlerpm = 600, - peakminrpm = 2000, - peakmaxrpm = 3300, - limitrpm = 3800 -} ) - --- Diesel - -ACF_DefineEngine( "4.5-V8", { - name = "4.5L V8 Diesel", - desc = "Light duty diesel v8, good for light vehicles that require a lot of torque", - model = "models/engines/v8s.mdl", - sound = "acf_base/engines/v8_dieselsmall.wav", - category = "V8", - fuel = "Diesel", - enginetype = "GenericDiesel", - weight = 320, - torque = 518, - flywheelmass = 0.75, - idlerpm = 800, - peakminrpm = 1000, - peakmaxrpm = 3000, - limitrpm = 5000 -} ) - -ACF_DefineEngine( "7.8-V8", { - name = "7.8L V8 Diesel", - desc = "Redneck chariot material. Truck duty V8 diesel, has a good, wide powerband", - model = "models/engines/v8m.mdl", - sound = "acf_base/engines/v8_dieselmedium2.wav", - category = "V8", - fuel = "Diesel", - enginetype = "GenericDiesel", - weight = 520, - torque = 875, - flywheelmass = 1.6, - idlerpm = 650, - peakminrpm = 1000, - peakmaxrpm = 3000, - limitrpm = 4000 -} ) - -ACF_DefineEngine( "19.0-V8", { - name = "19.0L V8 Diesel", - desc = "Heavy duty diesel V8, used in heavy construction equipment and tanks", - model = "models/engines/v8l.mdl", - sound = "acf_base/engines/v8_diesellarge.wav", - category = "V8", - fuel = "Diesel", - enginetype = "GenericDiesel", - weight = 1200, - torque = 2875, - flywheelmass = 4.5, - idlerpm = 500, - peakminrpm = 600, - peakmaxrpm = 1800, - limitrpm = 2500 -} ) - ACF.RegisterEngineClass("V8", { Name = "V8 Engine", }) diff --git a/lua/acf/shared/fueltanks/basic.lua b/lua/acf/shared/fueltanks/basic.lua deleted file mode 100644 index 66924783a..000000000 --- a/lua/acf/shared/fueltanks/basic.lua +++ /dev/null @@ -1,355 +0,0 @@ - ---definition for the fuel tank that shows on menu -ACF_DefineFuelTank( "Basic_FuelTank", { - name = "Fuel Tank", - desc = "A steel box containing fuel.", - --category = "Fuel" -} ) - ---definitions for the possible tank sizes selectable from the basic tank. -ACF_DefineFuelTankSize( "Tank_1x1x1", { --ID used in code - name = "1x1x1", --human readable name - desc = "Seriously consider walking.", - model = "models/fueltank/fueltank_1x1x1.mdl", - dims = { S = 590.5, V = 1019.9 } --surface area and volume of prop in gmu, used for capacity calcs in gui -} ) - -ACF_DefineFuelTankSize( "Tank_1x1x2", { - name = "1x1x2", - desc = "Will keep a kart running all day.", - model = "models/fueltank/fueltank_1x1x2.mdl", - dims = { S = 974, V = 1983.1 } -} ) - -ACF_DefineFuelTankSize( "Tank_1x1x4", { - name = "1x1x4", - desc = "Dinghy", - model = "models/fueltank/fueltank_1x1x4.mdl", - dims = { S = 1777.4, V = 3995.1 } -} ) - -ACF_DefineFuelTankSize( "Tank_1x2x1", { - name = "1x2x1", - desc = "Will keep a kart running all day.", - model = "models/fueltank/fueltank_1x2x1.mdl", - dims = { S = 995, V = 2062.5 } -} ) - -ACF_DefineFuelTankSize( "Tank_1x2x2", { - name = "1x2x2", - desc = "Dinghy", - model = "models/fueltank/fueltank_1x2x2.mdl", - dims = { S = 1590.8, V = 4070.9 } -} ) - -ACF_DefineFuelTankSize( "Tank_1x2x4", { - name = "1x2x4", - desc = "Outboard motor.", - model = "models/fueltank/fueltank_1x2x4.mdl", - dims = { S = 2796.6, V = 8119.2 } -} ) - -ACF_DefineFuelTankSize( "Tank_1x4x1", { - name = "1x4x1", - desc = "Dinghy", - model = "models/fueltank/fueltank_1x4x1.mdl", - dims = { S = 1745.6, V = 3962 } -} ) - -ACF_DefineFuelTankSize( "Tank_1x4x2", { - name = "1x4x2", - desc = "Clown car.", - model = "models/fueltank/fueltank_1x4x2.mdl", - dims = { S = 2753.9, V = 8018 } -} ) - -ACF_DefineFuelTankSize( "Tank_1x4x4", { - name = "1x4x4", - desc = "Fuel pancake.", - model = "models/fueltank/fueltank_1x4x4.mdl", - dims = { S = 4761, V = 16030.4 } -} ) - -ACF_DefineFuelTankSize( "Tank_1x6x1", { - name = "1x6x1", - desc = "Lawn tractors.", - model = "models/fueltank/fueltank_1x6x1.mdl", - dims = { S = 2535.3, V = 5973.1 } -} ) - -ACF_DefineFuelTankSize( "Tank_1x6x2", { - name = "1x6x2", - desc = "Small tractor tank.", - model = "models/fueltank/fueltank_1x6x2.mdl", - dims = { S = 3954.1, V = 12100.3 } -} ) - -ACF_DefineFuelTankSize( "Tank_1x6x4", { - name = "1x6x4", - desc = "Fuel. Will keep you going for awhile.", - model = "models/fueltank/fueltank_1x6x4.mdl", - dims = { S = 6743.3, V = 24109.4 } -} ) - -ACF_DefineFuelTankSize( "Tank_1x8x1", { - name = "1x8x1", - desc = "Clown car.", - model = "models/fueltank/fueltank_1x8x1.mdl", - dims = { S = 3315.5, V = 7962.4 } -} ) - -ACF_DefineFuelTankSize( "Tank_1x8x2", { - name = "1x8x2", - desc = "Gas stations? We don't need no stinking gas stations!", - model = "models/fueltank/fueltank_1x8x2.mdl", - dims = { S = 5113.7, V = 16026.2 } -} ) - -ACF_DefineFuelTankSize( "Tank_1x8x4", { - name = "1x8x4", - desc = "Beep beep.", - model = "models/fueltank/fueltank_1x8x4.mdl", - dims = { S = 8696, V = 31871 } -} ) - -ACF_DefineFuelTankSize( "Tank_2x2x1", { - name = "2x2x1", - desc = "Dinghy", - model = "models/fueltank/fueltank_2x2x1.mdl", - dims = { S = 1592.2, V = 4285.2 } -} ) - -ACF_DefineFuelTankSize( "Tank_2x2x2", { - name = "2x2x2", - desc = "Clown car.", - model = "models/fueltank/fueltank_2x2x2.mdl", - dims = { S = 2360.4, V = 8212.9 } -} ) - -ACF_DefineFuelTankSize( "Tank_2x2x4", { - name = "2x2x4", - desc = "Mini Cooper.", - model = "models/fueltank/fueltank_2x2x4.mdl", - dims = { S = 3988.6, V = 16362 } -} ) - -ACF_DefineFuelTankSize( "Tank_2x4x1", { - name = "2x4x1", - desc = "Good bit of go-juice.", - model = "models/fueltank/fueltank_2x4x1.mdl", - dims = { S = 2808.8, V = 8628 } -} ) - -ACF_DefineFuelTankSize( "Tank_2x4x2", { - name = "2x4x2", - desc = "Mini Cooper.", - model = "models/fueltank/fueltank_2x4x2.mdl", - dims = { S = 3996.1, V = 16761.4 } -} ) - -ACF_DefineFuelTankSize( "Tank_2x4x4", { - name = "2x4x4", - desc = "Land boat.", - model = "models/fueltank/fueltank_2x4x4.mdl", - dims = { S = 6397.3, V = 32854.4 } -} ) - -ACF_DefineFuelTankSize( "Tank_2x6x1", { - name = "2x6x1", - desc = "Conformal fuel tank, fits narrow spaces.", - model = "models/fueltank/fueltank_2x6x1.mdl", - dims = { S = 3861.4, V = 12389.9 } -} ) - -ACF_DefineFuelTankSize( "Tank_2x6x2", { - name = "2x6x2", - desc = "Compact car.", - model = "models/fueltank/fueltank_2x6x2.mdl", - dims = { S = 5388, V = 24127.7 } -} ) - -ACF_DefineFuelTankSize( "Tank_2x6x4", { - name = "2x6x4", - desc = "Sedan.", - model = "models/fueltank/fueltank_2x6x4.mdl", - dims = { S = 8485.6, V = 47537.2 } -} ) - -ACF_DefineFuelTankSize( "Tank_2x8x1", { - name = "2x8x1", - desc = "Conformal fuel tank, fits into tight spaces", - model = "models/fueltank/fueltank_2x8x1.mdl", - dims = { S = 5094.5, V = 16831.8 } -} ) - -ACF_DefineFuelTankSize( "Tank_2x8x2", { - name = "2x8x2", - desc = "Truck.", - model = "models/fueltank/fueltank_2x8x2.mdl", - dims = { S = 6980, V = 32275.9 } -} ) - -ACF_DefineFuelTankSize( "Tank_2x8x4", { - name = "2x8x4", - desc = "With great capacity, comes great responsibili--VROOOOM", - model = "models/fueltank/fueltank_2x8x4.mdl", - dims = { S = 10898.2, V = 63976 } -} ) - -ACF_DefineFuelTankSize( "Tank_4x4x1", { - name = "4x4x1", - desc = "Sedan.", - model = "models/fueltank/fueltank_4x4x1.mdl", - dims = { S = 4619.1, V = 16539.8 } -} ) - -ACF_DefineFuelTankSize( "Tank_4x4x2", { - name = "4x4x2", - desc = "Land boat.", - model = "models/fueltank/fueltank_4x4x2.mdl", - dims = { S = 6071.4, V = 32165.2 } -} ) - -ACF_DefineFuelTankSize( "Tank_4x4x4", { - name = "4x4x4", - desc = "Popular with arsonists.", - model = "models/fueltank/fueltank_4x4x4.mdl", - dims = { S = 9145.3, V = 62900.1 } -} ) - -ACF_DefineFuelTankSize( "Tank_4x6x1", { - name = "4x6x1", - desc = "Conformal fuel tank, fits in tight spaces.", - model = "models/fueltank/fueltank_4x6x1.mdl", - dims = { S = 6553.6, V = 24918.6 } -} ) - -ACF_DefineFuelTankSize( "Tank_4x6x2", { - name = "4x6x2", - desc = "Fire juice.", - model = "models/fueltank/fueltank_4x6x2.mdl", - dims = { S = 8425.3, V = 48581.2 } -} ) - -ACF_DefineFuelTankSize( "Tank_4x6x4", { - name = "4x6x4", - desc = "Trees are gay anyway.", - model = "models/fueltank/fueltank_4x6x4.mdl", - dims = { S = 12200.6, V = 94640 } -} ) - -ACF_DefineFuelTankSize( "Tank_4x8x1", { - name = "4x8x1", - desc = "Arson material.", - model = "models/fueltank/fueltank_4x8x1.mdl", - dims = { S = 8328.2, V = 32541.9 } -} ) - -ACF_DefineFuelTankSize( "Tank_4x8x2", { - name = "4x8x2", - desc = "What's a gas station?", - model = "models/fueltank/fueltank_4x8x2.mdl", - dims = { S = 10419.5, V = 63167.1 } -} ) - -ACF_DefineFuelTankSize( "Tank_4x8x4", { - name = "4x8x4", - desc = "\'MURRICA FUCKYEAH!", - model = "models/fueltank/fueltank_4x8x4.mdl", - dims = { S = 14993.3, V = 123693.2 } -} ) - -ACF_DefineFuelTankSize( "Tank_6x6x1", { - name = "6x6x1", - desc = "Got gas?", - model = "models/fueltank/fueltank_6x6x1.mdl", - dims = { S = 9405.2, V = 37278.5 } -} ) - -ACF_DefineFuelTankSize( "Tank_6x6x2", { - name = "6x6x2", - desc = "Drive across the desert without a fuck to give.", - model = "models/fueltank/fueltank_6x6x2.mdl", - dims = { S = 11514.5, V = 73606.2 } -} ) - -ACF_DefineFuelTankSize( "Tank_6x6x4", { - name = "6x6x4", - desc = "May contain Mesozoic ghosts.", - model = "models/fueltank/fueltank_6x6x4.mdl", - dims = { S = 16028.8, V = 143269 } -} ) - -ACF_DefineFuelTankSize( "Tank_6x8x1", { - name = "6x8x1", - desc = "Conformal fuel tank, does what all its friends do.", - model = "models/fueltank/fueltank_6x8x1.mdl", - dims = { S = 12131.1, V = 48480.2 } -} ) - -ACF_DefineFuelTankSize( "Tank_6x8x2", { - name = "6x8x2", - desc = "Certified 100% dinosaur juice.", - model = "models/fueltank/fueltank_6x8x2.mdl", - dims = { S = 14403.8, V = 95065.5 } -} ) - -ACF_DefineFuelTankSize( "Tank_6x8x4", { - name = "6x8x4", - desc = "Will last you a while.", - model = "models/fueltank/fueltank_6x8x4.mdl", - dims = { S = 19592.4, V = 187296.4 } -} ) - -ACF_DefineFuelTankSize( "Tank_8x8x1", { - name = "8x8x1", - desc = "Sloshy sloshy!", - model = "models/fueltank/fueltank_8x8x1.mdl", - dims = { S = 15524.8, V = 64794.2 } -} ) - -ACF_DefineFuelTankSize( "Tank_8x8x2", { - name = "8x8x2", - desc = "What's global warming?", - model = "models/fueltank/fueltank_8x8x2.mdl", - dims = { S = 18086.4, V = 125868.9 } -} ) - -ACF_DefineFuelTankSize( "Tank_8x8x4", { - name = "8x8x4", - desc = "Tank Tank.", - model = "models/fueltank/fueltank_8x8x4.mdl", - dims = { S = 23957.6, V = 246845.3 } -} ) - -ACF_DefineFuelTankSize( "Fuel_Drum", { - name = "Fuel Drum", - desc = "Tends to explode when shot.", - model = "models/props_c17/oildrum001_explosive.mdl", - dims = { S = 5128.9, V = 26794.4 } -} ) - -ACF_DefineFuelTankSize( "Jerry_Can", { - name = "Jerry Can", - desc = "Handy portable fuel container.", - model = "models/props_junk/gascan001a.mdl", - dims = { S = 1839.7, V = 4384.1 }, -} ) - -ACF_DefineFuelTankSize( "Transport_Tank", { - name = "Transport Tank", - desc = "Disappointingly non-explosive.", - model = "models/props_wasteland/horizontalcoolingtank04.mdl", - dims = { S = 127505.5, V = 2102493.3 }, - explosive = false, - nolinks = true -} ) - -ACF_DefineFuelTankSize( "Storage_Tank", { - name = "Storage Tank", - desc = "Disappointingly non-explosive.", - model = "models/props_wasteland/coolingtank02.mdl", - dims = { S = 144736.3, V = 2609960 }, - explosive = false, - nolinks = true -} ) diff --git a/lua/acf/shared/gearboxes/3-auto.lua b/lua/acf/shared/gearboxes/3-auto.lua index 4937fbbd6..f3871adea 100644 --- a/lua/acf/shared/gearboxes/3-auto.lua +++ b/lua/acf/shared/gearboxes/3-auto.lua @@ -73,7 +73,7 @@ ACF.RegisterGearboxClass("3-Auto", { local Point = ACF.CheckNumber(Points[I]) if not Point then - Point = (CheckNumber(Data["Shift" .. I]) or I * 100) * Mult + Point = (ACF.CheckNumber(Data["Shift" .. I]) or I * 100) * Mult Data["Shift" .. I] = nil end diff --git a/lua/acf/shared/gearboxes/4-speed.lua b/lua/acf/shared/gearboxes/4-speed.lua index 2fee5cf4a..3e762662a 100644 --- a/lua/acf/shared/gearboxes/4-speed.lua +++ b/lua/acf/shared/gearboxes/4-speed.lua @@ -13,308 +13,6 @@ local Gear4MT = 1700 local Gear4LT = 10000 local StTB = 1.25 --straight torque bonus multiplier --- Inline - -ACF_DefineGearbox( "4Gear-L-S", { - name = "4-Speed, Inline, Small", - desc = "A small, and light 4 speed inline gearbox, with a somewhat limited max torque rating\n\nThe Final Drive slider is a multiplier applied to all the other gear ratios", - model = "models/engines/linear_s.mdl", - category = "4-Speed", - weight = Gear4SW, - switch = 0.15, - maxtq = Gear4ST, - gears = 4, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.1, - [ 2 ] = 0.2, - [ 3 ] = 0.3, - [ 4 ] = -0.1, - [ -1 ] = 0.5 - } -} ) - -ACF_DefineGearbox( "4Gear-L-M", { - name = "4-Speed, Inline, Medium", - desc = "A medium sized, 4 speed inline gearbox", - model = "models/engines/linear_m.mdl", - category = "4-Speed", - weight = Gear4MW, - switch = 0.2, - maxtq = Gear4MT, - gears = 4, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.1, - [ 2 ] = 0.2, - [ 3 ] = 0.3, - [ 4 ] = -0.1, - [ -1 ] = 0.5 - } -} ) - -ACF_DefineGearbox( "4Gear-L-L", { - name = "4-Speed, Inline, Large", - desc = "A large, heavy and sturdy 4 speed inline gearbox", - model = "models/engines/linear_l.mdl", - category = "4-Speed", - weight = Gear4LW, - switch = 0.3, - maxtq = Gear4LT, - gears = 4, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.1, - [ 2 ] = 0.2, - [ 3 ] = 0.3, - [ 4 ] = -0.1, - [ -1 ] = 1 - } -} ) - --- Inline Dual Clutch - -ACF_DefineGearbox( "4Gear-LD-S", { - name = "4-Speed, Inline, Small, Dual Clutch", - desc = "A small, and light 4 speed inline gearbox, with a somewhat limited max torque rating. The dual clutch allows you to apply power and brake each side independently\n\nThe Final Drive slider is a multiplier applied to all the other gear ratios", - model = "models/engines/linear_s.mdl", - category = "4-Speed", - weight = Gear4SW, - switch = 0.15, - maxtq = Gear4ST, - gears = 4, - doubleclutch = true, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.1, - [ 2 ] = 0.2, - [ 3 ] = 0.3, - [ 4 ] = -0.1, - [ -1 ] = 0.5 - } -} ) - -ACF_DefineGearbox( "4Gear-LD-M", { - name = "4-Speed, Inline, Medium, Dual Clutch", - desc = "A medium sized, 4 speed inline gearbox. The dual clutch allows you to apply power and brake each side independently", - model = "models/engines/linear_m.mdl", - category = "4-Speed", - weight = Gear4MW, - switch = 0.2, - maxtq = Gear4MT, - gears = 4, - doubleclutch = true, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.1, - [ 2 ] = 0.2, - [ 3 ] = 0.3, - [ 4 ] = -0.1, - [ -1 ] = 0.5 - } -} ) - -ACF_DefineGearbox( "4Gear-LD-L", { - name = "4-Speed, Inline, Large, Dual Clutch", - desc = "A large, heavy and sturdy 4 speed inline gearbox. The dual clutch allows you to apply power and brake each side independently", - model = "models/engines/linear_l.mdl", - category = "4-Speed", - weight = Gear4LW, - switch = 0.3, - maxtq = Gear4LT, - gears = 4, - doubleclutch = true, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.1, - [ 2 ] = 0.2, - [ 3 ] = 0.3, - [ 4 ] = -0.1, - [ -1 ] = 1 - } -} ) - --- Transaxial - -ACF_DefineGearbox( "4Gear-T-S", { - name = "4-Speed, Transaxial, Small", - desc = "A small, and light 4 speed gearbox, with a somewhat limited max torque rating\n\nThe Final Drive slider is a multiplier applied to all the other gear ratios", - model = "models/engines/transaxial_s.mdl", - category = "4-Speed", - weight = Gear4SW, - switch = 0.15, - maxtq = Gear4ST, - gears = 4, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.1, - [ 2 ] = 0.2, - [ 3 ] = 0.3, - [ 4 ] = -0.1, - [ -1 ] = 0.5 - } -} ) - -ACF_DefineGearbox( "4Gear-T-M", { - name = "4-Speed, Transaxial, Medium", - desc = "A medium sized, 4 speed gearbox", - model = "models/engines/transaxial_m.mdl", - category = "4-Speed", - weight = Gear4MW, - switch = 0.2, - maxtq = Gear4MT, - gears = 4, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.1, - [ 2 ] = 0.2, - [ 3 ] = 0.3, - [ 4 ] = -0.1, - [ -1 ] = 0.5 - } -} ) - -ACF_DefineGearbox( "4Gear-T-L", { - name = "4-Speed, Transaxial, Large", - desc = "A large, heavy and sturdy 4 speed gearbox", - model = "models/engines/transaxial_l.mdl", - category = "4-Speed", - weight = Gear4LW, - switch = 0.3, - maxtq = Gear4LT, - gears = 4, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.1, - [ 2 ] = 0.2, - [ 3 ] = 0.3, - [ 4 ] = -0.1, - [ -1 ] = 1 - } -} ) - --- Transaxial Dual Clutch - -ACF_DefineGearbox( "4Gear-TD-S", { - name = "4-Speed, Transaxial, Small, Dual Clutch", - desc = "A small, and light 4 speed gearbox, with a somewhat limited max torque rating. The dual clutch allows you to apply power and brake each side independently\n\nThe Final Drive slider is a multiplier applied to all the other gear ratios", - model = "models/engines/transaxial_s.mdl", - category = "4-Speed", - weight = Gear4SW, - switch = 0.15, - maxtq = Gear4ST, - gears = 4, - doubleclutch = true, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.1, - [ 2 ] = 0.2, - [ 3 ] = 0.3, - [ 4 ] = -0.1, - [ -1 ] = 0.5 - } -} ) - -ACF_DefineGearbox( "4Gear-TD-M", { - name = "4-Speed, Transaxial, Medium, Dual Clutch", - desc = "A medium sized, 4 speed gearbox. The dual clutch allows you to apply power and brake each side independently", - model = "models/engines/transaxial_m.mdl", - category = "4-Speed", - weight = Gear4MW, - switch = 0.2, - maxtq = Gear4MT, - gears = 4, - doubleclutch = true, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.1, - [ 2 ] = 0.2, - [ 3 ] = 0.3, - [ 4 ] = -0.1, - [ -1 ] = 0.5 - } -} ) - -ACF_DefineGearbox( "4Gear-TD-L", { - name = "4-Speed, Transaxial, Large, Dual Clutch", - desc = "A large, heavy and sturdy 4 speed gearbox. The dual clutch allows you to apply power and brake each side independently", - model = "models/engines/transaxial_l.mdl", - category = "4-Speed", - weight = Gear4LW, - switch = 0.3, - maxtq = Gear4LT, - gears = 4, - doubleclutch = true, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.1, - [ 2 ] = 0.2, - [ 3 ] = 0.3, - [ 4 ] = -0.1, - [ -1 ] = 1 - } -} ) - --- Straight-through gearboxes - -ACF_DefineGearbox( "4Gear-ST-S", { - name = "4-Speed, Straight, Small", - desc = "A small straight-through gearbox", - model = "models/engines/t5small.mdl", - category = "4-Speed", - weight = math.floor(Gear4SW * StWB), - switch = 0.15, - maxtq = math.floor(Gear4ST * StTB), - gears = 4, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.1, - [ 2 ] = 0.2, - [ 3 ] = 0.3, - [ 4 ] = -0.1, - [ -1 ] = 1 - } -} ) - -ACF_DefineGearbox( "4Gear-ST-M", { - name = "4-Speed, Straight, Medium", - desc = "A medium sized, 4 speed straight-through gearbox.", - model = "models/engines/t5med.mdl", - category = "4-Speed", - weight = math.floor(Gear4MW * StWB), - switch = 0.2, - maxtq = math.floor(Gear4MT * StTB), - gears = 4, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.1, - [ 2 ] = 0.2, - [ 3 ] = 0.3, - [ 4 ] = -0.1, - [ -1 ] = 0.5 - } -} ) - -ACF_DefineGearbox( "4Gear-ST-L", { - name = "4-Speed, Straight, Large", - desc = "A large sized, 4 speed straight-through gearbox.", - model = "models/engines/t5large.mdl", - category = "4-Speed", - weight = math.floor(Gear4LW * StWB), - switch = 0.3, - maxtq = math.floor(Gear4LT * StTB), - gears = 4, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.1, - [ 2 ] = 0.2, - [ 3 ] = 0.3, - [ 4 ] = -0.1, - [ -1 ] = 0.5 - } -} ) - - ACF.RegisterGearboxClass("4-Speed", { Name = "4-Speed Gearbox", CreateMenu = ACF.ManualGearboxMenu, diff --git a/lua/acf/shared/gearboxes/6-speed.lua b/lua/acf/shared/gearboxes/6-speed.lua index 5fbcf201d..903bc6717 100644 --- a/lua/acf/shared/gearboxes/6-speed.lua +++ b/lua/acf/shared/gearboxes/6-speed.lua @@ -13,337 +13,6 @@ local Gear6MT = 1360 local Gear6LT = 10000 local StTB = 1.25 --straight torque bonus multiplier --- Inline - -ACF_DefineGearbox( "6Gear-L-S", { - name = "6-Speed, Inline, Small", - desc = "A small and light 6 speed inline gearbox, with a limited max torque rating.", - model = "models/engines/linear_s.mdl", - category = "6-Speed", - weight = Gear6SW, - switch = 0.15, - maxtq = Gear6ST, - gears = 6, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.1, - [ 2 ] = 0.2, - [ 3 ] = 0.3, - [ 4 ] = 0.4, - [ 5 ] = 0.5, - [ 6 ] = -0.1, - [ -1 ] = 0.5 - } -} ) - -ACF_DefineGearbox( "6Gear-L-M", { - name = "6-Speed, Inline, Medium", - desc = "A medium duty 6 speed inline gearbox with a limited torque rating.", - model = "models/engines/linear_m.mdl", - category = "6-Speed", - weight = Gear6MW, - switch = 0.2, - maxtq = Gear6MT, - gears = 6, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.1, - [ 2 ] = 0.2, - [ 3 ] = 0.3, - [ 4 ] = 0.4, - [ 5 ] = 0.5, - [ 6 ] = -0.1, - [ -1 ] = 0.5 - } -} ) - -ACF_DefineGearbox( "6Gear-L-L", { - name = "6-Speed, Inline, Large", - desc = "Heavy duty 6 speed inline gearbox, however not as resilient as a 4 speed.", - model = "models/engines/linear_l.mdl", - category = "6-Speed", - weight = Gear6LW, - switch = 0.3, - maxtq = Gear6LT, - gears = 6, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.1, - [ 2 ] = 0.2, - [ 3 ] = 0.3, - [ 4 ] = 0.4, - [ 5 ] = 0.5, - [ 6 ] = -0.1, - [ -1 ] = 1 - } -} ) - --- Inline Dual Clutch - -ACF_DefineGearbox( "6Gear-LD-S", { - name = "6-Speed, Inline, Small, Dual Clutch", - desc = "A small and light 6 speed inline gearbox, with a limited max torque rating. The dual clutch allows you to apply power and brake each side independently\n\nThe Final Drive slider is a multiplier applied to all the other gear ratios", - model = "models/engines/linear_s.mdl", - category = "6-Speed", - weight = Gear6SW, - switch = 0.15, - maxtq = Gear6ST, - gears = 6, - doubleclutch = true, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.1, - [ 2 ] = 0.2, - [ 3 ] = 0.3, - [ 4 ] = 0.4, - [ 5 ] = 0.5, - [ 6 ] = -0.1, - [ -1 ] = 0.5 - } -} ) - -ACF_DefineGearbox( "6Gear-LD-M", { - name = "6-Speed, Inline, Medium, Dual Clutch", - desc = "A a medium duty 6 speed inline gearbox. The added gears reduce torque capacity substantially. The dual clutch allows you to apply power and brake each side independently\n\nThe Final Drive slider is a multiplier applied to all the other gear ratios", - model = "models/engines/linear_m.mdl", - category = "6-Speed", - weight = Gear6MW, - switch = 0.2, - maxtq = Gear6MT, - gears = 6, - doubleclutch = true, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.1, - [ 2 ] = 0.2, - [ 3 ] = 0.3, - [ 4 ] = 0.4, - [ 5 ] = 0.5, - [ 6 ] = -0.1, - [ -1 ] = 0.5 - } -} ) - -ACF_DefineGearbox( "6Gear-LD-L", { - name = "6-Speed, Inline, Large, Dual Clutch", - desc = "Heavy duty 6 speed inline gearbox, however not as resilient as a 4 speed. The dual clutch allows you to apply power and brake each side independently\n\nThe Final Drive slider is a multiplier applied to all the other gear ratios", - model = "models/engines/linear_l.mdl", - category = "6-Speed", - weight = Gear6LW, - switch = 0.3, - maxtq = Gear6LT, - gears = 6, - doubleclutch = true, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.1, - [ 2 ] = 0.2, - [ 3 ] = 0.3, - [ 4 ] = 0.4, - [ 5 ] = 0.5, - [ 6 ] = -0.1, - [ -1 ] = 1 - } -} ) - --- Transaxial - -ACF_DefineGearbox( "6Gear-T-S", { - name = "6-Speed, Transaxial, Small", - desc = "A small and light 6 speed gearbox, with a limited max torque rating.", - model = "models/engines/transaxial_s.mdl", - category = "6-Speed", - weight = Gear6SW, - switch = 0.15, - maxtq = Gear6ST, - gears = 6, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.1, - [ 2 ] = 0.2, - [ 3 ] = 0.3, - [ 4 ] = 0.4, - [ 5 ] = 0.5, - [ 6 ] = -0.1, - [ -1 ] = 0.5 - } -} ) - -ACF_DefineGearbox( "6Gear-T-M", { - name = "6-Speed, Transaxial, Medium", - desc = "A medium duty 6 speed gearbox with a limited torque rating.", - model = "models/engines/transaxial_m.mdl", - category = "6-Speed", - weight = Gear6MW, - switch = 0.2, - maxtq = Gear6MT, - gears = 6, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.1, - [ 2 ] = 0.2, - [ 3 ] = 0.3, - [ 4 ] = 0.4, - [ 5 ] = 0.5, - [ 6 ] = -0.1, - [ -1 ] = 0.5 - } -} ) - -ACF_DefineGearbox( "6Gear-T-L", { - name = "6-Speed, Transaxial, Large", - desc = "Heavy duty 6 speed gearbox, however not as resilient as a 4 speed.", - model = "models/engines/transaxial_l.mdl", - category = "6-Speed", - weight = Gear6LW, - switch = 0.3, - maxtq = Gear6LT, - gears = 6, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.1, - [ 2 ] = 0.2, - [ 3 ] = 0.3, - [ 4 ] = 0.4, - [ 5 ] = 0.5, - [ 6 ] = -0.1, - [ -1 ] = 1 - } -} ) - --- Transaxial Dual Clutch - -ACF_DefineGearbox( "6Gear-TD-S", { - name = "6-Speed, Transaxial, Small, Dual Clutch", - desc = "A small and light 6 speed gearbox, with a limited max torque rating. The dual clutch allows you to apply power and brake each side independently\n\nThe Final Drive slider is a multiplier applied to all the other gear ratios", - model = "models/engines/transaxial_s.mdl", - category = "6-Speed", - weight = Gear6SW, - switch = 0.15, - maxtq = Gear6ST, - gears = 6, - doubleclutch = true, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.1, - [ 2 ] = 0.2, - [ 3 ] = 0.3, - [ 4 ] = 0.4, - [ 5 ] = 0.5, - [ 6 ] = -0.1, - [ -1 ] = 0.5 - } -} ) - -ACF_DefineGearbox( "6Gear-TD-M", { - name = "6-Speed, Transaxial, Medium, Dual Clutch", - desc = "A a medium duty 6 speed gearbox. The added gears reduce torque capacity substantially. The dual clutch allows you to apply power and brake each side independently\n\nThe Final Drive slider is a multiplier applied to all the other gear ratios", - model = "models/engines/transaxial_m.mdl", - category = "6-Speed", - weight = Gear6MW, - switch = 0.2, - maxtq = Gear6MT, - gears = 6, - doubleclutch = true, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.1, - [ 2 ] = 0.2, - [ 3 ] = 0.3, - [ 4 ] = 0.4, - [ 5 ] = 0.5, - [ 6 ] = -0.1, - [ -1 ] = 0.5 - } -} ) - -ACF_DefineGearbox( "6Gear-TD-L", { - name = "6-Speed, Transaxial, Large, Dual Clutch", - desc = "Heavy duty 6 speed gearbox, however not as resilient as a 4 speed. The dual clutch allows you to apply power and brake each side independently\n\nThe Final Drive slider is a multiplier applied to all the other gear ratios", - model = "models/engines/transaxial_l.mdl", - category = "6-Speed", - weight = Gear6LW, - switch = 0.3, - maxtq = Gear6LT, - gears = 6, - doubleclutch = true, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.1, - [ 2 ] = 0.2, - [ 3 ] = 0.3, - [ 4 ] = 0.4, - [ 5 ] = 0.5, - [ 6 ] = -0.1, - [ -1 ] = 1 - } -} ) - --- Straight-through gearboxes - -ACF_DefineGearbox( "6Gear-ST-S", { - name = "6-Speed, Straight, Small", - desc = "A small and light 6 speed straight-through gearbox.", - model = "models/engines/t5small.mdl", - category = "6-Speed", - weight = math.floor(Gear6SW * StWB), - switch = 0.15, - maxtq = math.floor(Gear6ST * StTB), - gears = 6, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.1, - [ 2 ] = 0.2, - [ 3 ] = 0.3, - [ 4 ] = 0.4, - [ 5 ] = 0.5, - [ 6 ] = -0.1, - [ -1 ] = 0.5 - } -} ) - -ACF_DefineGearbox( "6Gear-ST-M", { - name = "6-Speed, Straight, Medium", - desc = "A medium 6 speed straight-through gearbox.", - model = "models/engines/t5med.mdl", - category = "6-Speed", - weight = math.floor(Gear6MW * StWB), - switch = 0.2, - maxtq = math.floor(Gear6MT * StTB), - gears = 6, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.1, - [ 2 ] = 0.2, - [ 3 ] = 0.3, - [ 4 ] = 0.4, - [ 5 ] = 0.5, - [ 6 ] = -0.1, - [ -1 ] = 0.5 - } -} ) - -ACF_DefineGearbox( "6Gear-ST-L", { - name = "6-Speed, Straight, Large", - desc = "A large 6 speed straight-through gearbox.", - model = "models/engines/t5large.mdl", - category = "6-Speed", - weight = math.floor(Gear6LW * StWB), - switch = 0.3, - maxtq = math.floor(Gear6LT * StTB), - gears = 6, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.1, - [ 2 ] = 0.2, - [ 3 ] = 0.3, - [ 4 ] = 0.4, - [ 5 ] = 0.5, - [ 6 ] = -0.1, - [ -1 ] = 0.5 - } -} ) - ACF.RegisterGearboxClass("6-Speed", { Name = "6-Speed Gearbox", CreateMenu = ACF.ManualGearboxMenu, diff --git a/lua/acf/shared/gearboxes/8-speed.lua b/lua/acf/shared/gearboxes/8-speed.lua index ae8af62f2..25ac1c188 100644 --- a/lua/acf/shared/gearboxes/8-speed.lua +++ b/lua/acf/shared/gearboxes/8-speed.lua @@ -13,367 +13,6 @@ local Gear8MT = 1000 local Gear8LT = 10000 local StTB = 1.25 --straight torque bonus multiplier --- Inline - -ACF_DefineGearbox( "8Gear-L-S", { - name = "8-Speed, Inline, Small", - desc = "A small and light 8 speed gearbox.", - model = "models/engines/linear_s.mdl", - category = "8-Speed", - weight = Gear8SW, - switch = 0.15, - maxtq = Gear8ST, - gears = 8, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.1, - [ 2 ] = 0.2, - [ 3 ] = 0.3, - [ 4 ] = 0.4, - [ 5 ] = 0.5, - [ 6 ] = 0.6, - [ 7 ] = 0.7, - [ 8 ] = -0.1, - [ -1 ] = 0.5 - } -} ) - -ACF_DefineGearbox( "8Gear-L-M", { - name = "8-Speed, Inline, Medium", - desc = "A medium duty 8 speed gearbox..", - model = "models/engines/linear_m.mdl", - category = "8-Speed", - weight = Gear8MW, - switch = 0.2, - maxtq = Gear8MT, - gears = 8, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.1, - [ 2 ] = 0.2, - [ 3 ] = 0.3, - [ 4 ] = 0.4, - [ 5 ] = 0.5, - [ 6 ] = 0.6, - [ 7 ] = 0.7, - [ 8 ] = -0.1, - [ -1 ] = 0.5 - } -} ) - -ACF_DefineGearbox( "8Gear-L-L", { - name = "8-Speed, Inline, Large", - desc = "Heavy duty 8 speed gearbox, however rather heavy.", - model = "models/engines/linear_l.mdl", - category = "8-Speed", - weight = Gear8LW, - switch = 0.3, - maxtq = Gear8LT, - gears = 8, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.1, - [ 2 ] = 0.2, - [ 3 ] = 0.3, - [ 4 ] = 0.4, - [ 5 ] = 0.5, - [ 6 ] = 0.6, - [ 7 ] = 0.7, - [ 8 ] = -0.1, - [ -1 ] = 1 - } -} ) - --- Inline Dual Clutch - -ACF_DefineGearbox( "8Gear-LD-S", { - name = "8-Speed, Inline, Small, Dual Clutch", - desc = "A small and light 8 speed gearbox The dual clutch allows you to apply power and brake each side independently\n\nThe Final Drive slider is a multiplier applied to all the other gear ratios", - model = "models/engines/linear_s.mdl", - category = "8-Speed", - weight = Gear8SW, - switch = 0.15, - maxtq = Gear8ST, - gears = 8, - doubleclutch = true, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.1, - [ 2 ] = 0.2, - [ 3 ] = 0.3, - [ 4 ] = 0.4, - [ 5 ] = 0.5, - [ 6 ] = 0.6, - [ 7 ] = 0.7, - [ 8 ] = -0.1, - [ -1 ] = 0.5 - } -} ) - -ACF_DefineGearbox( "8Gear-LD-M", { - name = "8-Speed, Inline, Medium, Dual Clutch", - desc = "A a medium duty 8 speed gearbox. The dual clutch allows you to apply power and brake each side independently\n\nThe Final Drive slider is a multiplier applied to all the other gear ratios", - model = "models/engines/linear_m.mdl", - category = "8-Speed", - weight = Gear8MW, - switch = 0.2, - maxtq = Gear8MT, - gears = 8, - doubleclutch = true, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.1, - [ 2 ] = 0.2, - [ 3 ] = 0.3, - [ 4 ] = 0.4, - [ 5 ] = 0.5, - [ 6 ] = 0.6, - [ 7 ] = 0.7, - [ 8 ] = -0.1, - [ -1 ] = 0.5 - } -} ) - -ACF_DefineGearbox( "8Gear-LD-L", { - name = "8-Speed, Inline, Large, Dual Clutch", - desc = "Heavy duty 8 speed gearbox. The dual clutch allows you to apply power and brake each side independently\n\nThe Final Drive slider is a multiplier applied to all the other gear ratios", - model = "models/engines/linear_l.mdl", - category = "8-Speed", - weight = Gear8LW, - switch = 0.3, - maxtq = Gear8LT, - gears = 8, - doubleclutch = true, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.1, - [ 2 ] = 0.2, - [ 3 ] = 0.3, - [ 4 ] = 0.4, - [ 5 ] = 0.5, - [ 6 ] = 0.6, - [ 7 ] = 0.7, - [ 8 ] = -0.1, - [ -1 ] = 1 - } -} ) - --- Transaxial - -ACF_DefineGearbox( "8Gear-T-S", { - name = "8-Speed, Transaxial, Small", - desc = "A small and light 8 speed gearbox..", - model = "models/engines/transaxial_s.mdl", - category = "8-Speed", - weight = Gear8SW, - switch = 0.15, - maxtq = Gear8ST, - gears = 8, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.1, - [ 2 ] = 0.2, - [ 3 ] = 0.3, - [ 4 ] = 0.4, - [ 5 ] = 0.5, - [ 6 ] = 0.6, - [ 7 ] = 0.7, - [ 8 ] = -0.1, - [ -1 ] = 0.5 - } -} ) - -ACF_DefineGearbox( "8Gear-T-M", { - name = "8-Speed, Transaxial, Medium", - desc = "A medium duty 8 speed gearbox..", - model = "models/engines/transaxial_m.mdl", - category = "8-Speed", - weight = Gear8MW, - switch = 0.2, - maxtq = Gear8MT, - gears = 8, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.1, - [ 2 ] = 0.2, - [ 3 ] = 0.3, - [ 4 ] = 0.4, - [ 5 ] = 0.5, - [ 6 ] = 0.6, - [ 7 ] = 0.7, - [ 8 ] = -0.1, - [ -1 ] = 0.5 - } -} ) - -ACF_DefineGearbox( "8Gear-T-L", { - name = "8-Speed, Transaxial, Large", - desc = "Heavy duty 8 speed gearbox, however rather heavy.", - model = "models/engines/transaxial_l.mdl", - category = "8-Speed", - weight = Gear8LW, - switch = 0.3, - maxtq = Gear8LT, - gears = 8, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.1, - [ 2 ] = 0.2, - [ 3 ] = 0.3, - [ 4 ] = 0.4, - [ 5 ] = 0.5, - [ 6 ] = 0.6, - [ 7 ] = 0.7, - [ 8 ] = -0.1, - [ -1 ] = 1 - } -} ) - --- Transaxial Dual Clutch - -ACF_DefineGearbox( "8Gear-TD-S", { - name = "8-Speed, Transaxial, Small, Dual Clutch", - desc = "A small and light 8 speed gearbox The dual clutch allows you to apply power and brake each side independently\n\nThe Final Drive slider is a multiplier applied to all the other gear ratios", - model = "models/engines/transaxial_s.mdl", - category = "8-Speed", - weight = Gear8SW, - switch = 0.15, - maxtq = Gear8ST, - gears = 8, - doubleclutch = true, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.1, - [ 2 ] = 0.2, - [ 3 ] = 0.3, - [ 4 ] = 0.4, - [ 5 ] = 0.5, - [ 6 ] = 0.6, - [ 7 ] = 0.7, - [ 8 ] = -0.1, - [ -1 ] = 0.5 - } -} ) - -ACF_DefineGearbox( "8Gear-TD-M", { - name = "8-Speed, Transaxial, Medium, Dual Clutch", - desc = "A a medium duty 8 speed gearbox. The dual clutch allows you to apply power and brake each side independently\n\nThe Final Drive slider is a multiplier applied to all the other gear ratios", - model = "models/engines/transaxial_m.mdl", - category = "8-Speed", - weight = Gear8MW, - switch = 0.2, - maxtq = Gear8MT, - gears = 8, - doubleclutch = true, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.1, - [ 2 ] = 0.2, - [ 3 ] = 0.3, - [ 4 ] = 0.4, - [ 5 ] = 0.5, - [ 6 ] = 0.6, - [ 7 ] = 0.7, - [ 8 ] = -0.1, - [ -1 ] = 0.5 - } -} ) - -ACF_DefineGearbox( "8Gear-TD-L", { - name = "8-Speed, Transaxial, Large, Dual Clutch", - desc = "Heavy duty 8 speed gearbox. The dual clutch allows you to apply power and brake each side independently\n\nThe Final Drive slider is a multiplier applied to all the other gear ratios", - model = "models/engines/transaxial_l.mdl", - category = "8-Speed", - weight = Gear8LW, - switch = 0.3, - maxtq = Gear8LT, - gears = 8, - doubleclutch = true, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.1, - [ 2 ] = 0.2, - [ 3 ] = 0.3, - [ 4 ] = 0.4, - [ 5 ] = 0.5, - [ 6 ] = 0.6, - [ 7 ] = 0.7, - [ 8 ] = -0.1, - [ -1 ] = 1 - } -} ) - --- Straight-through gearboxes - -ACF_DefineGearbox( "8Gear-ST-S", { - name = "8-Speed, Straight, Small", - desc = "A small and light 8 speed straight-through gearbox.", - model = "models/engines/t5small.mdl", - category = "8-Speed", - weight = math.floor(Gear8SW * StWB), - switch = 0.15, - maxtq = math.floor(Gear8ST * StTB), - gears = 8, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.1, - [ 2 ] = 0.2, - [ 3 ] = 0.3, - [ 4 ] = 0.4, - [ 5 ] = 0.5, - [ 6 ] = 0.6, - [ 7 ] = 0.7, - [ 8 ] = 0.8, - [ -1 ] = 0.5 - } -} ) - -ACF_DefineGearbox( "8Gear-ST-M", { - name = "8-Speed, Straight, Medium", - desc = "A medium 8 speed straight-through gearbox.", - model = "models/engines/t5med.mdl", - category = "8-Speed", - weight = math.floor(Gear8MW * StWB), - switch = 0.2, - maxtq = math.floor(Gear8MT * StTB), - gears = 8, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.1, - [ 2 ] = 0.2, - [ 3 ] = 0.3, - [ 4 ] = 0.4, - [ 5 ] = 0.5, - [ 6 ] = 0.6, - [ 7 ] = 0.7, - [ 8 ] = -0.1, - [ -1 ] = 0.5 - } -} ) - -ACF_DefineGearbox( "8Gear-ST-L", { - name = "8-Speed, Straight, Large", - desc = "A large 8 speed straight-through gearbox.", - model = "models/engines/t5large.mdl", - category = "8-Speed", - weight = math.floor(Gear8LW * StWB), - switch = 0.3, - maxtq = math.floor(Gear8LT * StTB), - gears = 8, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.1, - [ 2 ] = 0.2, - [ 3 ] = 0.3, - [ 4 ] = 0.4, - [ 5 ] = 0.5, - [ 6 ] = 0.6, - [ 7 ] = 0.7, - [ 8 ] = -0.1, - [ -1 ] = 0.5 - } -} ) - ACF.RegisterGearboxClass("8-Speed", { Name = "8-Speed Gearbox", CreateMenu = ACF.ManualGearboxMenu, diff --git a/lua/acf/shared/gearboxes/automatic.lua b/lua/acf/shared/gearboxes/automatic.lua deleted file mode 100644 index 137e6dc81..000000000 --- a/lua/acf/shared/gearboxes/automatic.lua +++ /dev/null @@ -1,1059 +0,0 @@ --- Automatic Gearboxes --- Weight -local wmul = 1.5 -local Gear3SW = 60 * wmul -local Gear3MW = 120 * wmul -local Gear3LW = 240 * wmul -local Gear5SW = 80 * wmul -local Gear5MW = 160 * wmul -local Gear5LW = 320 * wmul -local Gear7SW = 100 * wmul -local Gear7MW = 200 * wmul -local Gear7LW = 400 * wmul --- Torque Rating -local Gear3ST = 675 -local Gear3MT = 2125 -local Gear3LT = 10000 -local Gear5ST = 550 -local Gear5MT = 1700 -local Gear5LT = 10000 -local Gear7ST = 425 -local Gear7MT = 1250 -local Gear7LT = 10000 --- Straight through bonuses -local StWB = 0.75 --straight weight bonus mulitplier -local StTB = 1.25 --straight torque bonus multiplier --- Shift Time -local ShiftS = 0.25 -local ShiftM = 0.35 -local ShiftL = 0.5 -local blurb = "\n\nAutomatics are controlled by shifting into either forward or reverse drive. In forward drive, the automatic will choose the appropriate gearing based the upshift speed setting for each gear." -blurb = blurb .. " For climbing inclines, automatics have an input to prevent upshifts. There's also an input for adjusting the shiftpoints, if for example you're driving with less throttle and want to shift earlier." -blurb = blurb .. " However, automatics are significantly heavier than their manual counterparts, and lose a bit of output torque due to inefficiency." - ---hold gear, shift scale, less efficient --- 3 Speed --- Inline -ACF_DefineGearbox("3Gear-A-L-S", { - name = "3-Speed Auto, Inline, Small", - desc = "A small, and light 3 speed automatic inline gearbox, with a somewhat limited max torque rating" .. blurb, - model = "models/engines/linear_s.mdl", - category = "Automatic", - weight = Gear3SW, - switch = ShiftS, - maxtq = Gear3ST, - auto = true, - gears = 3, - geartable = { - [0] = 0, - [1] = 0.1, - [2] = 0.2, - [3] = 0.3, - [-2] = -0.1, --reverse - [-1] = 0.5 --final drive - } -}) - -ACF_DefineGearbox("3Gear-A-L-M", { - name = "3-Speed Auto, Inline, Medium", - desc = "A medium sized, 3 speed automatic inline gearbox" .. blurb, - model = "models/engines/linear_m.mdl", - category = "Automatic", - weight = Gear3MW, - switch = ShiftM, - maxtq = Gear3MT, - auto = true, - gears = 3, - geartable = { - [0] = 0, - [1] = 0.1, - [2] = 0.2, - [3] = 0.3, - [-2] = -0.1, - [-1] = 0.5 - } -}) - -ACF_DefineGearbox("3Gear-A-L-L", { - name = "3-Speed Auto, Inline, Large", - desc = "A large, heavy and sturdy 3 speed inline gearbox" .. blurb, - model = "models/engines/linear_l.mdl", - category = "Automatic", - weight = Gear3LW, - switch = ShiftL, - maxtq = Gear3LT, - auto = true, - gears = 3, - geartable = { - [0] = 0, - [1] = 0.1, - [2] = 0.2, - [3] = 0.3, - [-2] = -0.1, - [-1] = 1 - } -}) - --- Inline Dual Clutch -ACF_DefineGearbox("3Gear-A-LD-S", { - name = "3-Speed Auto, Inline, Small, Dual Clutch", - desc = "A small, and light 3 speed automatic inline gearbox, with a somewhat limited max torque rating" .. blurb, - model = "models/engines/linear_s.mdl", - category = "Automatic", - weight = Gear3SW, - switch = ShiftS, - maxtq = Gear3ST, - auto = true, - doubleclutch = true, - gears = 3, - geartable = { - [0] = 0, - [1] = 0.1, - [2] = 0.2, - [3] = 0.3, - [-2] = -0.1, - [-1] = 0.5 - } -}) - -ACF_DefineGearbox("3Gear-A-LD-M", { - name = "3-Speed Auto, Inline, Medium, Dual Clutch", - desc = "A medium sized, 3 speed automatic inline gearbox" .. blurb, - model = "models/engines/linear_m.mdl", - category = "Automatic", - weight = Gear3MW, - switch = ShiftM, - maxtq = Gear3MT, - auto = true, - doubleclutch = true, - gears = 3, - geartable = { - [0] = 0, - [1] = 0.1, - [2] = 0.2, - [3] = 0.3, - [-2] = -0.1, - [-1] = 0.5 - } -}) - -ACF_DefineGearbox("3Gear-A-LD-L", { - name = "3-Speed Auto, Inline, Large, Dual Clutch", - desc = "A large, heavy and sturdy 3 speed automatic inline gearbox" .. blurb, - model = "models/engines/linear_l.mdl", - category = "Automatic", - weight = Gear3LW, - switch = ShiftL, - maxtq = Gear3LT, - auto = true, - doubleclutch = true, - gears = 3, - geartable = { - [0] = 0, - [1] = 0.1, - [2] = 0.2, - [3] = 0.3, - [-2] = -0.1, - [-1] = 1 - } -}) - --- Transaxial -ACF_DefineGearbox("3Gear-A-T-S", { - name = "3-Speed Auto, Transaxial, Small", - desc = "A small, and light 3 speed automatic gearbox, with a somewhat limited max torque rating" .. blurb, - model = "models/engines/transaxial_s.mdl", - category = "Automatic", - weight = Gear3SW, - switch = ShiftS, - maxtq = Gear3ST, - auto = true, - gears = 3, - geartable = { - [0] = 0, - [1] = 0.1, - [2] = 0.2, - [3] = 0.3, - [-2] = -0.1, - [-1] = 0.5 - } -}) - -ACF_DefineGearbox("3Gear-A-T-M", { - name = "3-Speed Auto, Transaxial, Medium", - desc = "A medium sized, 3 speed automatic gearbox" .. blurb, - model = "models/engines/transaxial_m.mdl", - category = "Automatic", - weight = Gear3MW, - switch = ShiftM, - maxtq = Gear3MT, - auto = true, - gears = 3, - geartable = { - [0] = 0, - [1] = 0.1, - [2] = 0.2, - [3] = 0.3, - [-2] = -0.1, - [-1] = 0.5 - } -}) - -ACF_DefineGearbox("3Gear-A-T-L", { - name = "3-Speed Auto, Transaxial, Large", - desc = "A large, heavy and sturdy 3 speed automatic gearbox" .. blurb, - model = "models/engines/transaxial_l.mdl", - category = "Automatic", - weight = Gear3LW, - switch = ShiftL, - maxtq = Gear3LT, - auto = true, - gears = 3, - geartable = { - [0] = 0, - [1] = 0.1, - [2] = 0.2, - [3] = 0.3, - [-2] = -0.1, - [-1] = 1 - } -}) - --- Transaxial Dual Clutch -ACF_DefineGearbox("3Gear-A-TD-S", { - name = "3-Speed Auto, Transaxial, Small, Dual Clutch", - desc = "A small, and light 3 speed automatic gearbox, with a somewhat limited max torque rating" .. blurb, - model = "models/engines/transaxial_s.mdl", - category = "Automatic", - weight = Gear3SW, - switch = ShiftS, - maxtq = Gear3ST, - auto = true, - doubleclutch = true, - gears = 3, - geartable = { - [0] = 0, - [1] = 0.1, - [2] = 0.2, - [3] = 0.3, - [-2] = -0.1, - [-1] = 0.5 - } -}) - -ACF_DefineGearbox("3Gear-A-TD-M", { - name = "3-Speed Auto, Transaxial, Medium, Dual Clutch", - desc = "A medium sized, 3 speed automatic gearbox" .. blurb, - model = "models/engines/transaxial_m.mdl", - category = "Automatic", - weight = Gear3MW, - switch = ShiftM, - maxtq = Gear3MT, - auto = true, - doubleclutch = true, - gears = 3, - geartable = { - [0] = 0, - [1] = 0.1, - [2] = 0.2, - [3] = 0.3, - [-2] = -0.1, - [-1] = 0.5 - } -}) - -ACF_DefineGearbox("3Gear-A-TD-L", { - name = "3-Speed Auto, Transaxial, Large, Dual Clutch", - desc = "A large, heavy and sturdy 3 speed automatic gearbox" .. blurb, - model = "models/engines/transaxial_l.mdl", - category = "Automatic", - weight = Gear3LW, - switch = ShiftL, - maxtq = Gear3LT, - auto = true, - doubleclutch = true, - gears = 3, - geartable = { - [0] = 0, - [1] = 0.1, - [2] = 0.2, - [3] = 0.3, - [-2] = -0.1, - [-1] = 1 - } -}) - --- Straight-through gearboxes -ACF_DefineGearbox("3Gear-A-ST-S", { - name = "3-Speed Auto, Straight, Small", - desc = "A small straight-through automatic gearbox" .. blurb, - model = "models/engines/t5small.mdl", - category = "Automatic", - weight = math.floor(Gear3SW * StWB), - switch = ShiftS, - maxtq = math.floor(Gear3ST * StTB), - auto = true, - gears = 3, - geartable = { - [0] = 0, - [1] = 0.1, - [2] = 0.2, - [3] = 0.3, - [-2] = -0.1, - [-1] = 1 - } -}) - -ACF_DefineGearbox("3Gear-A-ST-M", { - name = "3-Speed Auto, Straight, Medium", - desc = "A medium sized, 3 speed automatic straight-through gearbox." .. blurb, - model = "models/engines/t5med.mdl", - category = "Automatic", - weight = math.floor(Gear3MW * StWB), - switch = ShiftM, - maxtq = math.floor(Gear3MT * StTB), - auto = true, - gears = 3, - geartable = { - [0] = 0, - [1] = 0.1, - [2] = 0.2, - [3] = 0.3, - [-2] = -0.1, - [-1] = 0.5 - } -}) - -ACF_DefineGearbox("3Gear-A-ST-L", { - name = "3-Speed Auto, Straight, Large", - desc = "A large sized, 3 speed automatic straight-through gearbox." .. blurb, - model = "models/engines/t5large.mdl", - category = "Automatic", - weight = math.floor(Gear3LW * StWB), - switch = ShiftL, - maxtq = math.floor(Gear3LT * StTB), - auto = true, - gears = 3, - geartable = { - [0] = 0, - [1] = 0.1, - [2] = 0.2, - [3] = 0.3, - [-2] = -0.1, - [-1] = 0.5 - } -}) - --- 5 Speed --- Inline -ACF_DefineGearbox("5Gear-A-L-S", { - name = "5-Speed Auto, Inline, Small", - desc = "A small, and light 5 speed automatic inline gearbox, with a somewhat limited max torque rating" .. blurb, - model = "models/engines/linear_s.mdl", - category = "Automatic", - weight = Gear5SW, - switch = ShiftS, - maxtq = Gear5ST, - auto = true, - gears = 5, - geartable = { - [0] = 0, - [1] = 0.1, - [2] = 0.2, - [3] = 0.3, - [4] = 0.4, - [5] = 0.5, - [-2] = -0.1, - [-1] = 0.5 - } -}) - -ACF_DefineGearbox("5Gear-A-L-M", { - name = "5-Speed Auto, Inline, Medium", - desc = "A medium sized, 5 speed automatic inline gearbox" .. blurb, - model = "models/engines/linear_m.mdl", - category = "Automatic", - weight = Gear5MW, - switch = ShiftM, - maxtq = Gear5MT, - auto = true, - gears = 5, - geartable = { - [0] = 0, - [1] = 0.1, - [2] = 0.2, - [3] = 0.3, - [4] = 0.4, - [5] = 0.5, - [-2] = -0.1, - [-1] = 0.5 - } -}) - -ACF_DefineGearbox("5Gear-A-L-L", { - name = "5-Speed Auto, Inline, Large", - desc = "A large, heavy and sturdy 5 speed inline gearbox" .. blurb, - model = "models/engines/linear_l.mdl", - category = "Automatic", - weight = Gear5LW, - switch = ShiftL, - maxtq = Gear5LT, - auto = true, - gears = 5, - geartable = { - [0] = 0, - [1] = 0.1, - [2] = 0.2, - [3] = 0.3, - [4] = 0.4, - [5] = 0.5, - [-2] = -0.1, - [-1] = 0.5 - } -}) - --- Inline Dual Clutch -ACF_DefineGearbox("5Gear-A-LD-S", { - name = "5-Speed Auto, Inline, Small, Dual Clutch", - desc = "A small, and light 5 speed automatic inline gearbox, with a somewhat limited max torque rating" .. blurb, - model = "models/engines/linear_s.mdl", - category = "Automatic", - weight = Gear5SW, - switch = ShiftS, - maxtq = Gear5ST, - auto = true, - doubleclutch = true, - gears = 5, - geartable = { - [0] = 0, - [1] = 0.1, - [2] = 0.2, - [3] = 0.3, - [4] = 0.4, - [5] = 0.5, - [-2] = -0.1, - [-1] = 0.5 - } -}) - -ACF_DefineGearbox("5Gear-A-LD-M", { - name = "5-Speed Auto, Inline, Medium, Dual Clutch", - desc = "A medium sized, 5 speed automatic inline gearbox" .. blurb, - model = "models/engines/linear_m.mdl", - category = "Automatic", - weight = Gear5MW, - switch = ShiftM, - maxtq = Gear5MT, - auto = true, - doubleclutch = true, - gears = 5, - geartable = { - [0] = 0, - [1] = 0.1, - [2] = 0.2, - [3] = 0.3, - [4] = 0.4, - [5] = 0.5, - [-2] = -0.1, - [-1] = 0.5 - } -}) - -ACF_DefineGearbox("5Gear-A-LD-L", { - name = "5-Speed Auto, Inline, Large, Dual Clutch", - desc = "A large, heavy and sturdy 5 speed automatic inline gearbox" .. blurb, - model = "models/engines/linear_l.mdl", - category = "Automatic", - weight = Gear5LW, - switch = ShiftL, - maxtq = Gear5LT, - auto = true, - doubleclutch = true, - gears = 5, - geartable = { - [0] = 0, - [1] = 0.1, - [2] = 0.2, - [3] = 0.3, - [4] = 0.4, - [5] = 0.5, - [-2] = -0.1, - [-1] = 0.5 - } -}) - --- Transaxial -ACF_DefineGearbox("5Gear-A-T-S", { - name = "5-Speed Auto, Transaxial, Small", - desc = "A small, and light 5 speed automatic gearbox, with a somewhat limited max torque rating" .. blurb, - model = "models/engines/transaxial_s.mdl", - category = "Automatic", - weight = Gear5SW, - switch = ShiftS, - maxtq = Gear5ST, - auto = true, - gears = 5, - geartable = { - [0] = 0, - [1] = 0.1, - [2] = 0.2, - [3] = 0.3, - [4] = 0.4, - [5] = 0.5, - [-2] = -0.1, - [-1] = 0.5 - } -}) - -ACF_DefineGearbox("5Gear-A-T-M", { - name = "5-Speed Auto, Transaxial, Medium", - desc = "A medium sized, 5 speed automatic gearbox" .. blurb, - model = "models/engines/transaxial_m.mdl", - category = "Automatic", - weight = Gear5MW, - switch = ShiftM, - maxtq = Gear5MT, - auto = true, - gears = 5, - geartable = { - [0] = 0, - [1] = 0.1, - [2] = 0.2, - [3] = 0.3, - [4] = 0.4, - [5] = 0.5, - [-2] = -0.1, - [-1] = 0.5 - } -}) - -ACF_DefineGearbox("5Gear-A-T-L", { - name = "5-Speed Auto, Transaxial, Large", - desc = "A large, heavy and sturdy 5 speed automatic gearbox" .. blurb, - model = "models/engines/transaxial_l.mdl", - category = "Automatic", - weight = Gear5LW, - switch = ShiftL, - maxtq = Gear5LT, - auto = true, - gears = 5, - geartable = { - [0] = 0, - [1] = 0.1, - [2] = 0.2, - [3] = 0.3, - [4] = 0.4, - [5] = 0.5, - [-2] = -0.1, - [-1] = 0.5 - } -}) - --- Transaxial Dual Clutch -ACF_DefineGearbox("5Gear-A-TD-S", { - name = "5-Speed Auto, Transaxial, Small, Dual Clutch", - desc = "A small, and light 5 speed automatic gearbox, with a somewhat limited max torque rating" .. blurb, - model = "models/engines/transaxial_s.mdl", - category = "Automatic", - weight = Gear5SW, - switch = ShiftS, - maxtq = Gear5ST, - auto = true, - doubleclutch = true, - gears = 5, - geartable = { - [0] = 0, - [1] = 0.1, - [2] = 0.2, - [3] = 0.3, - [4] = 0.4, - [5] = 0.5, - [-2] = -0.1, - [-1] = 0.5 - } -}) - -ACF_DefineGearbox("5Gear-A-TD-M", { - name = "5-Speed Auto, Transaxial, Medium, Dual Clutch", - desc = "A medium sized, 5 speed automatic gearbox" .. blurb, - model = "models/engines/transaxial_m.mdl", - category = "Automatic", - weight = Gear5MW, - switch = ShiftM, - maxtq = Gear5MT, - auto = true, - doubleclutch = true, - gears = 5, - geartable = { - [0] = 0, - [1] = 0.1, - [2] = 0.2, - [3] = 0.3, - [4] = 0.4, - [5] = 0.5, - [-2] = -0.1, - [-1] = 0.5 - } -}) - -ACF_DefineGearbox("5Gear-A-TD-L", { - name = "5-Speed Auto, Transaxial, Large, Dual Clutch", - desc = "A large, heavy and sturdy 5 speed automatic gearbox" .. blurb, - model = "models/engines/transaxial_l.mdl", - category = "Automatic", - weight = Gear5LW, - switch = ShiftL, - maxtq = Gear5LT, - auto = true, - doubleclutch = true, - gears = 5, - geartable = { - [0] = 0, - [1] = 0.1, - [2] = 0.2, - [3] = 0.3, - [4] = 0.4, - [5] = 0.5, - [-2] = -0.1, - [-1] = 0.5 - } -}) - --- Straight-through gearboxes -ACF_DefineGearbox("5Gear-A-ST-S", { - name = "5-Speed Auto, Straight, Small", - desc = "A small straight-through automatic gearbox" .. blurb, - model = "models/engines/t5small.mdl", - category = "Automatic", - weight = math.floor(Gear5SW * StWB), - switch = ShiftS, - maxtq = math.floor(Gear5ST * StTB), - auto = true, - gears = 5, - geartable = { - [0] = 0, - [1] = 0.1, - [2] = 0.2, - [3] = 0.3, - [4] = 0.4, - [5] = 0.5, - [-2] = -0.1, - [-1] = 0.5 - } -}) - -ACF_DefineGearbox("5Gear-A-ST-M", { - name = "5-Speed Auto, Straight, Medium", - desc = "A medium sized, 5 speed automatic straight-through gearbox." .. blurb, - model = "models/engines/t5med.mdl", - category = "Automatic", - weight = math.floor(Gear5MW * StWB), - switch = ShiftM, - maxtq = math.floor(Gear5MT * StTB), - auto = true, - gears = 5, - geartable = { - [0] = 0, - [1] = 0.1, - [2] = 0.2, - [3] = 0.3, - [4] = 0.4, - [5] = 0.5, - [-2] = -0.1, - [-1] = 0.5 - } -}) - -ACF_DefineGearbox("5Gear-A-ST-L", { - name = "5-Speed Auto, Straight, Large", - desc = "A large sized, 5 speed automatic straight-through gearbox." .. blurb, - model = "models/engines/t5large.mdl", - category = "Automatic", - weight = math.floor(Gear5LW * StWB), - switch = ShiftL, - maxtq = math.floor(Gear5LT * StTB), - auto = true, - gears = 5, - geartable = { - [0] = 0, - [1] = 0.1, - [2] = 0.2, - [3] = 0.3, - [4] = 0.4, - [5] = 0.5, - [-2] = -0.1, - [-1] = 0.5 - } -}) - --- 7 Speed --- Inline -ACF_DefineGearbox("7Gear-A-L-S", { - name = "7-Speed Auto, Inline, Small", - desc = "A small, and light 7 speed automatic inline gearbox, with a somewhat limited max torque rating" .. blurb, - model = "models/engines/linear_s.mdl", - category = "Automatic", - weight = Gear7SW, - switch = ShiftS, - maxtq = Gear7ST, - auto = true, - gears = 7, - geartable = { - [0] = 0, - [1] = 0.1, - [2] = 0.2, - [3] = 0.3, - [4] = 0.4, - [5] = 0.5, - [6] = 0.6, - [7] = 0.7, - [-2] = -0.1, - [-1] = 0.5 - } -}) - -ACF_DefineGearbox("7Gear-A-L-M", { - name = "7-Speed Auto, Inline, Medium", - desc = "A medium sized, 7 speed automatic inline gearbox" .. blurb, - model = "models/engines/linear_m.mdl", - category = "Automatic", - weight = Gear7MW, - switch = ShiftM, - maxtq = Gear7MT, - auto = true, - gears = 7, - geartable = { - [0] = 0, - [1] = 0.1, - [2] = 0.2, - [3] = 0.3, - [4] = 0.4, - [5] = 0.5, - [6] = 0.6, - [7] = 0.7, - [-2] = -0.1, - [-1] = 0.5 - } -}) - -ACF_DefineGearbox("7Gear-A-L-L", { - name = "7-Speed Auto, Inline, Large", - desc = "A large, heavy and sturdy 7 speed inline gearbox" .. blurb, - model = "models/engines/linear_l.mdl", - category = "Automatic", - weight = Gear7LW, - switch = ShiftL, - maxtq = Gear7LT, - auto = true, - gears = 7, - geartable = { - [0] = 0, - [1] = 0.1, - [2] = 0.2, - [3] = 0.3, - [4] = 0.4, - [5] = 0.5, - [6] = 0.6, - [7] = 0.7, - [-2] = -0.1, - [-1] = 0.5 - } -}) - --- Inline Dual Clutch -ACF_DefineGearbox("7Gear-A-LD-S", { - name = "7-Speed Auto, Inline, Small, Dual Clutch", - desc = "A small, and light 7 speed automatic inline gearbox, with a somewhat limited max torque rating" .. blurb, - model = "models/engines/linear_s.mdl", - category = "Automatic", - weight = Gear7SW, - switch = ShiftS, - maxtq = Gear7ST, - auto = true, - doubleclutch = true, - gears = 7, - geartable = { - [0] = 0, - [1] = 0.1, - [2] = 0.2, - [3] = 0.3, - [4] = 0.4, - [5] = 0.5, - [6] = 0.6, - [7] = 0.7, - [-2] = -0.1, - [-1] = 0.5 - } -}) - -ACF_DefineGearbox("7Gear-A-LD-M", { - name = "7-Speed Auto, Inline, Medium, Dual Clutch", - desc = "A medium sized, 7 speed automatic inline gearbox" .. blurb, - model = "models/engines/linear_m.mdl", - category = "Automatic", - weight = Gear7MW, - switch = ShiftM, - maxtq = Gear7MT, - auto = true, - doubleclutch = true, - gears = 7, - geartable = { - [0] = 0, - [1] = 0.1, - [2] = 0.2, - [3] = 0.3, - [4] = 0.4, - [5] = 0.5, - [6] = 0.6, - [7] = 0.7, - [-2] = -0.1, - [-1] = 0.5 - } -}) - -ACF_DefineGearbox("7Gear-A-LD-L", { - name = "7-Speed Auto, Inline, Large, Dual Clutch", - desc = "A large, heavy and sturdy 7 speed automatic inline gearbox" .. blurb, - model = "models/engines/linear_l.mdl", - category = "Automatic", - weight = Gear7LW, - switch = ShiftL, - maxtq = Gear7LT, - auto = true, - doubleclutch = true, - gears = 7, - geartable = { - [0] = 0, - [1] = 0.1, - [2] = 0.2, - [3] = 0.3, - [4] = 0.4, - [5] = 0.5, - [6] = 0.6, - [7] = 0.7, - [-2] = -0.1, - [-1] = 0.5 - } -}) - --- Transaxial -ACF_DefineGearbox("7Gear-A-T-S", { - name = "7-Speed Auto, Transaxial, Small", - desc = "A small, and light 7 speed automatic gearbox, with a somewhat limited max torque rating" .. blurb, - model = "models/engines/transaxial_s.mdl", - category = "Automatic", - weight = Gear7SW, - switch = ShiftS, - maxtq = Gear7ST, - auto = true, - gears = 7, - geartable = { - [0] = 0, - [1] = 0.1, - [2] = 0.2, - [3] = 0.3, - [4] = 0.4, - [5] = 0.5, - [6] = 0.6, - [7] = 0.7, - [-2] = -0.1, - [-1] = 0.5 - } -}) - -ACF_DefineGearbox("7Gear-A-T-M", { - name = "7-Speed Auto, Transaxial, Medium", - desc = "A medium sized, 7 speed automatic gearbox" .. blurb, - model = "models/engines/transaxial_m.mdl", - category = "Automatic", - weight = Gear7MW, - switch = ShiftM, - maxtq = Gear7MT, - auto = true, - gears = 7, - geartable = { - [0] = 0, - [1] = 0.1, - [2] = 0.2, - [3] = 0.3, - [4] = 0.4, - [5] = 0.5, - [6] = 0.6, - [7] = 0.7, - [-2] = -0.1, - [-1] = 0.5 - } -}) - -ACF_DefineGearbox("7Gear-A-T-L", { - name = "7-Speed Auto, Transaxial, Large", - desc = "A large, heavy and sturdy 7 speed automatic gearbox" .. blurb, - model = "models/engines/transaxial_l.mdl", - category = "Automatic", - weight = Gear7LW, - switch = ShiftL, - maxtq = Gear7LT, - auto = true, - gears = 7, - geartable = { - [0] = 0, - [1] = 0.1, - [2] = 0.2, - [3] = 0.3, - [4] = 0.4, - [5] = 0.5, - [6] = 0.6, - [7] = 0.7, - [-2] = -0.1, - [-1] = 0.5 - } -}) - --- Transaxial Dual Clutch -ACF_DefineGearbox("7Gear-A-TD-S", { - name = "7-Speed Auto, Transaxial, Small, Dual Clutch", - desc = "A small, and light 7 speed automatic gearbox, with a somewhat limited max torque rating" .. blurb, - model = "models/engines/transaxial_s.mdl", - category = "Automatic", - weight = Gear7SW, - switch = ShiftS, - maxtq = Gear7ST, - auto = true, - doubleclutch = true, - gears = 7, - geartable = { - [0] = 0, - [1] = 0.1, - [2] = 0.2, - [3] = 0.3, - [4] = 0.4, - [5] = 0.5, - [6] = 0.6, - [7] = 0.7, - [-2] = -0.1, - [-1] = 0.5 - } -}) - -ACF_DefineGearbox("7Gear-A-TD-M", { - name = "7-Speed Auto, Transaxial, Medium, Dual Clutch", - desc = "A medium sized, 7 speed automatic gearbox" .. blurb, - model = "models/engines/transaxial_m.mdl", - category = "Automatic", - weight = Gear7MW, - switch = ShiftM, - maxtq = Gear7MT, - auto = true, - doubleclutch = true, - gears = 7, - geartable = { - [0] = 0, - [1] = 0.1, - [2] = 0.2, - [3] = 0.3, - [4] = 0.4, - [5] = 0.5, - [6] = 0.6, - [7] = 0.7, - [-2] = -0.1, - [-1] = 0.5 - } -}) - -ACF_DefineGearbox("7Gear-A-TD-L", { - name = "7-Speed Auto, Transaxial, Large, Dual Clutch", - desc = "A large, heavy and sturdy 7 speed automatic gearbox" .. blurb, - model = "models/engines/transaxial_l.mdl", - category = "Automatic", - weight = Gear7LW, - switch = ShiftL, - maxtq = Gear7LT, - auto = true, - doubleclutch = true, - gears = 7, - geartable = { - [0] = 0, - [1] = 0.1, - [2] = 0.2, - [3] = 0.3, - [4] = 0.4, - [5] = 0.5, - [6] = 0.6, - [7] = 0.7, - [-2] = -0.1, - [-1] = 0.5 - } -}) - --- Straight-through gearboxes -ACF_DefineGearbox("7Gear-A-ST-S", { - name = "7-Speed Auto, Straight, Small", - desc = "A small straight-through automatic gearbox" .. blurb, - model = "models/engines/t5small.mdl", - category = "Automatic", - weight = math.floor(Gear7SW * StWB), - switch = ShiftS, - maxtq = math.floor(Gear7ST * StTB), - auto = true, - gears = 7, - geartable = { - [0] = 0, - [1] = 0.1, - [2] = 0.2, - [3] = 0.3, - [4] = 0.4, - [5] = 0.5, - [6] = 0.6, - [7] = 0.7, - [-2] = -0.1, - [-1] = 0.5 - } -}) - -ACF_DefineGearbox("7Gear-A-ST-M", { - name = "7-Speed Auto, Straight, Medium", - desc = "A medium sized, 7 speed automatic straight-through gearbox." .. blurb, - model = "models/engines/t5med.mdl", - category = "Automatic", - weight = math.floor(Gear7MW * StWB), - switch = ShiftM, - maxtq = math.floor(Gear7MT * StTB), - auto = true, - gears = 7, - geartable = { - [0] = 0, - [1] = 0.1, - [2] = 0.2, - [3] = 0.3, - [4] = 0.4, - [5] = 0.5, - [6] = 0.6, - [7] = 0.7, - [-2] = -0.1, - [-1] = 0.5 - } -}) - -ACF_DefineGearbox("7Gear-A-ST-L", { - name = "7-Speed Auto, Straight, Large", - desc = "A large sized, 7 speed automatic straight-through gearbox." .. blurb, - model = "models/engines/t5large.mdl", - category = "Automatic", - weight = math.floor(Gear7LW * StWB), - switch = ShiftL, - maxtq = math.floor(Gear7LT * StTB), - auto = true, - gears = 7, - geartable = { - [0] = 0, - [1] = 0.1, - [2] = 0.2, - [3] = 0.3, - [4] = 0.4, - [5] = 0.5, - [6] = 0.6, - [7] = 0.7, - [-2] = -0.1, - [-1] = 0.5 - } -}) \ No newline at end of file diff --git a/lua/acf/shared/gearboxes/clutch.lua b/lua/acf/shared/gearboxes/clutch.lua index 97681f4bb..df9b7c6e8 100644 --- a/lua/acf/shared/gearboxes/clutch.lua +++ b/lua/acf/shared/gearboxes/clutch.lua @@ -16,76 +16,6 @@ local CLT = 8000 -- general description local CDesc = "A standalone clutch for when a full size gearbox is unnecessary or too long." --- Straight-through - -ACF_DefineGearbox( "Clutch-S-T", { - name = "Clutch, Straight, Tiny", - desc = CDesc, - model = "models/engines/flywheelclutcht.mdl", - category = "Clutch", - weight = CTW, - parentable = true, - switch = 0.1, - maxtq = CTT, - gears = 0, - geartable = { - [ 0 ] = 1, - [ 1 ] = 1, - [ -1 ] = 1 - } -} ) - -ACF_DefineGearbox( "Clutch-S-S", { - name = "Clutch, Straight, Small", - desc = CDesc, - model = "models/engines/flywheelclutchs.mdl", - category = "Clutch", - weight = CSW, - parentable = true, - switch = 0.15, - maxtq = CST, - gears = 0, - geartable = { - [ 0 ] = 1, - [ 1 ] = 1, - [ -1 ] = 1 - } -} ) - -ACF_DefineGearbox( "Clutch-S-M", { - name = "Clutch, Straight, Medium", - desc = CDesc, - model = "models/engines/flywheelclutchm.mdl", - category = "Clutch", - weight = CMW, - parentable = true, - switch = 0.2, - maxtq = CMT, - gears = 0, - geartable = { - [ 0 ] = 1, - [ 1 ] = 1, - [ -1 ] = 1 - } -} ) - -ACF_DefineGearbox( "Clutch-S-L", { - name = "Clutch, Straight, Large", - desc = CDesc, - model = "models/engines/flywheelclutchb.mdl", - category = "Clutch", - weight = CLW, - parentable = true, - switch = 0.3, - maxtq = CLT, - gears = 0, - geartable = { - [ 0 ] = 1, - [ 1 ] = 1, - [ -1 ] = 1 - } -} ) - ACF.RegisterGearboxClass("Clutch", { Name = "Clutch", CreateMenu = ACF.ManualGearboxMenu, diff --git a/lua/acf/shared/gearboxes/cvt.lua b/lua/acf/shared/gearboxes/cvt.lua index b697f5e5e..1675954ab 100644 --- a/lua/acf/shared/gearboxes/cvt.lua +++ b/lua/acf/shared/gearboxes/cvt.lua @@ -9,319 +9,6 @@ local GearCVTST = 175 local GearCVTMT = 650 local GearCVTLT = 6000 local StTB = 1.25 --straight torque bonus multiplier --- general description -local CVTDesc = "\n\nA CVT will adjust the ratio its first gear to keep an engine within a target rpm range, allowing constant peak performance. However, this comes at the cost of increased weight and limited torque ratings." - --- Inline -ACF_DefineGearbox("CVT-L-S", { - name = "CVT, Inline, Small", - desc = "A light duty inline CVT." .. CVTDesc, - model = "models/engines/linear_s.mdl", - category = "CVT", - weight = GearCVTSW, - switch = 0.15, - maxtq = GearCVTST, - gears = 2, - cvt = true, - geartable = { - [-3] = 3000, --target min rpm - [-2] = 5000, --target max rpm - [-1] = 1, --final drive - [0] = 0, - [1] = 0, - [2] = -0.1 - } -}) - -ACF_DefineGearbox("CVT-L-M", { - name = "CVT, Inline, Medium", - desc = "A medium inline CVT." .. CVTDesc, - model = "models/engines/linear_m.mdl", - category = "CVT", - weight = GearCVTMW, - switch = 0.2, - maxtq = GearCVTMT, - gears = 2, - cvt = true, - geartable = { - [-3] = 3000, --target min rpm - [-2] = 5000, --target max rpm - [-1] = 1, --final drive - [0] = 0, - [1] = 0, - [2] = -0.1 - } -}) - -ACF_DefineGearbox("CVT-L-L", { - name = "CVT, Inline, Large", - desc = "A massive inline CVT designed for high torque applications." .. CVTDesc, - model = "models/engines/linear_l.mdl", - category = "CVT", - weight = GearCVTLW, - switch = 0.3, - maxtq = GearCVTLT, - gears = 2, - cvt = true, - geartable = { - [-3] = 3000, --target min rpm - [-2] = 5000, --target max rpm - [-1] = 1, --final drive - [0] = 0, - [1] = 0, - [2] = -0.1 - } -}) - --- Inline Dual Clutch -ACF_DefineGearbox("CVT-LD-S", { - name = "CVT, Inline, Small, Dual Clutch", - desc = "A light duty inline CVT. The dual clutch allows you to apply power and brake each side independently." .. CVTDesc, - model = "models/engines/linear_s.mdl", - category = "CVT", - weight = GearCVTSW, - switch = 0.15, - maxtq = GearCVTST, - gears = 2, - doubleclutch = true, - cvt = true, - geartable = { - [-3] = 3000, --target min rpm - [-2] = 5000, --target max rpm - [-1] = 1, --final drive - [0] = 0, - [1] = 0, - [2] = -0.1 - } -}) - -ACF_DefineGearbox("CVT-LD-M", { - name = "CVT, Inline, Medium, Dual Clutch", - desc = "A medium inline CVT. The dual clutch allows you to apply power and brake each side independently." .. CVTDesc, - model = "models/engines/linear_m.mdl", - category = "CVT", - weight = GearCVTMW, - switch = 0.2, - maxtq = GearCVTMT, - gears = 2, - doubleclutch = true, - cvt = true, - geartable = { - [-3] = 3000, --target min rpm - [-2] = 5000, --target max rpm - [-1] = 1, --final drive - [0] = 0, - [1] = 0, - [2] = -0.1 - } -}) - -ACF_DefineGearbox("CVT-LD-L", { - name = "CVT, Inline, Large, Dual Clutch", - desc = "A massive inline CVT designed for high torque applications. The dual clutch allows you to apply power and brake each side independently." .. CVTDesc, - model = "models/engines/linear_l.mdl", - category = "CVT", - weight = GearCVTLW, - switch = 0.3, - maxtq = GearCVTLT, - gears = 2, - doubleclutch = true, - cvt = true, - geartable = { - [-3] = 3000, --target min rpm - [-2] = 5000, --target max rpm - [-1] = 1, --final drive - [0] = 0, - [1] = 0, - [2] = -0.1 - } -}) - --- Transaxial -ACF_DefineGearbox("CVT-T-S", { - name = "CVT, Transaxial, Small", - desc = "A light duty CVT." .. CVTDesc, - model = "models/engines/transaxial_s.mdl", - category = "CVT", - weight = GearCVTSW, - switch = 0.15, - maxtq = GearCVTST, - gears = 2, - cvt = true, - geartable = { - [-3] = 3000, --target min rpm - [-2] = 5000, --target max rpm - [-1] = 1, --final drive - [0] = 0, - [1] = 0, - [2] = -0.1 - } -}) - -ACF_DefineGearbox("CVT-T-M", { - name = "CVT, Transaxial, Medium", - desc = "A medium CVT." .. CVTDesc, - model = "models/engines/transaxial_m.mdl", - category = "CVT", - weight = GearCVTMW, - switch = 0.2, - maxtq = GearCVTMT, - gears = 2, - cvt = true, - geartable = { - [-3] = 3000, --target min rpm - [-2] = 5000, --target max rpm - [-1] = 1, --final drive - [0] = 0, - [1] = 0, - [2] = -0.1 - } -}) - -ACF_DefineGearbox("CVT-T-L", { - name = "CVT, Transaxial, Large", - desc = "A massive CVT designed for high torque applications." .. CVTDesc, - model = "models/engines/transaxial_l.mdl", - category = "CVT", - weight = GearCVTLW, - switch = 0.3, - maxtq = GearCVTLT, - gears = 2, - cvt = true, - geartable = { - [-3] = 3000, --target min rpm - [-2] = 5000, --target max rpm - [-1] = 1, --final drive - [0] = 0, - [1] = 0, - [2] = -0.1 - } -}) - --- Transaxial Dual Clutch -ACF_DefineGearbox("CVT-TD-S", { - name = "CVT, Transaxial, Small, Dual Clutch", - desc = "A light duty CVT. The dual clutch allows you to apply power and brake each side independently." .. CVTDesc, - model = "models/engines/transaxial_s.mdl", - category = "CVT", - weight = GearCVTSW, - switch = 0.15, - maxtq = GearCVTST, - gears = 2, - doubleclutch = true, - cvt = true, - geartable = { - [-3] = 3000, --target min rpm - [-2] = 5000, --target max rpm - [-1] = 1, --final drive - [0] = 0, - [1] = 0, - [2] = -0.1 - } -}) - -ACF_DefineGearbox("CVT-TD-M", { - name = "CVT, Transaxial, Medium, Dual Clutch", - desc = "A medium CVT. The dual clutch allows you to apply power and brake each side independently." .. CVTDesc, - model = "models/engines/transaxial_m.mdl", - category = "CVT", - weight = GearCVTMW, - switch = 0.2, - maxtq = GearCVTMT, - gears = 2, - doubleclutch = true, - cvt = true, - geartable = { - [-3] = 3000, --target min rpm - [-2] = 5000, --target max rpm - [-1] = 1, --final drive - [0] = 0, - [1] = 0, - [2] = -0.1 - } -}) - -ACF_DefineGearbox("CVT-TD-L", { - name = "CVT, Transaxial, Large, Dual Clutch", - desc = "A massive CVT designed for high torque applications. The dual clutch allows you to apply power and brake each side independently." .. CVTDesc, - model = "models/engines/transaxial_l.mdl", - category = "CVT", - weight = GearCVTLW, - switch = 0.3, - maxtq = GearCVTLT, - gears = 2, - doubleclutch = true, - cvt = true, - geartable = { - [-3] = 3000, --target min rpm - [-2] = 5000, --target max rpm - [-1] = 1, --final drive - [0] = 0, - [1] = 0, - [2] = -0.1 - } -}) - --- Straight-through gearboxes -ACF_DefineGearbox("CVT-ST-S", { - name = "CVT, Straight, Small", - desc = "A light duty straight-through CVT." .. CVTDesc, - model = "models/engines/t5small.mdl", - category = "CVT", - weight = math.floor(GearCVTSW * StWB), - switch = 0.15, - maxtq = math.floor(GearCVTST * StTB), - gears = 2, - cvt = true, - geartable = { - [-3] = 3000, --target min rpm - [-2] = 5000, --target max rpm - [-1] = 1, --final drive - [0] = 0, - [1] = 0, - [2] = -0.1 - } -}) - -ACF_DefineGearbox("CVT-ST-M", { - name = "CVT, Straight, Medium", - desc = "A medium straight-through CVT." .. CVTDesc, - model = "models/engines/t5med.mdl", - category = "CVT", - weight = math.floor(GearCVTMW * StWB), - switch = 0.2, - maxtq = math.floor(GearCVTMT * StTB), - gears = 2, - cvt = true, - geartable = { - [-3] = 3000, --target min rpm - [-2] = 5000, --target max rpm - [-1] = 1, --final drive - [0] = 0, - [1] = 0, - [2] = -0.1 - } -}) - -ACF_DefineGearbox("CVT-ST-L", { - name = "CVT, Straight, Large", - desc = "A massive straight-through CVT designed for high torque applications." .. CVTDesc, - model = "models/engines/t5large.mdl", - category = "CVT", - weight = math.floor(GearCVTLW * StWB), - switch = 0.3, - maxtq = math.floor(GearCVTLT * StTB), - gears = 2, - cvt = true, - geartable = { - [-3] = 3000, --target min rpm - [-2] = 5000, --target max rpm - [-1] = 1, --final drive - [0] = 0, - [1] = 0, - [2] = -0.1 - } -}) local function InitGearbox(Gearbox) local Gears = Gearbox.Gears diff --git a/lua/acf/shared/gearboxes/differential.lua b/lua/acf/shared/gearboxes/differential.lua index f1607826c..de89fe2a7 100644 --- a/lua/acf/shared/gearboxes/differential.lua +++ b/lua/acf/shared/gearboxes/differential.lua @@ -5,224 +5,6 @@ local Gear1SW = 10 local Gear1MW = 20 local Gear1LW = 40 --- Inline - -ACF_DefineGearbox( "1Gear-L-S", { - name = "Differential, Inline, Small", - desc = "Small differential, used to connect power from gearbox to wheels", - model = "models/engines/linear_s.mdl", - category = "Differential", - weight = Gear1SW, - parentable = true, - switch = 0.3, - maxtq = 25000, - gears = 1, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.5, - [ -1 ] = 0.5 - } -} ) - -ACF_DefineGearbox( "1Gear-L-M", { - name = "Differential, Inline, Medium", - desc = "Medium duty differential", - model = "models/engines/linear_m.mdl", - category = "Differential", - weight = Gear1MW, - parentable = true, - switch = 0.4, - maxtq = 50000, - gears = 1, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.5, - [ -1 ] = 0.5 - } -} ) - -ACF_DefineGearbox( "1Gear-L-L", { - name = "Differential, Inline, Large", - desc = "Heavy duty differential, for the heaviest of engines", - model = "models/engines/linear_l.mdl", - category = "Differential", - weight = Gear1LW, - parentable = true, - switch = 0.6, - maxtq = 100000, - gears = 1, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.5, - [ -1 ] = 1 - } -} ) - --- Inline Dual Clutch - -ACF_DefineGearbox( "1Gear-LD-S", { - name = "Differential, Inline, Small, Dual Clutch", - desc = "Small differential, used to connect power from gearbox to wheels", - model = "models/engines/linear_s.mdl", - category = "Differential", - weight = Gear1SW, - parentable = true, - switch = 0.3, - maxtq = 25000, - gears = 1, - doubleclutch = true, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.5, - [ -1 ] = 0.5 - } -} ) - -ACF_DefineGearbox( "1Gear-LD-M", { - name = "Differential, Inline, Medium, Dual Clutch", - desc = "Medium duty differential", - model = "models/engines/linear_m.mdl", - category = "Differential", - weight = Gear1MW, - parentable = true, - switch = 0.4, - maxtq = 50000, - gears = 1, - doubleclutch = true, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.5, - [ -1 ] = 0.5 - } -} ) - -ACF_DefineGearbox( "1Gear-LD-L", { - name = "Differential, Inline, Large, Dual Clutch", - desc = "Heavy duty differential, for the heaviest of engines", - model = "models/engines/linear_l.mdl", - category = "Differential", - weight = Gear1LW, - parentable = true, - switch = 0.6, - maxtq = 100000, - gears = 1, - doubleclutch = true, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.5, - [ -1 ] = 1 - } -} ) - --- Transaxial - -ACF_DefineGearbox( "1Gear-T-S", { - name = "Differential, Small", - desc = "Small differential, used to connect power from gearbox to wheels", - model = "models/engines/transaxial_s.mdl", - category = "Differential", - weight = Gear1SW, - parentable = true, - switch = 0.3, - maxtq = 25000, - gears = 1, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.5, - [ -1 ] = 0.5 - } -} ) - -ACF_DefineGearbox( "1Gear-T-M", { - name = "Differential, Medium", - desc = "Medium duty differential", - model = "models/engines/transaxial_m.mdl", - category = "Differential", - weight = Gear1MW, - parentable = true, - switch = 0.4, - maxtq = 50000, - gears = 1, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.5, - [ -1 ] = 0.5 - } -} ) - -ACF_DefineGearbox( "1Gear-T-L", { - name = "Differential, Large", - desc = "Heavy duty differential, for the heaviest of engines", - model = "models/engines/transaxial_l.mdl", - category = "Differential", - parentable = true, - weight = Gear1LW, - switch = 0.6, - maxtq = 100000, - gears = 1, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.5, - [ -1 ] = 1 - } -} ) - --- Transaxial Dual Clutch - -ACF_DefineGearbox( "1Gear-TD-S", { - name = "Differential, Small, Dual Clutch", - desc = "Small differential, used to connect power from gearbox to wheels", - model = "models/engines/transaxial_s.mdl", - category = "Differential", - weight = Gear1SW, - parentable = true, - switch = 0.3, - maxtq = 25000, - gears = 1, - doubleclutch = true, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.5, - [ -1 ] = 0.5 - } -} ) - -ACF_DefineGearbox( "1Gear-TD-M", { - name = "Differential, Medium, Dual Clutch", - desc = "Medium duty differential", - model = "models/engines/transaxial_m.mdl", - category = "Differential", - weight = Gear1MW, - parentable = true, - switch = 0.4, - maxtq = 50000, - gears = 1, - doubleclutch = true, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.5, - [ -1 ] = 0.5 - } -} ) - -ACF_DefineGearbox( "1Gear-TD-L", { - name = "Differential, Large, Dual Clutch", - desc = "Heavy duty differential, for the heaviest of engines", - model = "models/engines/transaxial_l.mdl", - category = "Differential", - weight = Gear1LW, - parentable = true, - switch = 0.6, - maxtq = 100000, - gears = 1, - doubleclutch = true, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.5, - [ -1 ] = 1 - } -} ) - ACF.RegisterGearboxClass("Differential", { Name = "Differential", CreateMenu = ACF.ManualGearboxMenu, diff --git a/lua/acf/shared/gearboxes/doublediff.lua b/lua/acf/shared/gearboxes/doublediff.lua index b346e2867..ab08e2bac 100644 --- a/lua/acf/shared/gearboxes/doublediff.lua +++ b/lua/acf/shared/gearboxes/doublediff.lua @@ -7,66 +7,6 @@ local GearDDLW = 180 local GearDDST = 20000 local GearDDMT = 45000 local GearDDLT = 100000 --- general description -local DDDesc = "\n\nA Double Differential transmission allows for a multitude of radii as well as a neutral steer." - --- Inline -ACF_DefineGearbox("DoubleDiff-T-S", { - name = "Double Differential, Small", - desc = "A light duty regenerative steering transmission." .. DDDesc, - model = "models/engines/transaxial_s.mdl", - category = "Regenerative Steering", - weight = GearDDSW, - parentable = true, - switch = 0.2, - maxtq = GearDDST, - gears = 1, - doublediff = true, - doubleclutch = true, - geartable = { - [0] = 0, - [1] = 1, - [-1] = 1 - } -}) - -ACF_DefineGearbox("DoubleDiff-T-M", { - name = "Double Differential, Medium", - desc = "A medium regenerative steering transmission." .. DDDesc, - model = "models/engines/transaxial_m.mdl", - category = "Regenerative Steering", - weight = GearDDMW, - parentable = true, - switch = 0.35, - maxtq = GearDDMT, - gears = 1, - doublediff = true, - doubleclutch = true, - geartable = { - [0] = 0, - [1] = 1, - [-1] = 1 - } -}) - -ACF_DefineGearbox("DoubleDiff-T-L", { - name = "Double Differential, Large", - desc = "A heavy regenerative steering transmission." .. DDDesc, - model = "models/engines/transaxial_l.mdl", - category = "Regenerative Steering", - weight = GearDDLW, - parentable = true, - switch = 0.5, - maxtq = GearDDLT, - gears = 1, - doublediff = true, - doubleclutch = true, - geartable = { - [0] = 0, - [1] = 1, - [-1] = 1 - } -}) local function InitGearbox(Gearbox) Gearbox.DoubleDiff = true diff --git a/lua/acf/shared/gearboxes/transfer.lua b/lua/acf/shared/gearboxes/transfer.lua index 2366563d4..578ddafc9 100644 --- a/lua/acf/shared/gearboxes/transfer.lua +++ b/lua/acf/shared/gearboxes/transfer.lua @@ -5,124 +5,6 @@ local Gear2SW = 20 local Gear2MW = 40 local Gear2LW = 80 --- Inline - -ACF_DefineGearbox( "2Gear-L-S", { - name = "Transfer case, Inline, Small", - desc = "2 speed gearbox, useful for low/high range and tank turning", - model = "models/engines/linear_s.mdl", - category = "Transfer", - weight = Gear2SW, - parentable = true, - switch = 0.3, - maxtq = 25000, - gears = 2, - doubleclutch = true, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.5, - [ 2 ] = -0.5, - [ -1 ] = 0.5 - } -} ) - -ACF_DefineGearbox( "2Gear-L-M", { - name = "Transfer case, Inline, Medium", - desc = "2 speed gearbox, useful for low/high range and tank turning", - model = "models/engines/linear_m.mdl", - category = "Transfer", - weight = Gear2MW, - parentable = true, - switch = 0.4, - maxtq = 50000, - gears = 2, - doubleclutch = true, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.5, - [ 2 ] = -0.5, - [ -1 ] = 0.5 - } -} ) - -ACF_DefineGearbox( "2Gear-L-L", { - name = "Transfer case, Inline, Large", - desc = "2 speed gearbox, useful for low/high range and tank turning", - model = "models/engines/linear_l.mdl", - category = "Transfer", - weight = Gear2LW, - parentable = true, - switch = 0.6, - maxtq = 100000, - gears = 2, - doubleclutch = true, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.5, - [ 2 ] = -0.5, - [ -1 ] = 1 - } -} ) - --- Transaxial - -ACF_DefineGearbox( "2Gear-T-S", { - name = "Transfer case, Small", - desc = "2 speed gearbox, useful for low/high range and tank turning", - model = "models/engines/transaxial_s.mdl", - category = "Transfer", - weight = Gear2SW, - parentable = true, - switch = 0.3, - maxtq = 25000, - gears = 2, - doubleclutch = true, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.5, - [ 2 ] = -0.5, - [ -1 ] = 0.5 - } -} ) - -ACF_DefineGearbox( "2Gear-T-M", { - name = "Transfer case, Medium", - desc = "2 speed gearbox, useful for low/high range and tank turning", - model = "models/engines/transaxial_m.mdl", - category = "Transfer", - weight = Gear2MW, - parentable = true, - switch = 0.4, - maxtq = 50000, - gears = 2, - doubleclutch = true, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.5, - [ 2 ] = -0.5, - [ -1 ] = 0.5 - } -} ) - -ACF_DefineGearbox( "2Gear-T-L", { - name = "Transfer case, Large", - desc = "2 speed gearbox, useful for low/high range and tank turning", - model = "models/engines/transaxial_l.mdl", - category = "Transfer", - weight = Gear2LW, - parentable = true, - switch = 0.6, - maxtq = 100000, - gears = 2, - doubleclutch = true, - geartable = { - [ 0 ] = 0, - [ 1 ] = 0.5, - [ 2 ] = -0.5, - [ -1 ] = 1 - } -} ) - ACF.RegisterGearboxClass("Transfer", { Name = "Transfer Case", CreateMenu = ACF.ManualGearboxMenu, diff --git a/lua/acf/shared/guns/autocannon.lua b/lua/acf/shared/guns/autocannon.lua index 52918246e..4422b8e11 100644 --- a/lua/acf/shared/guns/autocannon.lua +++ b/lua/acf/shared/guns/autocannon.lua @@ -1,91 +1,3 @@ --- DELETE -ACF_defineGunClass("AC", { - spread = 0.2, - name = "Autocannon", - desc = "Autocannons have a rather high weight and bulk for the ammo they fire, but they can fire it extremely fast.", - muzzleflash = "auto_muzzleflash_noscale", - rofmod = 0.85, - sound = "acf_base/weapons/ac_fire4.mp3", - soundDistance = " ", - soundNormal = " " -}) - --- DELETE -ACF_defineGun("20mmAC", { - name = "20mm Autocannon", - desc = "The 20mm AC is the smallest of the family; having a good rate of fire but a tiny shell.", - model = "models/autocannon/autocannon_20mm.mdl", - caliber = 2.0, - gunclass = "AC", - weight = 500, - year = 1930, - rofmod = 0.7, - magsize = 100, - magreload = 15, - Cyclic = 250, - round = { - maxlength = 32, - propweight = 0.13 - } -}) - --- DELETE -ACF_defineGun("30mmAC", { - name = "30mm Autocannon", - desc = "The 30mm AC can fire shells with sufficient space for a small payload, and has modest anti-armor capability", - model = "models/autocannon/autocannon_30mm.mdl", - gunclass = "AC", - caliber = 3.0, - weight = 1000, - year = 1935, - rofmod = 0.5, - magsize = 75, - magreload = 20, - Cyclic = 225, - round = { - maxlength = 39, - propweight = 0.350 - } -}) - --- DELETE -ACF_defineGun("40mmAC", { - name = "40mm Autocannon", - desc = "The 40mm AC can fire shells with sufficient space for a useful payload, and can get decent penetration with proper rounds.", - model = "models/autocannon/autocannon_40mm.mdl", - gunclass = "AC", - caliber = 4.0, - weight = 1500, - year = 1940, - rofmod = 0.48, - magsize = 30, - magreload = 25, - Cyclic = 200, - round = { - maxlength = 45, - propweight = 0.9 - } -}) - --- DELETE -ACF_defineGun("50mmAC", { - name = "50mm Autocannon", - desc = "The 50mm AC fires shells comparable with the 50mm Cannon, making it capable of destroying light armour quite quickly.", - model = "models/autocannon/autocannon_50mm.mdl", - gunclass = "AC", - caliber = 5.0, - weight = 2000, - year = 1965, - rofmod = 0.4, - magsize = 25, - Cyclic = 175, - magreload = 30, - round = { - maxlength = 52, - propweight = 1.2 - } -}) - ACF.RegisterWeaponClass("AC", { Name = "Autocannon", Description = "Autocannons have a rather high weight and bulk for the ammo they fire, but they can fire it extremely fast.", diff --git a/lua/acf/shared/guns/autoloader.lua b/lua/acf/shared/guns/autoloader.lua index f78e3fae7..3181411c2 100644 --- a/lua/acf/shared/guns/autoloader.lua +++ b/lua/acf/shared/guns/autoloader.lua @@ -1,110 +1,3 @@ --- DELETE -ACF_defineGunClass("AL", { - spread = 0.08, - name = "Autoloader", - desc = "A cannon with attached autoloading mechanism. While it allows for several quick shots, the mechanism adds considerable bulk, weight, and magazine reload time.", - muzzleflash = "cannon_muzzleflash_noscale", - rofmod = 0.64, - sound = "acf_base/weapons/autoloader.mp3", - soundDistance = "Cannon.Fire", - soundNormal = " " -}) - --- DELETE -ACF_defineGun("75mmAL", { - name = "75mm Autoloading Cannon", - desc = "A quick-firing 75mm gun, pops off a number of rounds in relatively short order.", - model = "models/tankgun/tankgun_al_75mm.mdl", - gunclass = "AL", - caliber = 7.5, - weight = 1892, - year = 1946, - rofmod = 1, - magsize = 8, - magreload = 15, - Cyclic = 30, - round = { - maxlength = 78, - propweight = 3.8 - } -}) - --- DELETE -ACF_defineGun("100mmAL", { - name = "100mm Autoloading Cannon", - desc = "The 100mm is good for rapidly hitting medium armor, then running like your ass is on fire to reload.", - model = "models/tankgun/tankgun_al_100mm.mdl", - gunclass = "AL", - caliber = 10.0, - weight = 3325, - year = 1956, - rofmod = 0.85, - magsize = 6, - magreload = 21, - Cyclic = 18, - round = { - maxlength = 93, - propweight = 9.5 - } -}) - --- DELETE -ACF_defineGun("120mmAL", { - name = "120mm Autoloading Cannon", - desc = "The 120mm autoloader can do serious damage before reloading, but the reload time is killer.", - model = "models/tankgun/tankgun_al_120mm.mdl", - gunclass = "AL", - caliber = 12.0, - weight = 6050, - year = 1956, - rofmod = 0.757, - magsize = 5, - magreload = 27, - Cyclic = 11, - round = { - maxlength = 110, - propweight = 18 - } -}) - --- DELETE -ACF_defineGun("140mmAL", { - name = "140mm Autoloading Cannon", - desc = "The 140mm can shred a medium tank's armor with one magazine, and even function as shoot & scoot artillery, with its useful HE payload.", - model = "models/tankgun/tankgun_al_140mm.mdl", - gunclass = "AL", - caliber = 14.0, - weight = 8830, - year = 1970, - rofmod = 0.743, - magsize = 5, - magreload = 35, - Cyclic = 8, - round = { - maxlength = 127, - propweight = 28 - } -}) ---[[ -ACF_defineGun("170mmAL", { - name = "170mm Autoloading Cannon", - desc = "The 170mm can shred an average 40ton tank's armor with one magazine.", - model = "models/tankgun/tankgun_al_170mm.mdl", - gunclass = "AL", - caliber = 17.0, - weight = 13350, - year = 1970, - rofmod = 0.8, - magsize = 4, - magreload = 40, - round = { - maxlength = 154, - propweight = 34 - } -} ) -]] --- - ACF.RegisterWeaponClass("AL", { Name = "Autoloader", Description = "A cannon with attached autoloading mechanism. While it allows for several quick shots, the mechanism adds considerable bulk, weight, and magazine reload time.", diff --git a/lua/acf/shared/guns/cannon.lua b/lua/acf/shared/guns/cannon.lua index b6776551e..4cb3e4aa7 100644 --- a/lua/acf/shared/guns/cannon.lua +++ b/lua/acf/shared/guns/cannon.lua @@ -1,124 +1,3 @@ --- DELETE -ACF_defineGunClass("C", { - spread = 0.08, - name = "Cannon", - desc = "High velocity guns that can fire very powerful ammunition, but are rather slow to reload.", - muzzleflash = "cannon_muzzleflash_noscale", - rofmod = 2, - sound = "acf_base/weapons/cannon_new.mp3", - soundDistance = "Cannon.Fire", - soundNormal = " " -}) - --- DELETE -ACF_defineGun("37mmC", { - name = "37mm Cannon", - desc = "A light and fairly weak cannon with good accuracy.", - model = "models/tankgun/tankgun_37mm.mdl", - gunclass = "C", - caliber = 3.7, - weight = 350, - year = 1919, - rofmod = 1.4, - sound = "acf_base/weapons/ac_fire4.mp3", - round = { - maxlength = 48, - propweight = 1.125 - } -}) - --- DELETE -ACF_defineGun("50mmC", { - name = "50mm Cannon", - desc = "The 50mm is surprisingly fast-firing, with good effectiveness against light armor, but a pea-shooter compared to its bigger cousins", - model = "models/tankgun/tankgun_50mm.mdl", - gunclass = "C", - caliber = 5.0, - weight = 665, - year = 1935, - sound = "acf_base/weapons/ac_fire4.mp3", - round = { - maxlength = 63, - propweight = 2.1 - } -}) - --- DELETE -ACF_defineGun("75mmC", { - name = "75mm Cannon", - desc = "The 75mm is still rather respectable in rate of fire, but has only modest payload. Often found on the Eastern Front, and on cold war light tanks.", - model = "models/tankgun/tankgun_75mm.mdl", - gunclass = "C", - caliber = 7.5, - weight = 1420, - year = 1942, - round = { - maxlength = 78, - propweight = 3.8 - } -}) - --- DELETE -ACF_defineGun("100mmC", { - name = "100mm Cannon", - desc = "The 100mm was a benchmark for the early cold war period, and has great muzzle velocity and hitting power, while still boasting a respectable, if small, payload.", - model = "models/tankgun/tankgun_100mm.mdl", - gunclass = "C", - caliber = 10.0, - weight = 2750, - year = 1944, - round = { - maxlength = 93, - propweight = 9.5 - } -}) - --- DELETE -ACF_defineGun("120mmC", { - name = "120mm Cannon", - desc = "Often found in MBTs, the 120mm shreds lighter armor with utter impunity, and is formidable against even the big boys.", - model = "models/tankgun/tankgun_120mm.mdl", - gunclass = "C", - caliber = 12.0, - weight = 5200, - year = 1955, - round = { - maxlength = 110, - propweight = 18 - } -}) - --- DELETE -ACF_defineGun("140mmC", { - name = "140mm Cannon", - desc = "The 140mm fires a massive shell with enormous penetrative capability, but has a glacial reload speed and a very hefty weight.", - model = "models/tankgun/tankgun_140mm.mdl", - gunclass = "C", - caliber = 14.0, - weight = 8180, - year = 1990, - round = { - maxlength = 127, - propweight = 28 - } -}) ---[[ -ACF_defineGun("170mmC", { - name = "170mm Cannon", - desc = "The 170mm fires a gigantic shell with ginormous penetrative capability, but has a glacial reload speed and an extremely hefty weight.", - model = "models/tankgun/tankgun_170mm.mdl", - gunclass = "C", - caliber = 17.0, - weight = 12350, - year = 1990, - round = { - maxlength = 154, - propweight = 34 - } -} ) -]] --- - ACF.RegisterWeaponClass("C", { Name = "Cannon", Description = "High velocity guns that can fire very powerful ammunition, but are rather slow to reload.", diff --git a/lua/acf/shared/guns/grenadelauncher.lua b/lua/acf/shared/guns/grenadelauncher.lua index deaee689f..7e98d1ca0 100644 --- a/lua/acf/shared/guns/grenadelauncher.lua +++ b/lua/acf/shared/guns/grenadelauncher.lua @@ -1,34 +1,3 @@ --- DELETE -ACF_defineGunClass("GL", { - spread = 0.28, - name = "Grenade Launcher", - desc = "Grenade Launchers can fire shells with relatively large payloads at a fast rate, but with very limited velocities and poor accuracy.", - muzzleflash = "gl_muzzleflash_noscale", - rofmod = 1, - sound = "acf_base/weapons/grenadelauncher.mp3", - soundDistance = " ", - soundNormal = " " -} ) - --- DELETE -ACF_defineGun("40mmGL", { --id - name = "40mm Grenade Launcher", - desc = "The 40mm chews up infantry but is about as useful as tits on a nun for fighting armor. Often found on 4x4s rolling through the third world.", - model = "models/launcher/40mmgl.mdl", - gunclass = "GL", - caliber = 4.0, - weight = 55, - magsize = 30, - magreload = 7.5, - year = 1970, - Cyclic = 200, - IsBoxed = true, - round = { - maxlength = 7.5, - propweight = 0.01 - } -} ) - ACF.RegisterWeaponClass("GL", { Name = "Grenade Launcher", Description = "Grenade Launchers can fire shells with relatively large payloads at a fast rate, but with very limited velocities and poor accuracy.", diff --git a/lua/acf/shared/guns/heavymachinegun.lua b/lua/acf/shared/guns/heavymachinegun.lua index a7aef2322..ce7fa3646 100644 --- a/lua/acf/shared/guns/heavymachinegun.lua +++ b/lua/acf/shared/guns/heavymachinegun.lua @@ -1,100 +1,3 @@ --- DELETE -ACF_defineGunClass("HMG", { - spread = 1.2, - name = "Heavy Machinegun", - desc = "Designed as autocannons for aircraft, HMGs are rapid firing, lightweight, and compact but sacrifice accuracy, magazine size, and reload times. They excel at strafing and dogfighting.\nBecause of their long reload times and high rate of fire, it is best to aim BEFORE pushing the almighty fire switch.", - muzzleflash = "mg_muzzleflash_noscale", - rofmod = 0.14, - sound = "acf_base/weapons/mg_fire3.mp3", - soundDistance = " ", - soundNormal = " ", - longbarrel = { - index = 2, - submodel = 4, - newpos = "muzzle2" - } -}) - --- DELETE -ACF_defineGun("13mmHMG", { - name = "13mm Heavy Machinegun", - desc = "The lightest of the HMGs, the 13mm has a rapid fire rate but suffers from poor payload size. Often used to strafe ground troops or annoy low-flying aircraft.", - model = "models/machinegun/machinegun_20mm.mdl", - gunclass = "HMG", - caliber = 1.3, - weight = 90, - year = 1935, - rofmod = 3.3, - magsize = 35, - magreload = 6, - Cyclic = 550, - IsBoxed = true, - round = { - maxlength = 22, - propweight = 0.09 - } -}) - --- DELETE -ACF_defineGun("20mmHMG", { - name = "20mm Heavy Machinegun", - desc = "The 20mm has a rapid fire rate but suffers from poor payload size. Often used to strafe ground troops or annoy low-flying aircraft.", - model = "models/machinegun/machinegun_20mm_compact.mdl", - gunclass = "HMG", - caliber = 2.0, - weight = 160, - year = 1935, - rofmod = 1.9, --at 1.5, 675rpm; at 2.0, 480rpm - magsize = 30, - magreload = 6, - Cyclic = 525, - IsBoxed = true, - round = { - maxlength = 30, - propweight = 0.12 - } -}) - --- DELETE -ACF_defineGun("30mmHMG", { - name = "30mm Heavy Machinegun", - desc = "30mm shell chucker, light and compact. Your average cold war dogfight go-to.", - model = "models/machinegun/machinegun_30mm_compact.mdl", - gunclass = "HMG", - caliber = 3.0, - weight = 480, - year = 1941, - rofmod = 1.1, --at 1.05, 495rpm; - magsize = 25, - magreload = 6, - Cyclic = 500, - IsBoxed = true, - round = { - maxlength = 37, - propweight = 0.35 - } -}) - --- DELETE -ACF_defineGun("40mmHMG", { - name = "40mm Heavy Machinegun", - desc = "The heaviest of the heavy machineguns. Massively powerful with a killer reload and hefty ammunition requirements, it can pop even relatively heavy targets with ease.", - model = "models/machinegun/machinegun_40mm_compact.mdl", - gunclass = "HMG", - caliber = 4.0, - weight = 780, - year = 1955, - rofmod = 0.95, --at 0.75, 455rpm - magsize = 20, - magreload = 8, - Cyclic = 475, - IsBoxed = true, - round = { - maxlength = 42, - propweight = 0.9 - } -}) - ACF.RegisterWeaponClass("HMG", { Name = "Heavy Machinegun", Description = "Designed as autocannons for aircraft, HMGs are rapid firing, lightweight, and compact but sacrifice accuracy, magazine size, and reload times.", diff --git a/lua/acf/shared/guns/howitzer.lua b/lua/acf/shared/guns/howitzer.lua index a98a217f8..66332c841 100644 --- a/lua/acf/shared/guns/howitzer.lua +++ b/lua/acf/shared/guns/howitzer.lua @@ -1,120 +1,3 @@ --- DELETE -ACF_defineGunClass("HW", { - spread = 0.1, - name = "Howitzer", - desc = "Howitzers are limited to rather mediocre muzzle velocities, but can fire extremely heavy projectiles with large useful payload capacities.", - muzzleflash = "howie_muzzleflash_noscale", - rofmod = 1.8, - sound = "acf_base/weapons/howitzer_new2.mp3", - soundDistance = "Howitzer.Fire", - soundNormal = " " -}) - --- DELETE -ACF_defineGun("75mmHW", { - name = "75mm Howitzer", - desc = "Often found being towed by large smelly animals, the 75mm has a high rate of fire, and is surprisingly lethal against light armor. Great for a sustained barrage against someone you really don't like.", - model = "models/howitzer/howitzer_75mm.mdl", - gunclass = "HW", - caliber = 7.5, - weight = 530, - year = 1900, - round = { - maxlength = 60, - propweight = 1.8 - } -}) - --- DELETE -ACF_defineGun("105mmHW", { - name = "105mm Howitzer", - desc = "The 105 lobs a big shell far, and its HEAT rounds can be extremely effective against even heavier armor.", - model = "models/howitzer/howitzer_105mm.mdl", - gunclass = "HW", - caliber = 10.5, - weight = 1480, - year = 1900, - round = { - maxlength = 86, - propweight = 3.75 - } -}) - --- DELETE -ACF_defineGun("122mmHW", { - name = "122mm Howitzer", - desc = "The 122mm bridges the gap between the 105 and the 155, providing a lethal round with a big splash radius.", - model = "models/howitzer/howitzer_122mm.mdl", - gunclass = "HW", - caliber = 12.2, - weight = 3420, - year = 1900, - round = { - maxlength = 106, - propweight = 7 - } -}) - --- DELETE -ACF_defineGun("155mmHW", { - name = "155mm Howitzer", - desc = "The 155 is a classic heavy artillery round, with good reason. A versatile weapon, it's found on most modern SPGs.", - model = "models/howitzer/howitzer_155mm.mdl", - gunclass = "HW", - caliber = 15.5, - weight = 5340, - year = 1900, - round = { - maxlength = 124, - propweight = 13.5 - } -}) - --- DELETE -ACF_defineGun("203mmHW", { - name = "203mm Howitzer", - desc = "An 8-inch deck gun, found on siege artillery and cruisers.", - model = "models/howitzer/howitzer_203mm.mdl", - gunclass = "HW", - caliber = 20.3, - weight = 10280, - year = 1900, - round = { - maxlength = 162.4, - propweight = 28.5 - } -}) ---[[ -ACF_defineGun("240mmHW", { - name = "240mm Howitzer", - desc = "A 9.4-inch deck gun, found on heavy siege artillery and cruisers.", - model = "models/howitzer/howitzer_240mm.mdl", - gunclass = "HW", - caliber = 24.0, - weight = 12980, - year = 1900, - round = { - maxlength = 192.0, - propweight = 33.7 - } -} ) - -ACF_defineGun("290mmHW", { - name = "290mm Howitzer", - desc = " Mother of all howitzers. This 12in beast can be found on battleships. It WILL fuck your day up... when it reloads.", - model = "models/howitzer/howitzer_406mm.mdl", - gunclass = "HW", - caliber = 29, - weight = 24960, - year = 1900, - round = { - maxlength = 325, - propweight = 57.0 - } -} ) -]] --- - ACF.RegisterWeaponClass("HW", { Name = "Howitzer", Description = "Howitzers are limited to rather mediocre muzzle velocities, but can fire extremely heavy projectiles with large useful payload capacities.", diff --git a/lua/acf/shared/guns/machinegun.lua b/lua/acf/shared/guns/machinegun.lua index ec0ff4ea4..c584d1e1a 100644 --- a/lua/acf/shared/guns/machinegun.lua +++ b/lua/acf/shared/guns/machinegun.lua @@ -1,75 +1,3 @@ --- DELETE -ACF_defineGunClass("MG", { - spread = 0.16, - name = "Machinegun", - desc = "Machineguns are light guns that fire equally light bullets at a fast rate.", - muzzleflash = "mg_muzzleflash_noscale", - rofmod = 0.9, - sound = "acf_base/weapons/mg_fire4.mp3", - soundNormal = "acf_base/weapons/mg_fire4.mp3", - soundDistance = "" -}) - --- DELETE -ACF_defineGun("7.62mmMG", { - name = "7.62mm Machinegun", - desc = "The 7.62mm is effective against infantry, but its usefulness against armor is laughable at best.", - model = "models/machinegun/machinegun_762mm.mdl", - gunclass = "MG", - caliber = 0.762, - weight = 15, - year = 1930, - rofmod = 1.59, - magsize = 250, - magreload = 6, -- Time to reload in seconds - Cyclic = 700, -- Rounds per minute - IsBoxed = true, - round = { - maxlength = 13, - propweight = 0.04 - } -}) - --- DELETE -ACF_defineGun("12.7mmMG", { - name = "12.7mm Machinegun", - desc = "The 12.7mm MG is still light, finding its way into a lot of mountings, including on top of tanks.", - model = "models/machinegun/machinegun_127mm.mdl", - gunclass = "MG", - caliber = 1.27, - weight = 30, - year = 1910, - rofmod = 1, --0.766 - magsize = 150, - magreload = 6, - Cyclic = 600, - IsBoxed = true, - round = { - maxlength = 15.8, - propweight = 0.03 - } -}) - --- DELETE -ACF_defineGun("14.5mmMG", { - name = "14.5mm Machinegun", - desc = "The 14.5mm MG trades its smaller stablemates' rate of fire for more armor penetration and damage.", - model = "models/machinegun/machinegun_145mm.mdl", - gunclass = "MG", - caliber = 1.45, - weight = 45, - year = 1932, - rofmod = 1, --0.722 - magsize = 90, - magreload = 5, - Cyclic = 500, - IsBoxed = true, - round = { - maxlength = 19.5, - propweight = 0.04 - } -}) - ACF.RegisterWeaponClass("MG", { Name = "Machinegun", Description = "Machineguns are light guns that fire equally light bullets at a fast rate.", diff --git a/lua/acf/shared/guns/mortar.lua b/lua/acf/shared/guns/mortar.lua index bd640efa6..742145daa 100644 --- a/lua/acf/shared/guns/mortar.lua +++ b/lua/acf/shared/guns/mortar.lua @@ -1,107 +1,3 @@ --- DELETE -ACF_defineGunClass("MO", { - spread = 0.72, - name = "Mortar", - desc = "Mortars are able to fire shells with usefull payloads from a light weight gun, at the price of limited velocities.", - muzzleflash = "mortar_muzzleflash_noscale", - rofmod = 2.5, - sound = "acf_base/weapons/mortar_new.mp3", - soundDistance = "Mortar.Fire", - soundNormal = " " -}) - --- DELETE -ACF_defineGun("60mmM", { - name = "60mm Mortar", - desc = "The 60mm is a common light infantry support weapon, with a high rate of fire but a puny payload.", - model = "models/mortar/mortar_60mm.mdl", - gunclass = "MO", - caliber = 6.0, - weight = 60, - rofmod = 1.25, - year = 1930, - round = { - maxlength = 20, - propweight = 0.037 - } -}) - --- DELETE -ACF_defineGun("80mmM", { - name = "80mm Mortar", - desc = "The 80mm is a common infantry support weapon, with a good bit more boom than its little cousin.", - model = "models/mortar/mortar_80mm.mdl", - gunclass = "MO", - caliber = 8.0, - weight = 120, - year = 1930, - round = { - maxlength = 28, - propweight = 0.055 - } -}) - --- DELETE -ACF_defineGun("120mmM", { - name = "120mm Mortar", - desc = "The versatile 120 is sometimes vehicle-mounted to provide quick boomsplat to support the infantry. Carries more boom in its boomsplat, has good HEAT performance, and is more accurate in high-angle firing.", - model = "models/mortar/mortar_120mm.mdl", - gunclass = "MO", - caliber = 12.0, - weight = 640, - year = 1935, - round = { - maxlength = 45, - propweight = 0.175 - } -}) - --- DELETE -ACF_defineGun("150mmM", { - name = "150mm Mortar", - desc = "The perfect balance between the 120mm and the 200mm. Can prove a worthy main gun weapon, as well as a mighty good mortar emplacement", - model = "models/mortar/mortar_150mm.mdl", - gunclass = "MO", - caliber = 15.0, - weight = 1255, - year = 1945, - round = { - maxlength = 58, - propweight = 0.235 - } -}) - --- DELETE -ACF_defineGun("200mmM", { - name = "200mm Mortar", - desc = "The 200mm is a beast, often used against fortifications. Though enormously powerful, feel free to take a nap while it reloads", - model = "models/mortar/mortar_200mm.mdl", - gunclass = "MO", - caliber = 20.0, - weight = 2850, - year = 1940, - round = { - maxlength = 80, - propweight = 0.330 - } -}) ---[[ -ACF_defineGun("280mmM", { - name = "280mm Mortar", - desc = "Massive payload, with a reload time to match. Found in rare WW2 siege artillery pieces. It's the perfect size for a jeep.", - model = "models/mortar/mortar_280mm.mdl", - gunclass = "MO", - caliber = 28.0, - weight = 9035, - year = 1945, - round = { - maxlength = 138, - propweight = 0.462 - } -} ) -]] --- - ACF.RegisterWeaponClass("MO", { Name = "Mortar", Description = "Mortars are able to fire shells with usefull payloads from a light weight gun, at the price of limited velocities.", diff --git a/lua/acf/shared/guns/rotaryautocannon.lua b/lua/acf/shared/guns/rotaryautocannon.lua index 08bbf3f35..d826a042d 100644 --- a/lua/acf/shared/guns/rotaryautocannon.lua +++ b/lua/acf/shared/guns/rotaryautocannon.lua @@ -1,73 +1,3 @@ --- DELETE -ACF_defineGunClass("RAC", { - spread = 0.48, - name = "Rotary Autocannon", - desc = "Rotary Autocannons sacrifice weight, bulk and accuracy over classic Autocannons to get the highest rate of fire possible.", - muzzleflash = "mg_muzzleflash_noscale", - rofmod = 0.07, - sound = "acf_base/weapons/mg_fire3.mp3", - soundDistance = " ", - soundNormal = " ", - color = {135, 135, 135} -} ) - --- DELETE -ACF_defineGun("14.5mmRAC", { --id - name = "14.5mm Rotary Autocannon", - desc = "A lightweight rotary autocannon, used primarily against infantry and light vehicles.", - model = "models/rotarycannon/kw/14_5mmrac.mdl", - gunclass = "RAC", - caliber = 1.45, - weight = 400, - year = 1962, - magsize = 250, - magreload = 15, - rofmod = 5.4, - Cyclic = 2250, - round = { - maxlength = 25, - propweight = 0.06 - } -} ) - --- DELETE -ACF_defineGun("20mmRAC", { - name = "20mm Rotary Autocannon", - desc = "The 20mm is able to chew up light armor with decent penetration or put up a big flak screen.", - model = "models/rotarycannon/kw/20mmrac.mdl", - gunclass = "RAC", - caliber = 2.0, - weight = 760, - year = 1965, - magsize = 200, - magreload = 20, - rofmod = 2.1, - Cyclic = 2000, - round = { - maxlength = 30, - propweight = 0.12 - } -} ) - --- DELETE -ACF_defineGun("30mmRAC", { - name = "30mm Rotary Autocannon", - desc = "The 30mm is the bane of ground-attack aircraft, able to tear up light armor without giving one single fuck. Also seen in the skies above dead T-72s.", - model = "models/rotarycannon/kw/30mmrac.mdl", - gunclass = "RAC", - caliber = 3.0, - weight = 1500, - year = 1975, - magsize = 100, - magreload = 30, - rofmod = 1, - Cyclic = 1500, - round = { - maxlength = 40, - propweight = 0.350 - } -} ) - ACF.RegisterWeaponClass("RAC", { Name = "Rotary Autocannon", Description = "Rotary Autocannons sacrifice weight, bulk and accuracy over classic autocannons to get the highest rate of fire possible.", diff --git a/lua/acf/shared/guns/semiauto.lua b/lua/acf/shared/guns/semiauto.lua index c3afb8a56..2b1e6a8ce 100644 --- a/lua/acf/shared/guns/semiauto.lua +++ b/lua/acf/shared/guns/semiauto.lua @@ -1,115 +1,3 @@ --- DELETE -ACF_defineGunClass("SA", { - spread = 0.12, - name = "Semiautomatic Cannon", - desc = "Semiautomatic cannons offer light weight, small size, and high rates of fire at the cost of often reloading and low accuracy.", - muzzleflash = "semi_muzzleflash_noscale", - rofmod = 0.36, - sound = "acf_base/weapons/sa_fire1.mp3", - soundDistance = " ", - soundNormal = " " -}) - --- DELETE -ACF_defineGun("25mmSA", { - name = "25mm Semiautomatic Cannon", - desc = "The 25mm semiauto can quickly put five rounds downrange, being lethal, yet light.", - model = "models/autocannon/semiautocannon_25mm.mdl", - gunclass = "SA", - caliber = 2.5, - weight = 250, - year = 1935, - rofmod = 0.7, - magsize = 5, - magreload = 2.5, - Cyclic = 300, - IsBoxed = true, - round = { - maxlength = 39, - propweight = 0.5 - } -}) - --- DELETE -ACF_defineGun("37mmSA", { - name = "37mm Semiautomatic Cannon", - desc = "The 37mm is surprisingly powerful, its five-round clips boasting a respectable payload and a high muzzle velocity.", - model = "models/autocannon/semiautocannon_37mm.mdl", - gunclass = "SA", - caliber = 3.7, - weight = 500, - year = 1940, - rofmod = 0.7, - magsize = 5, - magreload = 3.7, - Cyclic = 250, - IsBoxed = true, - round = { - maxlength = 42, - propweight = 1.125 - } -}) - --- DELETE -ACF_defineGun("45mmSA", { - name = "45mm Semiautomatic Cannon", - desc = "The 45mm can easily shred light armor, with a respectable rate of fire, but its armor penetration pales in comparison to regular cannons.", - model = "models/autocannon/semiautocannon_45mm.mdl", - gunclass = "SA", - caliber = 4.5, - weight = 750, - year = 1965, - rofmod = 0.72, - magsize = 5, - magreload = 4.5, - Cyclic = 225, - IsBoxed = true, - round = { - maxlength = 52, - propweight = 1.8 - } -}) - --- DELETE -ACF_defineGun("57mmSA", { - name = "57mm Semiautomatic Cannon", - desc = "The 57mm is a respectable light armament, offering considerable penetration and moderate fire rate.", - model = "models/autocannon/semiautocannon_57mm.mdl", - gunclass = "SA", - caliber = 5.7, - weight = 1000, - year = 1965, - rofmod = 0.8, - magsize = 5, - magreload = 5.7, - Cyclic = 200, - IsBoxed = true, - round = { - maxlength = 62, - propweight = 2 - } -}) - --- DELETE -ACF_defineGun("76mmSA", { - name = "76mm Semiautomatic Cannon", - desc = "The 76mm semiauto is a fearsome weapon, able to put 5 76mm rounds downrange in 8 seconds.", - model = "models/autocannon/semiautocannon_76mm.mdl", - gunclass = "SA", - caliber = 7.62, - weight = 2000, - year = 1984, - rofmod = 0.85, - magsize = 5, - magreload = 7.6, - Cyclic = 150, - IsBoxed = true, - round = { - maxlength = 70, - propweight = 4.75 - } -}) - ACF.RegisterWeaponClass("SA", { Name = "Semiautomatic Cannon", Description = "Semiautomatic cannons offer light weight, small size, and high rates of fire at the cost of often reloading and low accuracy.", diff --git a/lua/acf/shared/guns/shortcannon.lua b/lua/acf/shared/guns/shortcannon.lua index 4be7f294c..9c2bae987 100644 --- a/lua/acf/shared/guns/shortcannon.lua +++ b/lua/acf/shared/guns/shortcannon.lua @@ -1,109 +1,3 @@ --- DELETE -ACF_defineGunClass("SC", { - spread = 0.16, - name = "Short-Barrel Cannon", - desc = "Short cannons trade muzzle velocity and accuracy for lighter weight and smaller size, with more penetration than howitzers and lighter than cannons.", - muzzleflash = "cannon_muzzleflash_noscale", - rofmod = 1.7, - sound = "acf_base/weapons/cannon_new.mp3", - soundDistance = "Cannon.Fire", - soundNormal = " " -} ) - --- DELETE -ACF_defineGun("37mmSC", { - name = "37mm Short Cannon", - desc = "Quick-firing and light, but penetration is laughable. You're better off throwing rocks.", - model = "models/tankgun/tankgun_short_37mm.mdl", - gunclass = "SC", - caliber = 3.7, - weight = 200, - rofmod = 1.4, - year = 1915, - sound = "acf_base/weapons/ac_fire4.mp3", - round = { - maxlength = 45, - propweight = 0.29 - } -} ) - --- DELETE -ACF_defineGun("50mmSC", { - name = "50mm Short Cannon", - desc = "The 50mm is a quick-firing pea-shooter, good for scouts, and common on old interwar tanks.", - model = "models/tankgun/tankgun_short_50mm.mdl", - gunclass = "SC", - caliber = 5.0, - weight = 330, - rofmod = 1.4, - year = 1915, - sound = "acf_base/weapons/ac_fire4.mp3", - round = { - maxlength = 63, - propweight = 0.6, - } -} ) - --- DELETE -ACF_defineGun("75mmSC", { - name = "75mm Short Cannon", - desc = "The 75mm is common WW2 medium tank armament, and still useful in many other applications.", - model = "models/tankgun/tankgun_short_75mm.mdl", - gunclass = "SC", - caliber = 7.5, - weight = 750, - year = 1936, - round = { - maxlength = 76, - propweight = 2 - } -} ) - --- DELETE -ACF_defineGun("100mmSC", { - name = "100mm Short Cannon", - desc = "The 100mm is an effective infantry-support or antitank weapon, with a lot of uses and surprising lethality.", - model = "models/tankgun/tankgun_short_100mm.mdl", - gunclass = "SC", - caliber = 10.0, - weight = 1750, - year = 1940, - round = { - maxlength = 93, - propweight = 4.5 - } -} ) - --- DELETE -ACF_defineGun("120mmSC", { - name = "120mm Short Cannon", - desc = "The 120mm is a formidable yet lightweight weapon, with excellent performance against larger vehicles.", - model = "models/tankgun/tankgun_short_120mm.mdl", - gunclass = "SC", - caliber = 12.0, - weight = 3800, - year = 1944, - round = { - maxlength = 110, - propweight = 8.5 - } -} ) - --- DELETE -ACF_defineGun("140mmSC", { - name = "140mm Short Cannon", - desc = "A specialized weapon, developed from dark magic and anti-heavy tank hatred. Deal with it.", - model = "models/tankgun/tankgun_short_140mm.mdl", - gunclass = "SC", - caliber = 14.0, - weight = 6040, - year = 1999, - round = { - maxlength = 127, - propweight = 12.8 - } -} ) - ACF.RegisterWeaponClass("SC", { Name = "Short-Barrelled Cannon", Description = "Short cannons trade muzzle velocity and accuracy for lighter weight and smaller size, with more penetration than howitzers and lighter than cannons.", diff --git a/lua/acf/shared/guns/smokelauncher.lua b/lua/acf/shared/guns/smokelauncher.lua index 2cfb21703..8e92439fd 100644 --- a/lua/acf/shared/guns/smokelauncher.lua +++ b/lua/acf/shared/guns/smokelauncher.lua @@ -1,56 +1,3 @@ --- DELETE -ACF_defineGunClass("SL", { - spread = 0.32, - name = "Smoke Launcher", - desc = "Smoke launcher to block an attacker's line of sight.", - muzzleflash = "gl_muzzleflash_noscale", - rofmod = 22.5, - sound = "acf_base/weapons/smoke_launch.mp3", - soundDistance = "Mortar.Fire", - soundNormal = " " -}) - --- DELETE -ACF_defineGun("40mmSL", { - name = "40mm Smoke Launcher", - desc = "", - model = "models/launcher/40mmsl.mdl", - gunclass = "SL", - canparent = true, - caliber = 4.0, - weight = 1, - year = 1941, - magsize = 1, - magreload = 30, - Cyclic = 600, - IsBoxed = true, - round = { - maxlength = 17.5, - propweight = 0.000075 - } -}) - --- DELETE -ACF_defineGun("40mmCL", { - name = "40mm Countermeasure Launcher", - desc = "A revolver-style launcher capable of firing off several smoke or flare rounds.", - model = "models/launcher/40mmgl.mdl", - gunclass = "SL", - canparent = true, - caliber = 4.0, - weight = 20, - rofmod = 0.015, - magsize = 6, - magreload = 15, - Cyclic = 200, - year = 1950, - IsBoxed = true, - round = { - maxlength = 17.5, - propweight = 0.001 - } -}) - ACF.RegisterWeaponClass("SL", { Name = "Smoke Launcher", Description = "Smoke launcher to block an attacker's line of sight.", diff --git a/lua/acf/shared/guns/smoothbore.lua b/lua/acf/shared/guns/smoothbore.lua index eda02a985..8cd33cf78 100644 --- a/lua/acf/shared/guns/smoothbore.lua +++ b/lua/acf/shared/guns/smoothbore.lua @@ -1,76 +1,3 @@ --- DELETE -ACF_defineGunClass("SB", { - spread = 0.08, - name = "Smoothbore Cannon", - desc = "More modern smoothbore cannons that can only fire munitions that do not rely on spinning for accuracy.", - muzzleflash = "cannon_muzzleflash_noscale", - rofmod = 1.72, - sound = "acf_base/weapons/cannon_new.mp3", - soundDistance = "Cannon.Fire", - soundNormal = " " -} ) - --- DELETE -ACF_defineGun("105mmSB", { - name = "105mm Smoothbore Cannon", - desc = "The 105mm was a benchmark for the early cold war period, and has great muzzle velocity and hitting power, while still boasting a respectable, if small, payload.", - model = "models/tankgun_old/tankgun_100mm.mdl", - gunclass = "SB", - caliber = 10.5, - weight = 3550, - year = 1970, - round = { - maxlength = 101, - propweight = 9 - } -} ) - --- DELETE -ACF_defineGun("120mmSB", { - name = "120mm Smoothbore Cannon", - desc = "Often found in MBTs, the 120mm shreds lighter armor with utter impunity, and is formidable against even the big boys.", - model = "models/tankgun_old/tankgun_120mm.mdl", - gunclass = "SB", - caliber = 12.0, - weight = 6000, - year = 1975, - round = { - maxlength = 123, - propweight = 18 - } -} ) - --- DELETE -ACF_defineGun("140mmSB", { - name = "140mm Smoothbore Cannon", - desc = "The 140mm fires a massive shell with enormous penetrative capability, but has a glacial reload speed and a very hefty weight.", - model = "models/tankgun_old/tankgun_140mm.mdl", - gunclass = "SB", - caliber = 14.0, - weight = 8980, - year = 1990, - round = { - maxlength = 145, - propweight = 28 - } -} ) - ---[[ -ACF_defineGun("170mmC", { - name = "170mm Cannon", - desc = "The 170mm fires a gigantic shell with ginormous penetrative capability, but has a glacial reload speed and an extremely hefty weight.", - model = "models/tankgun/tankgun_170mm.mdl", - gunclass = "C", - caliber = 17.0, - weight = 12350, - year = 1990, - round = { - maxlength = 154, - propweight = 34 - } -} ) -]]-- - ACF.RegisterWeaponClass("SB", { Name = "Smoothbore Cannon", Description = "More modern smoothbore cannons that can only fire munitions that do not rely on spinning for accuracy.", diff --git a/lua/acf/shared/rounds/acf_roundfunctions.lua b/lua/acf/shared/rounds/acf_roundfunctions.lua deleted file mode 100644 index 24eac7d26..000000000 --- a/lua/acf/shared/rounds/acf_roundfunctions.lua +++ /dev/null @@ -1,63 +0,0 @@ - -function ACF_RoundBaseGunpowder(PlayerData, Data, ServerData, GUIData) - local Bullet = ACF.Weapons.Guns[PlayerData.Id] - local Round = Bullet.round - - Data.Caliber = Bullet.caliber - Data.FrArea = 3.1416 * (Data.Caliber * 0.5) ^ 2 - Data.Tracer = tonumber(PlayerData.Data10) > 0 and math.min(5 / Data.Caliber, 2.5) or 0 - - GUIData.MaxTotalLength = Round.maxlength * (Data.LengthAdj or 1) - - local PropMax = Round.propweight * 1000 / ACF.PDensity / Data.FrArea --Current casing absolute max propellant capacity - local CurLength = PlayerData.ProjLength + math.min(PlayerData.PropLength, PropMax) + Data.Tracer - - GUIData.MinPropLength = 0.01 - GUIData.MaxPropLength = math.max(math.min(GUIData.MaxTotalLength - CurLength + PlayerData.PropLength, PropMax), GUIData.MinPropLength) --Check if the desired prop lenght fits in the case and doesn't exceed the gun max - GUIData.MinProjLength = Data.Caliber * 1.5 - GUIData.MaxProjLength = math.max(GUIData.MaxTotalLength - CurLength + PlayerData.ProjLength, GUIData.MinProjLength) --Check if the desired proj lenght fits in the case - - local Ratio = math.min((GUIData.MaxTotalLength - Data.Tracer) / (PlayerData.ProjLength + math.min(PlayerData.PropLength, PropMax)), 1) --This is to check the current ratio between elements if i need to clamp it - - Data.ProjLength = math.Clamp(PlayerData.ProjLength * Ratio, GUIData.MinProjLength, GUIData.MaxProjLength) - Data.PropLength = math.Clamp(PlayerData.PropLength * Ratio, GUIData.MinPropLength, GUIData.MaxPropLength) - Data.PropMass = Data.FrArea * (ACF.AmmoCaseScale ^ 2) * (Data.PropLength * ACF.PDensity / 1000) --Volume of the case as a cylinder * Powder density converted from g to kg - Data.RoundVolume = Data.FrArea * ACF.AmmoCaseScale ^ 2 * (Data.ProjLength + Data.PropLength) - - GUIData.ProjVolume = Data.FrArea * Data.ProjLength - - return PlayerData, Data, ServerData, GUIData -end - -function ACF_RoundShellCapacity(Momentum, FrArea, Caliber, ProjLength) - local MinWall = 0.2 + ((Momentum / FrArea) ^ 0.7) / 50 --The minimal shell wall thickness required to survive firing at the current energy level - local Length = math.max(ProjLength - MinWall, 0) - local Radius = math.max((Caliber / 2) - MinWall, 0) - local Volume = 3.1416 * Radius ^ 2 * Length - --Returning the cavity volume and the minimum wall thickness - - return Volume, Length, Radius -end - -function ACF_RicoProbability(Rico, Speed) - local MinAngle = math.min(Rico - Speed / 15, 89) - - return { - Min = math.Round(math.max(MinAngle, 0.1), 1), - Mean = math.Round(math.max(MinAngle + (90 - MinAngle) / 2, 0.1), 1), - Max = 90 - } -end - ---Formula from https://mathscinotes.wordpress.com/2013/10/03/parameter-determination-for-pejsa-velocity-model/ ---not terribly accurate for acf, particularly small caliber (7.62mm off by 120 m/s at 800m), but is good enough for quick indicator ---range in m, vel is m/s -function ACF_PenRanging(MuzzleVel, DragCoef, ProjMass, PenArea, LimitVel, Range) - local V0 = (MuzzleVel * 39.37 * ACF.Scale) --initial velocity - local D0 = (DragCoef * V0 ^ 2 / ACF.DragDiv) --initial drag - local K1 = (D0 / (V0 ^ (3 / 2))) ^ -1 --estimated drag coefficient - local Vel = (math.sqrt(V0) - ((Range * 39.37) / (2 * K1))) ^ 2 - local Pen = (ACF_Kinetic(Vel, ProjMass, LimitVel).Penetration / PenArea) * ACF.KEtoRHA - - return Vel * 0.0254, Pen -end \ No newline at end of file diff --git a/lua/acf/shared/rounds/ap.lua b/lua/acf/shared/rounds/ap.lua deleted file mode 100644 index 5023c8870..000000000 --- a/lua/acf/shared/rounds/ap.lua +++ /dev/null @@ -1,211 +0,0 @@ -ACF.AmmoBlacklist.AP = {"MO", "SL", "SB"} -- DELETE -local Round = {} -Round.type = "Ammo" --Tells the spawn menu what entity to spawn -Round.name = "Armour Piercing (AP)" --Human readable name -Round.model = "models/munitions/round_100mm_shot.mdl" --Shell flight model -Round.desc = "A shell made out of a solid piece of steel, meant to penetrate armour" - -function Round.create(_, BulletData) - ACF_CreateBullet(BulletData) -end - --- Function to convert the player's slider data into the complete round data -function Round.convert(_, PlayerData) - local Data = {} - local ServerData = {} - local GUIData = {} - - if not PlayerData.PropLength then - PlayerData.PropLength = 0 - end - - if not PlayerData.ProjLength then - PlayerData.ProjLength = 0 - end - - if not PlayerData.Data10 then - PlayerData.Data10 = 0 - end - - PlayerData, Data, ServerData, GUIData = ACF_RoundBaseGunpowder(PlayerData, Data, ServerData, GUIData) - Data.ProjMass = Data.FrArea * (Data.ProjLength * 7.9 / 1000) --Volume of the projectile as a cylinder * density of steel - Data.ShovePower = 0.2 - Data.PenArea = Data.FrArea ^ ACF.PenAreaMod - Data.DragCoef = ((Data.FrArea / 10000) / Data.ProjMass) - Data.LimitVel = 800 --Most efficient penetration speed in m/s - Data.KETransfert = 0.1 --Kinetic energy transfert to the target for movement purposes - Data.Ricochet = 60 --Base ricochet angle - Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass, Data.Caliber) - Data.CartMass = Data.PropMass + Data.ProjMass - - --Only the crates need this part - if SERVER then - ServerData.Id = PlayerData.Id - ServerData.Type = PlayerData.Type - - return table.Merge(Data, ServerData) - end - - --Only the GUI needs this part - if CLIENT then - GUIData = table.Merge(GUIData, Round.getDisplayData(Data)) - - return table.Merge(Data, GUIData) - end -end - -function Round.getDisplayData(Data) - local GUIData = {} - local Energy = ACF_Kinetic(Data.MuzzleVel * 39.37, Data.ProjMass, Data.LimitVel) - GUIData.MaxPen = (Energy.Penetration / Data.PenArea) * ACF.KEtoRHA - - return GUIData -end - -function Round.network(Crate, BulletData) - Crate:SetNWString("AmmoType", "AP") - Crate:SetNWString("AmmoID", BulletData.Id) - Crate:SetNWFloat("Caliber", BulletData.Caliber) - Crate:SetNWFloat("ProjMass", BulletData.ProjMass) - Crate:SetNWFloat("PropMass", BulletData.PropMass) - Crate:SetNWFloat("DragCoef", BulletData.DragCoef) - Crate:SetNWFloat("MuzzleVel", BulletData.MuzzleVel) - Crate:SetNWFloat("Tracer", BulletData.Tracer) -end - -function Round.cratetxt(BulletData) - --local FrArea = BulletData.FrArea - local DData = Round.getDisplayData(BulletData) - - local str = {"Muzzle Velocity: ", math.Round(BulletData.MuzzleVel, 1), " m/s\n", "Max Penetration: ", math.floor(DData.MaxPen), " mm"} --"Cartridge Mass: ", math.Round(TotalMass, 2), MassUnit, "\n", --"Max Pen. Damage: ", math.Round(MaxHP.Damage, 1), " HP\n", - - return table.concat(str) -end - -function Round.propimpact(_, Bullet, Target, HitNormal, HitPos, Bone) - if ACF_Check(Target) then - local Speed = Bullet.Flight:Length() / ACF.Scale - local Energy = ACF_Kinetic(Speed, Bullet.ProjMass, Bullet.LimitVel) - local HitRes = ACF_RoundImpact(Bullet, Speed, Energy, Target, HitPos, HitNormal, Bone) - - if HitRes.Overkill > 0 then - table.insert(Bullet.Filter, Target) --"Penetrate" (Ingoring the prop for the retry trace) - Bullet.Flight = Bullet.Flight:GetNormalized() * (Energy.Kinetic * (1 - HitRes.Loss) * 2000 / Bullet.ProjMass) ^ 0.5 * 39.37 - - return "Penetrated" - elseif HitRes.Ricochet then - return "Ricochet" - else - return false - end - else - table.insert(Bullet.Filter, Target) - - return "Penetrated" - end -end - -function Round.worldimpact(_, Bullet, HitPos, HitNormal) - local Energy = ACF_Kinetic(Bullet.Flight:Length() / ACF.Scale, Bullet.ProjMass, Bullet.LimitVel) - local HitRes = ACF_PenetrateGround(Bullet, Energy, HitPos, HitNormal) - - if HitRes.Penetrated then - return "Penetrated" - elseif HitRes.Ricochet then - return "Ricochet" - else - return false - end -end - -function Round.endflight(Index) - ACF_RemoveBullet(Index) -end - -local DecalIndex = ACF.GetAmmoDecalIndex - -function Round.endeffect(_, Bullet) - local Effect = EffectData() - Effect:SetOrigin(Bullet.SimPos) - Effect:SetNormal(Bullet.SimFlight:GetNormalized()) - Effect:SetRadius(Bullet.Caliber) - Effect:SetDamageType(DecalIndex(Bullet.AmmoType)) - - util.Effect("ACF_Impact", Effect) -end - -function Round.pierceeffect(_, Bullet) - local Effect = EffectData() - Effect:SetOrigin(Bullet.SimPos) - Effect:SetNormal(Bullet.SimFlight:GetNormalized()) - Effect:SetScale(Bullet.SimFlight:Length()) - Effect:SetMagnitude(Bullet.RoundMass) - Effect:SetRadius(Bullet.Caliber) - Effect:SetDamageType(DecalIndex(Bullet.AmmoType)) - - util.Effect("ACF_Penetration", Effect) -end - -function Round.ricocheteffect(_, Bullet) - local Effect = EffectData() - Effect:SetOrigin(Bullet.SimPos) - Effect:SetNormal(Bullet.SimFlight:GetNormalized()) - Effect:SetScale(Bullet.SimFlight:Length()) - Effect:SetMagnitude(Bullet.RoundMass) - Effect:SetRadius(Bullet.Caliber) - Effect:SetDamageType(DecalIndex(Bullet.AmmoType)) - - util.Effect("ACF_Ricochet", Effect) -end - -function Round.guicreate(Panel, Table) - acfmenupanel:AmmoSelect(ACF.AmmoBlacklist.AP) - - acfmenupanel:CPanelText("Desc", "") --Description (Name, Desc) - acfmenupanel:CPanelText("LengthDisplay", "") --Total round length (Name, Desc) - acfmenupanel:AmmoSlider("PropLength", 0, 0, 1000, 3, "Propellant Length", "") --Propellant Length Slider (Name, Value, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("ProjLength", 0, 0, 1000, 3, "Projectile Length", "") --Projectile Length Slider (Name, Value, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoCheckbox("Tracer", "Tracer", "") --Tracer checkbox (Name, Title, Desc) - acfmenupanel:CPanelText("VelocityDisplay", "") --Proj muzzle velocity (Name, Desc) - --acfmenupanel:CPanelText("RicoDisplay", "") --estimated rico chance - acfmenupanel:CPanelText("PenetrationDisplay", "") --Proj muzzle penetration (Name, Desc) - Round.guiupdate(Panel, Table) -end - -function Round.guiupdate(Panel) - local PlayerData = {} - PlayerData.Id = acfmenupanel.AmmoData.Data.id --AmmoSelect GUI - PlayerData.Type = "AP" --Hardcoded, match ACFRoundTypes table index - PlayerData.PropLength = acfmenupanel.AmmoData.PropLength --PropLength slider - PlayerData.ProjLength = acfmenupanel.AmmoData.ProjLength --ProjLength slider - local Tracer = 0 - - if acfmenupanel.AmmoData.Tracer then - Tracer = 1 - end - - PlayerData.Data10 = Tracer --Tracer - local Data = Round.convert(Panel, PlayerData) - RunConsoleCommand("acfmenu_data1", acfmenupanel.AmmoData.Data.id) - RunConsoleCommand("acfmenu_data2", PlayerData.Type) - RunConsoleCommand("acfmenu_data3", Data.PropLength) --For Gun ammo, Data3 should always be Propellant - RunConsoleCommand("acfmenu_data4", Data.ProjLength) --And Data4 total round mass - RunConsoleCommand("acfmenu_data10", Data.Tracer) - - acfmenupanel:AmmoUpdate() - acfmenupanel:AmmoSlider("PropLength", Data.PropLength, Data.MinPropLength, Data.MaxTotalLength, 3, "Propellant Length", "Propellant Mass : " .. (math.floor(Data.PropMass * 1000)) .. " g") --Propellant Length Slider (Name, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("ProjLength", Data.ProjLength, Data.MinProjLength, Data.MaxTotalLength, 3, "Projectile Length", "Projectile Mass : " .. (math.floor(Data.ProjMass * 1000)) .. " g") --Projectile Length Slider (Name, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoCheckbox("Tracer", "Tracer : " .. (math.floor(Data.Tracer * 10) / 10) .. "cm\n", "") --Tracer checkbox (Name, Title, Desc) - acfmenupanel:CPanelText("Desc", ACF.RoundTypes[PlayerData.Type].desc) --Description (Name, Desc) - acfmenupanel:CPanelText("LengthDisplay", "Cartridge Length : " .. (math.floor((Data.PropLength + Data.ProjLength + Data.Tracer) * 100) / 100) .. "/" .. Data.MaxTotalLength .. " cm") --Total round length (Name, Desc) - acfmenupanel:CPanelText("VelocityDisplay", "Muzzle Velocity : " .. math.floor(Data.MuzzleVel * ACF.Scale) .. " m\\s") --Proj muzzle velocity (Name, Desc) - --local RicoAngs = ACF_RicoProbability( Data.Ricochet, Data.MuzzleVel*ACF.Scale ) - --acfmenupanel:CPanelText("RicoDisplay", "Ricochet probability vs impact angle:\n".." 0% @ "..RicoAngs.Min.." degrees\n 50% @ "..RicoAngs.Mean.." degrees\n100% @ "..RicoAngs.Max.." degrees") - local R1V, R1P = ACF_PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 300) - local R2V, R2P = ACF_PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 800) - acfmenupanel:CPanelText("PenetrationDisplay", "Maximum Penetration : " .. math.floor(Data.MaxPen) .. " mm RHA\n\n300m pen: " .. math.Round(R1P, 0) .. "mm @ " .. math.Round(R1V, 0) .. " m\\s\n800m pen: " .. math.Round(R2P, 0) .. "mm @ " .. math.Round(R2V, 0) .. " m\\s\n\nThe range data is an approximation and may not be entirely accurate.") --Proj muzzle penetration (Name, Desc) -end - -ACF.RoundTypes.AP = Round -- DELETE - -ACF.RegisterAmmoDecal("AP", "damage/ap_pen", "damage/ap_rico") \ No newline at end of file diff --git a/lua/acf/shared/rounds/apcr.lua b/lua/acf/shared/rounds/apcr.lua deleted file mode 100644 index b9a57079c..000000000 --- a/lua/acf/shared/rounds/apcr.lua +++ /dev/null @@ -1,216 +0,0 @@ -ACF.AmmoBlacklist.APCR = { "MO", "SL", "HW", "MG", "SB", "GL", "AAM", "ARTY", "ASM", "BOMB", "GBU", "POD", "SAM", "UAR", "FFAR", "FGL" } - -local Round = {} - -Round.type = "Ammo" --Tells the spawn menu what entity to spawn -Round.name = "Armor Piercing, Composite Rigid (APCR)" --Human readable name -Round.model = "models/munitions/round_100mm_shot.mdl" --Shell flight model -Round.desc = "A hardened core munition designed for weapons in the 1940s. Short Cannons only." - -function Round.create(_, BulletData) - ACF_CreateBullet(BulletData) -end - --- Function to convert the player's slider data into the complete round data -function Round.convert(_, PlayerData) - local Data = {} - local ServerData = {} - local GUIData = {} - - if not PlayerData.PropLength then - PlayerData.PropLength = 0 - end - - if not PlayerData.ProjLength then - PlayerData.ProjLength = 0 - end - - if not PlayerData.Data10 then - PlayerData.Data10 = 0 - end - - PlayerData, Data, ServerData, GUIData = ACF_RoundBaseGunpowder(PlayerData, Data, ServerData, GUIData) - - Data.ProjMass = (Data.FrArea / 0.9) * (Data.ProjLength * 7.9 / 1000) * 0.75 --Volume of the projectile as a cylinder * density of steel - Data.ShovePower = 0.2 - Data.PenArea = (Data.FrArea * 0.7) ^ ACF.PenAreaMod -- APCR has a smaller penetrator - Data.DragCoef = (Data.FrArea * 1.25 / 10000) / Data.ProjMass -- But worse drag (Manually fudged to make a meaningful difference) - Data.LimitVel = 900 --Most efficient penetration speed in m/s - Data.KETransfert = 0.1 --Kinetic energy transfert to the target for movement purposes - Data.Ricochet = 55 --Base ricochet angle - Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass) - Data.CartMass = Data.PropMass + Data.ProjMass - - --Only the crates need this part - if SERVER then - ServerData.Id = PlayerData.Id - ServerData.Type = PlayerData.Type - return table.Merge(Data,ServerData) - end - - --Only the GUI needs this part - if CLIENT then - GUIData = table.Merge(GUIData, Round.getDisplayData(Data)) - return table.Merge(Data,GUIData) - end -end - -function Round.getDisplayData(Data) - local GUIData = {} - local Energy = ACF_Kinetic(Data.MuzzleVel * 39.37, Data.ProjMass, Data.LimitVel) - GUIData.MaxPen = (Energy.Penetration / Data.PenArea) * ACF.KEtoRHA - return GUIData -end - -function Round.network(Crate, BulletData) - Crate:SetNWString("AmmoType", "APCR") - Crate:SetNWString("AmmoID", BulletData.Id) - Crate:SetNWFloat("Caliber", BulletData.Caliber) - Crate:SetNWFloat("ProjMass", BulletData.ProjMass) - Crate:SetNWFloat("PropMass", BulletData.PropMass) - Crate:SetNWFloat("DragCoef", BulletData.DragCoef) - Crate:SetNWFloat("MuzzleVel", BulletData.MuzzleVel) - Crate:SetNWFloat("Tracer", BulletData.Tracer) -end - -function Round.cratetxt(BulletData) - local DData = Round.getDisplayData(BulletData) - - local str = - { - "Muzzle Velocity: ", math.Round(BulletData.MuzzleVel, 1), " m/s\n", - "Max Penetration: ", math.floor(DData.MaxPen), " mm" - } - - return table.concat(str) -end - -function Round.propimpact(_, Bullet, Target, HitNormal, HitPos, Bone) - if ACF_Check(Target) then - local Speed = Bullet.Flight:Length() / ACF.Scale - local Energy = ACF_Kinetic(Speed, Bullet.ProjMass, Bullet.LimitVel) - local HitRes = ACF_RoundImpact(Bullet, Speed, Energy, Target, HitPos, HitNormal, Bone) - - if HitRes.Overkill > 0 then - table.insert(Bullet.Filter, Target) --"Penetrate" (Ingoring the prop for the retry trace) - Bullet.Flight = Bullet.Flight:GetNormalized() * (Energy.Kinetic * (1-HitRes.Loss) * 2000 / Bullet.ProjMass) ^ 0.5 * 39.37 - return "Penetrated" - elseif HitRes.Ricochet then - return "Ricochet" - else - return false - end - end - - table.insert(Bullet.Filter, Target) - - return "Penetrated" -end - -function Round.worldimpact(_, Bullet, HitPos, HitNormal) - local Energy = ACF_Kinetic(Bullet.Flight:Length() / ACF.Scale, Bullet.ProjMass, Bullet.LimitVel) - local HitRes = ACF_PenetrateGround(Bullet, Energy, HitPos, HitNormal) - - if HitRes.Penetrated then - return "Penetrated" - elseif HitRes.Ricochet then - return "Ricochet" - else - return false - end -end - -function Round.endflight(Index) - ACF_RemoveBullet(Index) -end - -local DecalIndex = ACF.GetAmmoDecalIndex - -function Round.endeffect(_, Bullet) - local Effect = EffectData() - Effect:SetOrigin(Bullet.SimPos) - Effect:SetNormal(Bullet.SimFlight:GetNormalized()) - Effect:SetRadius(Bullet.Caliber) - Effect:SetDamageType(DecalIndex(Bullet.AmmoType)) - - util.Effect("ACF_Impact", Effect) -end - -function Round.pierceeffect(_, Bullet) - local Effect = EffectData() - Effect:SetOrigin(Bullet.SimPos) - Effect:SetNormal(Bullet.SimFlight:GetNormalized()) - Effect:SetScale(Bullet.SimFlight:Length()) - Effect:SetMagnitude(Bullet.RoundMass) - Effect:SetRadius(Bullet.Caliber) - Effect:SetDamageType(DecalIndex(Bullet.AmmoType)) - - util.Effect("ACF_Penetration", Effect) -end - -function Round.ricocheteffect(_, Bullet) - local Effect = EffectData() - Effect:SetOrigin(Bullet.SimPos) - Effect:SetNormal(Bullet.SimFlight:GetNormalized()) - Effect:SetScale(Bullet.SimFlight:Length()) - Effect:SetMagnitude(Bullet.RoundMass) - Effect:SetRadius(Bullet.Caliber) - Effect:SetDamageType(DecalIndex(Bullet.AmmoType)) - - util.Effect("ACF_Ricochet", Effect) -end - -function Round.guicreate(Panel, Table) - acfmenupanel:AmmoSelect(ACF.AmmoBlacklist.APCR) - - acfmenupanel:CPanelText("Desc", "") --Description (Name, Desc) - acfmenupanel:CPanelText("LengthDisplay", "") --Total round length (Name, Desc) - acfmenupanel:AmmoSlider("PropLength", 0, 0, 1000, 3, "Propellant Length", "") --Propellant Length Slider (Name, Value, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("ProjLength", 0, 0, 1000, 3, "Penetrator Length", "") --Projectile Length Slider (Name, Value, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoCheckbox("Tracer", "Tracer", "") --Tracer checkbox (Name, Title, Desc) - acfmenupanel:CPanelText("VelocityDisplay", "") --Proj muzzle velocity (Name, Desc) - acfmenupanel:CPanelText("PenetrationDisplay", "") --Proj muzzle penetration (Name, Desc) - - Round.guiupdate(Panel, Table) -end - -function Round.guiupdate(Panel) - local PlayerData = {} - PlayerData.Id = acfmenupanel.AmmoData.Data.id --AmmoSelect GUI - PlayerData.Type = "APCR" --Hardcoded, match ACFRoundTypes table index - PlayerData.PropLength = acfmenupanel.AmmoData.PropLength --PropLength slider - PlayerData.ProjLength = acfmenupanel.AmmoData.ProjLength --ProjLength slider - local Tracer = 0 - - if acfmenupanel.AmmoData.Tracer then - Tracer = 1 - end - - PlayerData.Data10 = Tracer --Tracer - - local Data = Round.convert(Panel, PlayerData) - RunConsoleCommand("acfmenu_data1", acfmenupanel.AmmoData.Data.id) - RunConsoleCommand("acfmenu_data2", PlayerData.Type) - RunConsoleCommand("acfmenu_data3", Data.PropLength) --For Gun ammo, Data3 should always be Propellant - RunConsoleCommand("acfmenu_data4", Data.ProjLength) --And Data4 total round mass - RunConsoleCommand("acfmenu_data10", Data.Tracer) - - acfmenupanel:AmmoUpdate() - acfmenupanel:AmmoSlider("PropLength", Data.PropLength, Data.MinPropLength, Data.MaxTotalLength, 3, "Propellant Length", "Propellant Mass : " .. (math.floor(Data.PropMass * 1000)) .. " g") --Propellant Length Slider (Name, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("ProjLength", Data.ProjLength, Data.MinProjLength, Data.MaxTotalLength, 3, "Penetrator Length", "Projectile Mass : " .. (math.floor(Data.ProjMass * 1000)) .. " g") --Projectile Length Slider (Name, Min, Max, Decimals, Title, Desc) - - acfmenupanel:AmmoCheckbox("Tracer", "Tracer : " .. (math.floor(Data.Tracer * 10) / 10) .. "cm\n", "") --Tracer checkbox (Name, Title, Desc) - - acfmenupanel:CPanelText("Desc", ACF.RoundTypes[PlayerData.Type].desc) --Description (Name, Desc) - acfmenupanel:CPanelText("LengthDisplay", "Cartridge Length : " .. (math.floor((Data.PropLength + Data.ProjLength + Data.Tracer) * 100) / 100) .. "/" .. Data.MaxTotalLength .. " cm") --Total round length (Name, Desc) - acfmenupanel:CPanelText("VelocityDisplay", "Muzzle Velocity : " .. math.floor(Data.MuzzleVel * ACF.Scale) .. " m\\s") --Proj muzzle velocity (Name, Desc) - - local R1V, R1P = ACF_PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 300) - local R2V, R2P = ACF_PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 800) - - acfmenupanel:CPanelText("PenetrationDisplay", "Maximum Penetration : " .. math.floor(Data.MaxPen) .. " mm RHA\n\n300m pen: " .. math.Round(R1P,0) .. "mm @ " .. math.Round(R1V,0) .. " m\\s\n800m pen: " .. math.Round(R2P,0) .. "mm @ " .. math.Round(R2V,0) .. " m\\s\n\nThe range data is an approximation and may not be entirely accurate.") --Proj muzzle penetration (Name, Desc) -end - -ACF.RoundTypes.APCR = Round -- DELETE - -ACF.RegisterAmmoDecal("APCR", "damage/apcr_pen", "damage/apcr_rico") diff --git a/lua/acf/shared/rounds/apds.lua b/lua/acf/shared/rounds/apds.lua deleted file mode 100644 index 7e04d2144..000000000 --- a/lua/acf/shared/rounds/apds.lua +++ /dev/null @@ -1,223 +0,0 @@ -ACF.AmmoBlacklist.APDS = { "MO", "SL", "HW", "SC", "MG", "SB", "GL", "HMG", "AAM", "ARTY", "ASM", "BOMB", "GBU", "POD", "SAM", "UAR", "FFAR", "FGL" } - -local Round = {} - -Round.type = "Ammo" --Tells the spawn menu what entity to spawn -Round.name = "Armor Piercing, Discarding Sabot (APDS)" --Human readable name -Round.model = "models/munitions/round_100mm_shot.mdl" --Shell flight model -Round.desc = "A subcaliber munition designed to trade damage for penetration. Loses energy quickly over distance." - -function Round.create(_, BulletData) - ACF_CreateBullet(BulletData) -end - --- Function to convert the player's slider data into the complete round data -function Round.convert(_, PlayerData) - local Data = {} - local ServerData = {} - local GUIData = {} - - if not PlayerData.PropLength then - PlayerData.PropLength = 0 - end - - if not PlayerData.ProjLength then - PlayerData.ProjLength = 0 - end - - if not PlayerData.Data10 then - PlayerData.Data10 = 0 - end - - PlayerData, Data, ServerData, GUIData = ACF_RoundBaseGunpowder(PlayerData, Data, ServerData, GUIData) - - local SubCaliberRatio = 0.375 -- Ratio of projectile to gun caliber - local Area = 3.1416 * (Data.Caliber * 0.5 * SubCaliberRatio) ^ 2 - - local DartMass = (Area / 1.5) * (Data.ProjLength * 7.9 / 1000) -- Volume of the projectile as a cylinder * density of steel - - local Cylinder = (3.1416 * (Data.Caliber * 0.5) ^ 2) * Data.ProjLength * 0.5 -- A cylinder 1/2 the length of the projectile - local Hole = Area * Data.ProjLength * 0.25 -- Volume removed by the hole the dart passes through - local SabotMass = (Cylinder - Hole) * 2.7 * 0.65 * 0.001 -- Aluminum sabot - - Data.ProjMass = DartMass - Data.ShovePower = 0.2 - Data.PenArea = Area ^ ACF.PenAreaMod - Data.DragCoef = (Area / 10000) / Data.ProjMass - Data.LimitVel = 950 --Most efficient penetration speed in m/s - Data.KETransfert = 0.1 --Kinetic energy transfert to the target for movement purposes - Data.Ricochet = 80 --Base ricochet angle - Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, DartMass + SabotMass) - Data.CartMass = Data.PropMass + DartMass + SabotMass - - --Only the crates need this part - if SERVER then - ServerData.Id = PlayerData.Id - ServerData.Type = PlayerData.Type - return table.Merge(Data,ServerData) - end - - --Only the GUI needs this part - if CLIENT then - GUIData = table.Merge(GUIData, Round.getDisplayData(Data)) - return table.Merge(Data,GUIData) - end -end - -function Round.getDisplayData(Data) - local GUIData = {} - local Energy = ACF_Kinetic(Data.MuzzleVel * 39.37, Data.ProjMass, Data.LimitVel) - GUIData.MaxPen = (Energy.Penetration / Data.PenArea) * ACF.KEtoRHA - return GUIData -end - -function Round.network(Crate, BulletData) - Crate:SetNWString("AmmoType", "APDS") - Crate:SetNWString("AmmoID", BulletData.Id) - Crate:SetNWFloat("Caliber", BulletData.Caliber) - Crate:SetNWFloat("ProjMass", BulletData.ProjMass) - Crate:SetNWFloat("PropMass", BulletData.PropMass) - Crate:SetNWFloat("DragCoef", BulletData.DragCoef) - Crate:SetNWFloat("MuzzleVel", BulletData.MuzzleVel) - Crate:SetNWFloat("Tracer", BulletData.Tracer) -end - -function Round.cratetxt(BulletData) - local DData = Round.getDisplayData(BulletData) - - local str = - { - "Muzzle Velocity: ", math.Round(BulletData.MuzzleVel, 1), " m/s\n", - "Max Penetration: ", math.floor(DData.MaxPen), " mm" - } - - return table.concat(str) -end - -function Round.propimpact(_, Bullet, Target, HitNormal, HitPos, Bone) - if ACF_Check(Target) then - local Speed = Bullet.Flight:Length() / ACF.Scale - local Energy = ACF_Kinetic(Speed, Bullet.ProjMass, Bullet.LimitVel) - local HitRes = ACF_RoundImpact(Bullet, Speed, Energy, Target, HitPos, HitNormal, Bone) - - if HitRes.Overkill > 0 then - table.insert(Bullet.Filter, Target) --"Penetrate" (Ingoring the prop for the retry trace) - Bullet.Flight = Bullet.Flight:GetNormalized() * (Energy.Kinetic * (1 - HitRes.Loss) * 2000 / Bullet.ProjMass) ^ 0.5 * 39.37 - return "Penetrated" - elseif HitRes.Ricochet then - return "Ricochet" - else - return false - end - end - - table.insert(Bullet.Filter, Target) - - return "Penetrated" -end - -function Round.worldimpact(_, Bullet, HitPos, HitNormal) - local Energy = ACF_Kinetic(Bullet.Flight:Length() / ACF.Scale, Bullet.ProjMass, Bullet.LimitVel) - local HitRes = ACF_PenetrateGround(Bullet, Energy, HitPos, HitNormal) - - if HitRes.Penetrated then - return "Penetrated" - elseif HitRes.Ricochet then - return "Ricochet" - else - return false - end -end - -function Round.endflight(Index) - ACF_RemoveBullet(Index) -end - -local DecalIndex = ACF.GetAmmoDecalIndex - -function Round.endeffect(_, Bullet) - local Effect = EffectData() - Effect:SetOrigin(Bullet.SimPos) - Effect:SetNormal(Bullet.SimFlight:GetNormalized()) - Effect:SetRadius(Bullet.Caliber) - Effect:SetDamageType(DecalIndex(Bullet.AmmoType)) - - util.Effect("ACF_Impact", Effect) -end - -function Round.pierceeffect(_, Bullet) - local Effect = EffectData() - Effect:SetOrigin(Bullet.SimPos) - Effect:SetNormal(Bullet.SimFlight:GetNormalized()) - Effect:SetScale(Bullet.SimFlight:Length()) - Effect:SetMagnitude(Bullet.RoundMass) - Effect:SetRadius(Bullet.Caliber) - Effect:SetDamageType(DecalIndex(Bullet.AmmoType)) - - util.Effect("ACF_Penetration", Effect) -end - -function Round.ricocheteffect(_, Bullet) - local Effect = EffectData() - Effect:SetOrigin(Bullet.SimPos) - Effect:SetNormal(Bullet.SimFlight:GetNormalized()) - Effect:SetScale(Bullet.SimFlight:Length()) - Effect:SetMagnitude(Bullet.RoundMass) - Effect:SetRadius(Bullet.Caliber) - Effect:SetDamageType(DecalIndex(Bullet.AmmoType)) - - util.Effect("ACF_Ricochet", Effect) -end - -function Round.guicreate(Panel, Table) - acfmenupanel:AmmoSelect(ACF.AmmoBlacklist.APDS) - - acfmenupanel:CPanelText("Desc", "") --Description (Name, Desc) - acfmenupanel:CPanelText("LengthDisplay", "") --Total round length (Name, Desc) - acfmenupanel:AmmoSlider("PropLength", 0, 0, 1000, 3, "Propellant Length", "") --Propellant Length Slider (Name, Value, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("ProjLength", 0, 0, 1000, 3, "Penetrator Length", "") --Projectile Length Slider (Name, Value, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoCheckbox("Tracer", "Tracer", "") --Tracer checkbox (Name, Title, Desc) - acfmenupanel:CPanelText("VelocityDisplay", "") --Proj muzzle velocity (Name, Desc) - acfmenupanel:CPanelText("PenetrationDisplay", "") --Proj muzzle penetration (Name, Desc) - - Round.guiupdate(Panel, Table) -end - -function Round.guiupdate(Panel) - local PlayerData = {} - PlayerData.Id = acfmenupanel.AmmoData.Data.id --AmmoSelect GUI - PlayerData.Type = "APDS" --Hardcoded, match ACFRoundTypes table index - PlayerData.PropLength = acfmenupanel.AmmoData.PropLength --PropLength slider - PlayerData.ProjLength = acfmenupanel.AmmoData.ProjLength --ProjLength slider - local Tracer = 0 - - if acfmenupanel.AmmoData.Tracer then - Tracer = 1 - end - - PlayerData.Data10 = Tracer --Tracer - - local Data = Round.convert(Panel, PlayerData) - RunConsoleCommand("acfmenu_data1", acfmenupanel.AmmoData.Data.id) - RunConsoleCommand("acfmenu_data2", PlayerData.Type) - RunConsoleCommand("acfmenu_data3", Data.PropLength) --For Gun ammo, Data3 should always be Propellant - RunConsoleCommand("acfmenu_data4", Data.ProjLength) --And Data4 total round mass - RunConsoleCommand("acfmenu_data10", Data.Tracer) - - acfmenupanel:AmmoUpdate() - acfmenupanel:AmmoSlider("PropLength", Data.PropLength, Data.MinPropLength, Data.MaxTotalLength, 3, "Propellant Length", "Propellant Mass : " .. (math.floor(Data.PropMass * 1000)) .. " g") --Propellant Length Slider (Name, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("ProjLength", Data.ProjLength, Data.MinProjLength, Data.MaxTotalLength, 3, "Penetrator Length", "Projectile Mass : " .. (math.floor(Data.ProjMass * 1000)) .. " g") --Projectile Length Slider (Name, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoCheckbox("Tracer", "Tracer : " .. (math.floor(Data.Tracer * 10) / 10) .. "cm\n", "") --Tracer checkbox (Name, Title, Desc) - acfmenupanel:CPanelText("Desc", ACF.RoundTypes[PlayerData.Type].desc) --Description (Name, Desc) - acfmenupanel:CPanelText("LengthDisplay", "Cartridge Length : " .. (math.floor((Data.PropLength + Data.ProjLength + Data.Tracer) * 100) / 100) .. "/" .. Data.MaxTotalLength .. " cm") --Total round length (Name, Desc) - acfmenupanel:CPanelText("VelocityDisplay", "Muzzle Velocity : " .. math.floor(Data.MuzzleVel * ACF.Scale) .. " m\\s") --Proj muzzle velocity (Name, Desc) - - local R1V, R1P = ACF_PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 300) - local R2V, R2P = ACF_PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 800) - - acfmenupanel:CPanelText("PenetrationDisplay", "Maximum Penetration : " .. math.floor(Data.MaxPen) .. " mm RHA\n\n300m pen: " .. math.Round(R1P,0) .. "mm @ " .. math.Round(R1V,0) .. " m\\s\n800m pen: " .. math.Round(R2P,0) .. "mm @ " .. math.Round(R2V,0) .. " m\\s\n\nThe range data is an approximation and may not be entirely accurate.") --Proj muzzle penetration (Name, Desc) -end - -ACF.RoundTypes.APDS = Round -- DELETE - -ACF.RegisterAmmoDecal("APDS", "damage/apcr_pen", "damage/apcr_rico") diff --git a/lua/acf/shared/rounds/apfsds.lua b/lua/acf/shared/rounds/apfsds.lua deleted file mode 100644 index dd216d42c..000000000 --- a/lua/acf/shared/rounds/apfsds.lua +++ /dev/null @@ -1,223 +0,0 @@ -ACF.AmmoBlacklist.APFSDS = { "MO", "SL", "C", "HW", "AC", "SC", "SA", "MG", "AL", "RAC", "GL", "HMG", "AAM", "ARTY", "ASM", "BOMB", "GBU", "POD", "SAM", "UAR", "FFAR", "FGL" } - -local Round = {} - -Round.type = "Ammo" --Tells the spawn menu what entity to spawn -Round.name = "AP Fin Stabilized, Discarding Sabot (APFSDS)" --Human readable name -Round.model = "models/munitions/dart_100mm.mdl" --Shell flight model -Round.desc = "A fin stabilized sabot munition designed to trade damage for superior penetration and long range effectiveness." - -function Round.create(_, BulletData) - ACF_CreateBullet(BulletData) -end - --- Function to convert the player's slider data into the complete round data -function Round.convert(_, PlayerData) - local Data = {} - local ServerData = {} - local GUIData = {} - - if not PlayerData.PropLength then - PlayerData.PropLength = 0 - end - - if not PlayerData.ProjLength then - PlayerData.ProjLength = 0 - end - - if not PlayerData.Data10 then - PlayerData.Data10 = 0 - end - - PlayerData, Data, ServerData, GUIData = ACF_RoundBaseGunpowder(PlayerData, Data, ServerData, GUIData) - - local SubCaliberRatio = 0.29 -- Ratio of projectile to gun caliber - local Area = 3.1416 * (Data.Caliber * 0.5 * SubCaliberRatio) ^ 2 - - local DartMass = (Area / 1.5) * (Data.ProjLength * 7.9 / 1000) -- Volume of the projectile as a cylinder * density of steel - - local Cylinder = (3.1416 * (Data.Caliber * 0.5) ^ 2) * Data.ProjLength * 0.25 -- A cylinder 1/4 the length of the projectile - local Hole = Area * Data.ProjLength * 0.25 -- Volume removed by the hole the dart passes through - local SabotMass = (Cylinder - Hole) * 2.7 * 0.25 * 0.001 -- A cylinder with a hole the size of the dart in it and im no math wizard so we're just going to take off 3/4 of the mass for the cutout since sabots are shaped like this: ][ - - Data.ProjMass = DartMass - Data.ShovePower = 0.2 - Data.PenArea = Area ^ ACF.PenAreaMod - Data.DragCoef = (Area / 10000) / Data.ProjMass - Data.LimitVel = 1000 --Most efficient penetration speed in m/s - Data.KETransfert = 0.1 --Kinetic energy transfert to the target for movement purposes - Data.Ricochet = 80 --Base ricochet angle - Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, DartMass + SabotMass) - Data.CartMass = Data.PropMass + DartMass + SabotMass - - --Only the crates need this part - if SERVER then - ServerData.Id = PlayerData.Id - ServerData.Type = PlayerData.Type - return table.Merge(Data, ServerData) - end - - --Only the GUI needs this part - if CLIENT then - GUIData = table.Merge(GUIData, Round.getDisplayData(Data)) - return table.Merge(Data, GUIData) - end -end - -function Round.getDisplayData(Data) - local GUIData = {} - local Energy = ACF_Kinetic(Data.MuzzleVel * 39.37, Data.ProjMass, Data.LimitVel) - GUIData.MaxPen = (Energy.Penetration / Data.PenArea) * ACF.KEtoRHA - return GUIData -end - -function Round.network(Crate, BulletData) - Crate:SetNWString("AmmoType", "APFSDS") - Crate:SetNWString("AmmoID", BulletData.Id) - Crate:SetNWFloat("Caliber", BulletData.Caliber) - Crate:SetNWFloat("ProjMass", BulletData.ProjMass) - Crate:SetNWFloat("PropMass", BulletData.PropMass) - Crate:SetNWFloat("DragCoef", BulletData.DragCoef) - Crate:SetNWFloat("MuzzleVel", BulletData.MuzzleVel) - Crate:SetNWFloat("Tracer", BulletData.Tracer) -end - -function Round.cratetxt(BulletData) - local DData = Round.getDisplayData(BulletData) - - local str = - { - "Muzzle Velocity: ", math.Round(BulletData.MuzzleVel, 1), " m/s\n", - "Max Penetration: ", math.floor(DData.MaxPen), " mm" - } - - return table.concat(str) -end - -function Round.propimpact(_, Bullet, Target, HitNormal, HitPos, Bone) - if ACF_Check(Target) then - local Speed = Bullet.Flight:Length() / ACF.Scale - local Energy = ACF_Kinetic(Speed, Bullet.ProjMass, Bullet.LimitVel) - local HitRes = ACF_RoundImpact(Bullet, Speed, Energy, Target, HitPos, HitNormal, Bone) - - if HitRes.Overkill > 0 then - table.insert(Bullet.Filter, Target) --"Penetrate" (Ingoring the prop for the retry trace) - Bullet.Flight = Bullet.Flight:GetNormalized() * (Energy.Kinetic * (1 - HitRes.Loss) * 2000 / Bullet.ProjMass) ^ 0.5 * 39.37 - return "Penetrated" - elseif HitRes.Ricochet then - return "Ricochet" - else - return false - end - end - - table.insert(Bullet.Filter, Target) - - return "Penetrated" -end - -function Round.worldimpact(_, Bullet, HitPos, HitNormal) - local Energy = ACF_Kinetic(Bullet.Flight:Length() / ACF.Scale, Bullet.ProjMass, Bullet.LimitVel) - local HitRes = ACF_PenetrateGround(Bullet, Energy, HitPos, HitNormal) - - if HitRes.Penetrated then - return "Penetrated" - elseif HitRes.Ricochet then - return "Ricochet" - else - return false - end -end - -function Round.endflight(Index) - ACF_RemoveBullet(Index) -end - -local DecalIndex = ACF.GetAmmoDecalIndex - -function Round.endeffect(_, Bullet) - local Effect = EffectData() - Effect:SetOrigin(Bullet.SimPos) - Effect:SetNormal(Bullet.SimFlight:GetNormalized()) - Effect:SetRadius(Bullet.Caliber) - Effect:SetDamageType(DecalIndex(Bullet.AmmoType)) - - util.Effect("ACF_Impact", Effect) -end - -function Round.pierceeffect(_, Bullet) - local Effect = EffectData() - Effect:SetOrigin(Bullet.SimPos) - Effect:SetNormal(Bullet.SimFlight:GetNormalized()) - Effect:SetScale(Bullet.SimFlight:Length()) - Effect:SetMagnitude(Bullet.RoundMass) - Effect:SetRadius(Bullet.Caliber) - Effect:SetDamageType(DecalIndex(Bullet.AmmoType)) - - util.Effect("ACF_Penetration", Effect) -end - -function Round.ricocheteffect(_, Bullet) - local Effect = EffectData() - Effect:SetOrigin(Bullet.SimPos) - Effect:SetNormal(Bullet.SimFlight:GetNormalized()) - Effect:SetScale(Bullet.SimFlight:Length()) - Effect:SetMagnitude(Bullet.RoundMass) - Effect:SetRadius(Bullet.Caliber) - Effect:SetDamageType(DecalIndex(Bullet.AmmoType)) - - util.Effect("ACF_Ricochet", Effect) -end - -function Round.guicreate(Panel, Table) - acfmenupanel:AmmoSelect(ACF.AmmoBlacklist.APFSDS) - - acfmenupanel:CPanelText("Desc", "") --Description (Name, Desc) - acfmenupanel:CPanelText("LengthDisplay", "") --Total round length (Name, Desc) - acfmenupanel:AmmoSlider("PropLength", 0, 0, 1000, 3, "Propellant Length", "") --Propellant Length Slider (Name, Value, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("ProjLength", 0, 0, 1000, 3, "Penetrator Length", "") --Projectile Length Slider (Name, Value, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoCheckbox("Tracer", "Tracer", "") --Tracer checkbox (Name, Title, Desc) - acfmenupanel:CPanelText("VelocityDisplay", "") --Proj muzzle velocity (Name, Desc) - acfmenupanel:CPanelText("PenetrationDisplay", "") --Proj muzzle penetration (Name, Desc) - - Round.guiupdate(Panel, Table) -end - -function Round.guiupdate(Panel) - local PlayerData = {} - PlayerData.Id = acfmenupanel.AmmoData.Data.id --AmmoSelect GUI - PlayerData.Type = "APFSDS" --Hardcoded, match ACFRoundTypes table index - PlayerData.PropLength = acfmenupanel.AmmoData.PropLength --PropLength slider - PlayerData.ProjLength = acfmenupanel.AmmoData.ProjLength --ProjLength slider - local Tracer = 0 - - if acfmenupanel.AmmoData.Tracer then - Tracer = 1 - end - - PlayerData.Data10 = Tracer --Tracer - - local Data = Round.convert(Panel, PlayerData) - RunConsoleCommand("acfmenu_data1", acfmenupanel.AmmoData.Data.id) - RunConsoleCommand("acfmenu_data2", PlayerData.Type) - RunConsoleCommand("acfmenu_data3", Data.PropLength) --For Gun ammo, Data3 should always be Propellant - RunConsoleCommand("acfmenu_data4", Data.ProjLength) --And Data4 total round mass - RunConsoleCommand("acfmenu_data10", Data.Tracer) - - acfmenupanel:AmmoUpdate() - acfmenupanel:AmmoSlider("PropLength", Data.PropLength, Data.MinPropLength, Data.MaxTotalLength, 3, "Propellant Length", "Propellant Mass : " .. (math.floor(Data.PropMass * 1000)) .. " g") --Propellant Length Slider (Name, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("ProjLength", Data.ProjLength, Data.MinProjLength, Data.MaxTotalLength, 3, "Penetrator Length", "Projectile Mass : " .. (math.floor(Data.ProjMass * 1000)) .. " g") --Projectile Length Slider (Name, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoCheckbox("Tracer", "Tracer : " .. (math.floor(Data.Tracer * 10) / 10) .. "cm\n", "") --Tracer checkbox (Name, Title, Desc) - acfmenupanel:CPanelText("Desc", ACF.RoundTypes[PlayerData.Type].desc) --Description (Name, Desc) - acfmenupanel:CPanelText("LengthDisplay", "Cartridge Length : " .. (math.floor((Data.PropLength + Data.ProjLength + Data.Tracer) * 100) / 100) .. "/" .. Data.MaxTotalLength .. " cm") --Total round length (Name, Desc) - acfmenupanel:CPanelText("VelocityDisplay", "Muzzle Velocity : " .. math.floor(Data.MuzzleVel * ACF.Scale) .. " m\\s") --Proj muzzle velocity (Name, Desc) - - local R1V, R1P = ACF_PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 300) - local R2V, R2P = ACF_PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 800) - - acfmenupanel:CPanelText("PenetrationDisplay", "Maximum Penetration : " .. math.floor(Data.MaxPen) .. " mm RHA\n\n300m pen: " .. math.Round(R1P,0) .. "mm @ " .. math.Round(R1V,0) .. " m\\s\n800m pen: " .. math.Round(R2P,0) .. "mm @ " .. math.Round(R2V,0) .. " m\\s\n\nThe range data is an approximation and may not be entirely accurate.") --Proj muzzle penetration (Name, Desc) -end - -ACF.RoundTypes.APFSDS = Round -- DELETE - -ACF.RegisterAmmoDecal("APFSDS", "damage/apcr_pen", "damage/apcr_rico") diff --git a/lua/acf/shared/rounds/aphe.lua b/lua/acf/shared/rounds/aphe.lua deleted file mode 100644 index cfe5b1a0d..000000000 --- a/lua/acf/shared/rounds/aphe.lua +++ /dev/null @@ -1,246 +0,0 @@ -ACF.AmmoBlacklist.APHE = {"MO", "MG", "RAC", "SL"} -local Round = {} -Round.type = "Ammo" --Tells the spawn menu what entity to spawn -Round.name = "Armour Piercing Explosive (APHE)" --Human readable name -Round.model = "models/munitions/round_100mm_shot.mdl" --Shell flight model -Round.desc = "An armour piercing round with a cavity for High explosives. Less capable of defeating armour than plain Armour Piercing, but will explode after penetration" - -function Round.create(_, BulletData) - ACF_CreateBullet(BulletData) -end - --- Function to convert the player's slider data into the complete round data -function Round.convert(_, PlayerData) - local Data = {} - local ServerData = {} - local GUIData = {} - - if not PlayerData.PropLength then - PlayerData.PropLength = 0 - end - - if not PlayerData.ProjLength then - PlayerData.ProjLength = 0 - end - - PlayerData.Data5 = math.max(PlayerData.Data5 or 0, 0) - - if not PlayerData.Data10 then - PlayerData.Data10 = 0 - end - - PlayerData, Data, ServerData, GUIData = ACF_RoundBaseGunpowder(PlayerData, Data, ServerData, GUIData) - --Shell sturdiness calcs - Data.ProjMass = math.max(GUIData.ProjVolume - PlayerData.Data5, 0) * 7.9 / 1000 + math.min(PlayerData.Data5, GUIData.ProjVolume) * ACF.HEDensity / 1000 --Volume of the projectile as a cylinder - Volume of the filler * density of steel + Volume of the filler * density of TNT - Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass, Data.Caliber) - local Energy = ACF_Kinetic(Data.MuzzleVel * 39.37, Data.ProjMass, Data.LimitVel) - local MaxVol = ACF_RoundShellCapacity(Energy.Momentum, Data.FrArea, Data.Caliber, Data.ProjLength) - GUIData.MinFillerVol = 0 - GUIData.MaxFillerVol = math.min(GUIData.ProjVolume, MaxVol * 0.9) - GUIData.FillerVol = math.min(PlayerData.Data5, GUIData.MaxFillerVol) - Data.FillerMass = GUIData.FillerVol * ACF.HEDensity / 1000 - Data.ProjMass = math.max(GUIData.ProjVolume - GUIData.FillerVol, 0) * 7.9 / 1000 + Data.FillerMass - Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass, Data.Caliber) - --Random bullshit left - Data.ShovePower = 0.1 - Data.PenArea = Data.FrArea ^ ACF.PenAreaMod - Data.DragCoef = ((Data.FrArea / 10000) / Data.ProjMass) - Data.LimitVel = 700 --Most efficient penetration speed in m/s - Data.KETransfert = 0.1 --Kinetic energy transfert to the target for movement purposes - Data.Ricochet = 65 --Base ricochet angle - Data.CartMass = Data.PropMass + Data.ProjMass - - --Only the crates need this part - if SERVER then - ServerData.Id = PlayerData.Id - ServerData.Type = PlayerData.Type - - return table.Merge(Data, ServerData) - end - - --Only the GUI needs this part - if CLIENT then - GUIData = table.Merge(GUIData, Round.getDisplayData(Data)) - - return table.Merge(Data, GUIData) - end -end - -function Round.getDisplayData(Data) - local GUIData = {} - local Energy = ACF_Kinetic(Data.MuzzleVel * 39.37, Data.ProjMass, Data.LimitVel) - GUIData.MaxPen = (Energy.Penetration / Data.PenArea) * ACF.KEtoRHA - GUIData.BlastRadius = Data.FillerMass ^ 0.33 * 8 - local FragMass = Data.ProjMass - Data.FillerMass - GUIData.Fragments = math.max(math.floor((Data.FillerMass / FragMass) * ACF.HEFrag), 2) - GUIData.FragMass = FragMass / GUIData.Fragments - GUIData.FragVel = (Data.FillerMass * ACF.HEPower * 1000 / GUIData.FragMass / GUIData.Fragments) ^ 0.5 - - return GUIData -end - -function Round.network(Crate, BulletData) - Crate:SetNWString("AmmoType", "APHE") - Crate:SetNWString("AmmoID", BulletData.Id) - Crate:SetNWFloat("Caliber", BulletData.Caliber) - Crate:SetNWFloat("ProjMass", BulletData.ProjMass) - Crate:SetNWFloat("FillerMass", BulletData.FillerMass) - Crate:SetNWFloat("PropMass", BulletData.PropMass) - Crate:SetNWFloat("DragCoef", BulletData.DragCoef) - Crate:SetNWFloat("MuzzleVel", BulletData.MuzzleVel) - Crate:SetNWFloat("Tracer", BulletData.Tracer) -end - -function Round.cratetxt(BulletData) - local DData = Round.getDisplayData(BulletData) - local str = { - "Muzzle Velocity: ", math.Round(BulletData.MuzzleVel, 1), " m/s\n", - "Max Penetration: ", math.floor(DData.MaxPen), "mm\n", - "Blast Radius: ", math.Round(DData.BlastRadius, 1), "m\n", - "Blast Energy: ", math.floor(BulletData.FillerMass * ACF.HEPower), "kJ\n", - "Filler Mass: ", math.Round(BulletData.FillerMass * 1000, 2), "g\n", - "Avg. Frag Mass: ", math.Round(DData.FragMass * 1000, 2), "g\n", - "Case Mass: ", math.Round((BulletData.ProjMass - BulletData.FillerMass) * 1000, 2), "g", - } - - return table.concat(str) -end - -function Round.propimpact(_, Bullet, Target, HitNormal, HitPos, Bone) - if ACF_Check(Target) then - local Speed = Bullet.Flight:Length() / ACF.Scale - local Energy = ACF_Kinetic(Speed, Bullet.ProjMass, Bullet.LimitVel) - local HitRes = ACF_RoundImpact(Bullet, Speed, Energy, Target, HitPos, HitNormal, Bone) - - if HitRes.Overkill > 0 then - table.insert(Bullet.Filter, Target) --"Penetrate" (Ingoring the prop for the retry trace) - Bullet.Flight = Bullet.Flight:GetNormalized() * (Energy.Kinetic * (1 - HitRes.Loss) * 2000 / Bullet.ProjMass) ^ 0.5 * 39.37 - - return "Penetrated" - elseif HitRes.Ricochet then - return "Ricochet" - else - return false - end - else - table.insert(Bullet.Filter, Target) - - return "Penetrated" - end -end - -function Round.worldimpact(_, Bullet, HitPos, HitNormal) - local Energy = ACF_Kinetic(Bullet.Flight:Length() / ACF.Scale, Bullet.ProjMass, Bullet.LimitVel) - local HitRes = ACF_PenetrateGround(Bullet, Energy, HitPos, HitNormal) - - if HitRes.Penetrated then - return "Penetrated" - elseif HitRes.Ricochet then - return "Ricochet" - else - return false - end -end - -function Round.endflight(Index, Bullet, HitPos) - ACF_HE(HitPos, Bullet.FillerMass, Bullet.ProjMass - Bullet.FillerMass, Bullet.Owner, nil, Bullet.Gun) - ACF_RemoveBullet(Index) -end - -local DecalIndex = ACF.GetAmmoDecalIndex - -function Round.endeffect(_, Bullet) - local Effect = EffectData() - Effect:SetOrigin(Bullet.SimPos) - Effect:SetNormal(Bullet.SimFlight:GetNormalized()) - Effect:SetScale(math.max(Bullet.FillerMass ^ 0.33 * 8 * 39.37, 1)) - Effect:SetRadius(Bullet.Caliber) - - util.Effect("ACF_Explosion", Effect) -end - -function Round.pierceeffect(_, Bullet) - local Effect = EffectData() - Effect:SetOrigin(Bullet.SimPos) - Effect:SetNormal(Bullet.SimFlight:GetNormalized()) - Effect:SetScale(Bullet.SimFlight:Length()) - Effect:SetMagnitude(Bullet.RoundMass) - Effect:SetRadius(Bullet.Caliber) - Effect:SetDamageType(DecalIndex(Bullet.AmmoType)) - - util.Effect("ACF_Penetration", Effect) -end - -function Round.ricocheteffect(_, Bullet) - local Effect = EffectData() - Effect:SetOrigin(Bullet.SimPos) - Effect:SetNormal(Bullet.SimFlight:GetNormalized()) - Effect:SetScale(Bullet.SimFlight:Length()) - Effect:SetMagnitude(Bullet.RoundMass) - Effect:SetRadius(Bullet.Caliber) - Effect:SetDamageType(DecalIndex(Bullet.AmmoType)) - - util.Effect("ACF_Ricochet", Effect) -end - -function Round.guicreate(Panel, Table) - acfmenupanel:AmmoSelect(ACF.AmmoBlacklist.APHE) - - acfmenupanel:CPanelText("Desc", "") --Description (Name, Desc) - acfmenupanel:CPanelText("LengthDisplay", "") --Total round length (Name, Desc) - acfmenupanel:AmmoSlider("PropLength", 0, 0, 1000, 3, "Propellant Length", "") --Propellant Length Slider (Name, Value, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("ProjLength", 0, 0, 1000, 3, "Projectile Length", "") --Projectile Length Slider (Name, Value, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("FillerVol", 0, 0, 1000, 3, "HE Filler", "") --Hollow Point Cavity Slider (Name, Value, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoCheckbox("Tracer", "Tracer", "") --Tracer checkbox (Name, Title, Desc) - acfmenupanel:CPanelText("VelocityDisplay", "") --Proj muzzle velocity (Name, Desc) - acfmenupanel:CPanelText("PenetrationDisplay", "") --Proj muzzle penetration (Name, Desc) - acfmenupanel:CPanelText("BlastDisplay", "") --HE Blast data (Name, Desc) - acfmenupanel:CPanelText("FragDisplay", "") --HE Fragmentation data (Name, Desc) - --acfmenupanel:CPanelText("RicoDisplay", "") --estimated rico chance - acfmenupanel:CPanelText("PenetrationRanging", "") --penetration ranging (Name, Desc) - Round.guiupdate(Panel, Table) -end - -function Round.guiupdate(Panel) - local PlayerData = {} - PlayerData.Id = acfmenupanel.AmmoData.Data.id --AmmoSelect GUI - PlayerData.Type = "APHE" --Hardcoded, match ACFRoundTypes table index - PlayerData.PropLength = acfmenupanel.AmmoData.PropLength --PropLength slider - PlayerData.ProjLength = acfmenupanel.AmmoData.ProjLength --ProjLength slider - PlayerData.Data5 = acfmenupanel.AmmoData.FillerVol - local Tracer = 0 - - if acfmenupanel.AmmoData.Tracer then - Tracer = 1 - end - - PlayerData.Data10 = Tracer --Tracer - local Data = Round.convert(Panel, PlayerData) - RunConsoleCommand("acfmenu_data1", acfmenupanel.AmmoData.Data.id) - RunConsoleCommand("acfmenu_data2", PlayerData.Type) - RunConsoleCommand("acfmenu_data3", Data.PropLength) --For Gun ammo, Data3 should always be Propellant - RunConsoleCommand("acfmenu_data4", Data.ProjLength) --And Data4 total round mass - RunConsoleCommand("acfmenu_data5", Data.FillerVol) - RunConsoleCommand("acfmenu_data10", Data.Tracer) - - acfmenupanel:AmmoUpdate() - acfmenupanel:AmmoSlider("PropLength", Data.PropLength, Data.MinPropLength, Data.MaxTotalLength, 3, "Propellant Length", "Propellant Mass : " .. (math.floor(Data.PropMass * 1000)) .. " g") --Propellant Length Slider (Name, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("ProjLength", Data.ProjLength, Data.MinProjLength, Data.MaxTotalLength, 3, "Projectile Length", "Projectile Mass : " .. (math.floor(Data.ProjMass * 1000)) .. " g") --Projectile Length Slider (Name, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("FillerVol", Data.FillerVol, Data.MinFillerVol, Data.MaxFillerVol, 3, "HE Filler Volume", "HE Filler Mass : " .. (math.floor(Data.FillerMass * 1000)) .. " g") --HE Filler Slider (Name, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoCheckbox("Tracer", "Tracer : " .. (math.floor(Data.Tracer * 10) / 10) .. "cm\n", "") --Tracer checkbox (Name, Title, Desc) - acfmenupanel:CPanelText("Desc", ACF.RoundTypes[PlayerData.Type].desc) --Description (Name, Desc) - acfmenupanel:CPanelText("LengthDisplay", "Cartridge Length : " .. (math.floor((Data.PropLength + Data.ProjLength + Data.Tracer) * 100) / 100) .. "/" .. Data.MaxTotalLength .. " cm") --Total round length (Name, Desc) - acfmenupanel:CPanelText("VelocityDisplay", "Muzzle Velocity : " .. math.floor(Data.MuzzleVel * ACF.Scale) .. " m/s") --Proj muzzle velocity (Name, Desc) - acfmenupanel:CPanelText("PenetrationDisplay", "Maximum Penetration : " .. math.floor(Data.MaxPen) .. " mm RHA") --Proj muzzle penetration (Name, Desc) - acfmenupanel:CPanelText("BlastDisplay", "Blast Radius : " .. (math.floor(Data.BlastRadius * 100) / 100) .. " m") --Proj muzzle velocity (Name, Desc) - acfmenupanel:CPanelText("FragDisplay", "Fragments : " .. Data.Fragments .. "\n Average Fragment Weight : " .. (math.floor(Data.FragMass * 10000) / 10) .. " g \n Average Fragment Velocity : " .. math.floor(Data.FragVel) .. " m/s") --Proj muzzle penetration (Name, Desc) - --local RicoAngs = ACF_RicoProbability( Data.Ricochet, Data.MuzzleVel*ACF.Scale ) - --acfmenupanel:CPanelText("RicoDisplay", "Ricochet probability vs impact angle:\n".." 0% @ "..RicoAngs.Min.." degrees\n 50% @ "..RicoAngs.Mean.." degrees\n100% @ "..RicoAngs.Max.." degrees") - local R1V, R1P = ACF_PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 300) - local R2V, R2P = ACF_PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 800) - acfmenupanel:CPanelText("PenetrationRanging", "\n300m pen: " .. math.Round(R1P, 0) .. "mm @ " .. math.Round(R1V, 0) .. " m\\s\n800m pen: " .. math.Round(R2P, 0) .. "mm @ " .. math.Round(R2V, 0) .. " m\\s\n\nThe range data is an approximation and may not be entirely accurate.") --Proj muzzle penetration (Name, Desc) -end - -ACF.RoundTypes.APHE = Round -- DELETE - -ACF.RegisterAmmoDecal("APHE", "damage/ap_pen", "damage/ap_rico") \ No newline at end of file diff --git a/lua/acf/shared/rounds/fl.lua b/lua/acf/shared/rounds/fl.lua deleted file mode 100644 index f8297f5d5..000000000 --- a/lua/acf/shared/rounds/fl.lua +++ /dev/null @@ -1,317 +0,0 @@ -ACF.AmmoBlacklist["FL"] = {"AC", "RAC", "MG", "HMG", "GL", "SL"} -local Round = {} -Round.type = "Ammo" --Tells the spawn menu what entity to spawn -Round.name = "Flechette (FL)" --Human readable name -Round.model = "models/munitions/dart_100mm.mdl" --Shell flight model -Round.desc = "Flechette rounds contain several long thin steel spikes, functioning as a shotgun shell for cannons. While it seems like the spikes would penetrate well, they tend to tumble in flight and impact at less than ideal angles, causing only minor penetration and structural damage. They are best used against infantry or lightly armored mobile targets such as aircraft or light tanks, since flechettes trade brute damage for a better chance to hit." - -function Round.create(Gun, BulletData) - --setup flechettes - local FlechetteData = {} - FlechetteData["Caliber"] = math.Round(BulletData["FlechetteRadius"] * 0.2, 2) - FlechetteData["Id"] = BulletData["Id"] - FlechetteData["Type"] = "AP" --BulletData["Type"] - FlechetteData["Owner"] = BulletData["Owner"] - FlechetteData["Crate"] = BulletData["Crate"] - FlechetteData["Gun"] = BulletData["Gun"] - FlechetteData["Pos"] = BulletData["Pos"] - FlechetteData["FrArea"] = BulletData["FlechetteArea"] - FlechetteData["ProjMass"] = BulletData["FlechetteMass"] - FlechetteData["DragCoef"] = BulletData["FlechetteDragCoef"] - FlechetteData["Tracer"] = BulletData["Tracer"] - FlechetteData["LimitVel"] = BulletData["LimitVel"] - FlechetteData["Ricochet"] = BulletData["Ricochet"] - FlechetteData["PenArea"] = BulletData["FlechettePenArea"] - FlechetteData["ShovePower"] = BulletData["ShovePower"] - FlechetteData["KETransfert"] = BulletData["KETransfert"] - - local MuzzleVec - - --if ammo is cooking off, shoot in random direction - if Gun:GetClass() == "acf_ammo" then - local Inaccuracy - MuzzleVec = VectorRand() - - for _ = 1, BulletData["Flechettes"] do - Inaccuracy = VectorRand() / 360 * ((Gun.Spread or 0) + BulletData["FlechetteSpread"]) - FlechetteData["Flight"] = (MuzzleVec + Inaccuracy):GetNormalized() * BulletData["MuzzleVel"] * 39.37 + Gun:GetVelocity() - ACF_CreateBullet(FlechetteData) - end - else - local BaseInaccuracy = math.tan(math.rad(Gun:GetSpread())) - local AddInaccuracy = math.tan(math.rad(BulletData["FlechetteSpread"])) - MuzzleVec = Gun:GetForward() - - for _ = 1, BulletData["Flechettes"] do - BaseSpread = BaseInaccuracy * (math.random() ^ (1 / math.Clamp(ACF.GunInaccuracyBias, 0.5, 4))) * (Gun:GetUp() * (2 * math.random() - 1) + Gun:GetRight() * (2 * math.random() - 1)):GetNormalized() - AddSpread = AddInaccuracy * (math.random() ^ (1 / math.Clamp(ACF.GunInaccuracyBias, 0.5, 4))) * (Gun:GetUp() * (2 * math.random() - 1) + Gun:GetRight() * (2 * math.random() - 1)):GetNormalized() - FlechetteData["Flight"] = (MuzzleVec + BaseSpread + AddSpread):GetNormalized() * BulletData["MuzzleVel"] * 39.37 + Gun:GetVelocity() - ACF_CreateBullet(FlechetteData) - end - end -end - --- Function to convert the player's slider data into the complete round data -function Round.convert(_, PlayerData) - local Data = {} - local ServerData = {} - local GUIData = {} - Data["LengthAdj"] = 0.5 - - if not PlayerData["PropLength"] then - PlayerData["PropLength"] = 0 - end - - if not PlayerData["ProjLength"] then - PlayerData["ProjLength"] = 0 - end - - --flechette count - if not PlayerData["Data5"] then - PlayerData["Data5"] = 3 - end - - --flechette spread - if not PlayerData["Data6"] then - PlayerData["Data6"] = 5 - end - - --tracer - if not PlayerData["Data10"] then - PlayerData["Data10"] = 0 - end - - PlayerData, Data, ServerData, GUIData = ACF_RoundBaseGunpowder(PlayerData, Data, ServerData, GUIData) - local GunClass = ACF.Weapons["Guns"][Data["Id"] or PlayerData["Id"]]["gunclass"] - - if GunClass == "SA" then - Data["MaxFlechettes"] = math.Clamp(math.floor(Data["Caliber"] * 3 - 4.5), 1, 32) - elseif GunClass == "MO" then - Data["MaxFlechettes"] = math.Clamp(math.floor(Data["Caliber"] * 4) - 12, 1, 32) - elseif GunClass == "HW" then - Data["MaxFlechettes"] = math.Clamp(math.floor(Data["Caliber"] * 4) - 10, 1, 32) - else - Data["MaxFlechettes"] = math.Clamp(math.floor(Data["Caliber"] * 4) - 8, 1, 32) - end - - Data["MinFlechettes"] = math.min(6, Data["MaxFlechettes"]) --force bigger guns to have higher min count - Data["Flechettes"] = math.Clamp(math.floor(PlayerData["Data5"]), Data["MinFlechettes"], Data["MaxFlechettes"]) --number of flechettes - Data["MinSpread"] = 0.25 - Data["MaxSpread"] = 30 - Data["FlechetteSpread"] = math.Clamp(tonumber(PlayerData["Data6"]), Data["MinSpread"], Data["MaxSpread"]) - local PenAdj = 0.8 --higher means lower pen, but more structure (hp) damage (old: 2.35, 2.85) - local RadiusAdj = 1.0 -- lower means less structure (hp) damage, but higher pen (old: 1.0, 0.8) - local PackRatio = 0.0025 * Data["Flechettes"] + 0.69 --how efficiently flechettes are packed into shell - Data["FlechetteRadius"] = math.sqrt(((PackRatio * RadiusAdj * Data["Caliber"] / 2) ^ 2) / Data["Flechettes"]) -- max radius flechette can be, to fit number of flechettes in a shell - Data["FlechetteArea"] = 3.1416 * Data["FlechetteRadius"] ^ 2 -- area of a single flechette - Data["FlechetteMass"] = Data["FlechetteArea"] * (Data["ProjLength"] * 7.9 / 1000) -- volume of single flechette * density of steel - Data["FlechettePenArea"] = (PenAdj * Data["FlechetteArea"]) ^ ACF.PenAreaMod - Data["FlechetteDragCoef"] = (Data["FlechetteArea"] / 10000) / Data["FlechetteMass"] - Data["ProjMass"] = Data["Flechettes"] * Data["FlechetteMass"] -- total mass of all flechettes - Data["PropMass"] = Data["PropMass"] - Data["ShovePower"] = 0.2 - Data["PenArea"] = Data["FrArea"] ^ ACF.PenAreaMod - Data["DragCoef"] = ((Data["FrArea"] / 10000) / Data["ProjMass"]) - Data["LimitVel"] = 500 --Most efficient penetration speed in m/s - Data["KETransfert"] = 0.1 --Kinetic energy transfert to the target for movement purposes - Data["Ricochet"] = 75 --Base ricochet angle - Data["MuzzleVel"] = ACF_MuzzleVelocity(Data["PropMass"], Data["ProjMass"], Data["Caliber"]) - Data.CartMass = Data.PropMass + Data.ProjMass - - --Only the crates need this part - if SERVER then - ServerData["Id"] = PlayerData["Id"] - ServerData["Type"] = PlayerData["Type"] - - return table.Merge(Data, ServerData) - end - - --Only the GUI needs this part - if CLIENT then - GUIData = table.Merge(GUIData, Round.getDisplayData(Data, PlayerData)) - - return table.Merge(Data, GUIData) - end -end - -function Round.getDisplayData(Data) - local GUIData = {} - local Energy = ACF_Kinetic(Data["MuzzleVel"] * 39.37, Data["FlechetteMass"], Data["LimitVel"]) - GUIData["MaxPen"] = (Energy.Penetration / Data["FlechettePenArea"]) * ACF.KEtoRHA - - return GUIData -end - -function Round.network(Crate, BulletData) - Crate:SetNWString("AmmoType", "FL") - Crate:SetNWString("AmmoID", BulletData["Id"]) - Crate:SetNWFloat("PropMass", BulletData["PropMass"]) - Crate:SetNWFloat("MuzzleVel", BulletData["MuzzleVel"]) - Crate:SetNWFloat("Tracer", BulletData["Tracer"]) - -- bullet effects use networked data, so set these to the flechette stats - Crate:SetNWFloat("Caliber", math.Round(BulletData["FlechetteRadius"] * 0.2, 2)) - Crate:SetNWFloat("ProjMass", BulletData["FlechetteMass"]) - Crate:SetNWFloat("DragCoef", BulletData["FlechetteDragCoef"]) - Crate:SetNWFloat("FillerMass", 0) - --Crate:SetNWFloat("Caliber",BulletData["Caliber"]) - --Crate:SetNWFloat("ProjMass",BulletData["ProjMass"]) - --Crate:SetNWFloat("DragCoef",BulletData["DragCoef"]) -end - -function Round.cratetxt(BulletData) - local DData = Round.getDisplayData(BulletData) - local inaccuracy = 0 - local Gun = ACF.Weapons.Guns[BulletData.Id] - - if Gun then - local Classes = ACF.Classes - - inaccuracy = (Classes.GunClass[Gun.gunclass] or { - spread = 0 - }).spread - end - - local coneAng = inaccuracy * ACF.GunInaccuracyScale - local str = {"Muzzle Velocity: ", math.Round(BulletData.MuzzleVel, 1), " m/s\n", "Max Penetration: ", math.floor(DData.MaxPen), " mm\n", "Max Spread: ", math.ceil((BulletData.FlechetteSpread + coneAng) * 10) / 10, " deg"} - - return table.concat(str) -end - -function Round.propimpact(_, Bullet, Target, HitNormal, HitPos, Bone) - if ACF_Check(Target) then - local Speed = Bullet["Flight"]:Length() / ACF.Scale - local Energy = ACF_Kinetic(Speed, Bullet["ProjMass"], Bullet["LimitVel"]) - local HitRes = ACF_RoundImpact(Bullet, Speed, Energy, Target, HitPos, HitNormal, Bone) - - if HitRes.Overkill > 0 then - table.insert(Bullet["Filter"], Target) --"Penetrate" (Ingoring the prop for the retry trace) - Bullet["Flight"] = Bullet["Flight"]:GetNormalized() * (Energy.Kinetic * (1 - HitRes.Loss) * 2000 / Bullet["ProjMass"]) ^ 0.5 * 39.37 - - return "Penetrated" - elseif HitRes.Ricochet then - return "Ricochet" - else - return false - end - else - table.insert(Bullet["Filter"], Target) - - return "Penetrated" - end -end - -function Round.worldimpact(_, Bullet, HitPos, HitNormal) - local Energy = ACF_Kinetic(Bullet.Flight:Length() / ACF.Scale, Bullet.ProjMass, Bullet.LimitVel) - local HitRes = ACF_PenetrateGround(Bullet, Energy, HitPos, HitNormal) - - if HitRes.Penetrated then - return "Penetrated" - elseif HitRes.Ricochet then - return "Ricochet" - else - return false - end -end - -function Round.endflight(Index) - ACF_RemoveBullet(Index) -end - -local DecalIndex = ACF.GetAmmoDecalIndex - -function Round.endeffect(_, Bullet) - local Effect = EffectData() - Effect:SetOrigin(Bullet.SimPos) - Effect:SetNormal(Bullet.SimFlight:GetNormalized()) - Effect:SetRadius(Bullet.Caliber) - Effect:SetDamageType(DecalIndex(Bullet.AmmoType)) - - util.Effect("ACF_Impact", Effect) -end - -function Round.pierceeffect(_, Bullet) - local Effect = EffectData() - Effect:SetOrigin(Bullet.SimPos) - Effect:SetNormal(Bullet.SimFlight:GetNormalized()) - Effect:SetScale(Bullet.SimFlight:Length()) - Effect:SetMagnitude(Bullet.RoundMass) - Effect:SetRadius(Bullet.Caliber) - Effect:SetDamageType(DecalIndex(Bullet.AmmoType)) - - util.Effect("ACF_Penetration", Effect) -end - -function Round.ricocheteffect(_, Bullet) - local Effect = EffectData() - Effect:SetOrigin(Bullet.SimPos) - Effect:SetNormal(Bullet.SimFlight:GetNormalized()) - Effect:SetScale(Bullet.SimFlight:Length()) - Effect:SetMagnitude(Bullet.RoundMass) - Effect:SetRadius(Bullet.Caliber) - Effect:SetDamageType(DecalIndex(Bullet.AmmoType)) - - util.Effect("ACF_Ricochet", Effect) -end - -function Round.guicreate(Panel, Table) - acfmenupanel:AmmoSelect(ACF.AmmoBlacklist["FL"]) - acfmenupanel:CPanelText("BonusDisplay", "") - acfmenupanel:CPanelText("Desc", "") --Description (Name, Desc) - acfmenupanel:CPanelText("LengthDisplay", "") --Total round length (Name, Desc) - acfmenupanel:AmmoSlider("PropLength", 0, 0, 1000, 3, "Propellant Length", "") --Propellant Length Slider (Name, Value, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("ProjLength", 0, 0, 1000, 3, "Projectile Length", "") --Projectile Length Slider (Name, Value, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("Flechettes", 3, 3, 32, 0, "Flechettes", "") --flechette count Slider (Name, Value, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("FlechetteSpread", 10, 5, 60, 1, "Flechette Spread", "") --flechette spread Slider (Name, Value, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoCheckbox("Tracer", "Tracer", "") --Tracer checkbox (Name, Title, Desc) - acfmenupanel:CPanelText("VelocityDisplay", "") --Proj muzzle velocity (Name, Desc) - --acfmenupanel:CPanelText("RicoDisplay", "") --estimated rico chance - acfmenupanel:CPanelText("PenetrationDisplay", "") --Proj muzzle penetration (Name, Desc) - Round.guiupdate(Panel, Table) -end - -function Round.guiupdate(Panel) - local PlayerData = {} - PlayerData["Id"] = acfmenupanel.AmmoData["Data"]["id"] --AmmoSelect GUI - PlayerData["Type"] = "FL" --Hardcoded, match ACFRoundTypes table index - PlayerData["PropLength"] = acfmenupanel.AmmoData["PropLength"] --PropLength slider - PlayerData["ProjLength"] = acfmenupanel.AmmoData["ProjLength"] --ProjLength slider - PlayerData["Data5"] = acfmenupanel.AmmoData["Flechettes"] --Flechette count slider - PlayerData["Data6"] = acfmenupanel.AmmoData["FlechetteSpread"] --flechette spread slider - --PlayerData["Data7"] = acfmenupanel.AmmoData[Name] --Not used - --PlayerData["Data8"] = acfmenupanel.AmmoData[Name] --Not used - --PlayerData["Data9"] = acfmenupanel.AmmoData[Name] --Not used - local Tracer = 0 - - if acfmenupanel.AmmoData["Tracer"] then - Tracer = 1 - end - - PlayerData["Data10"] = Tracer --Tracer - local Data = Round.convert(Panel, PlayerData) - RunConsoleCommand("acfmenu_data1", acfmenupanel.AmmoData["Data"]["id"]) - RunConsoleCommand("acfmenu_data2", PlayerData["Type"]) - RunConsoleCommand("acfmenu_data3", Data.PropLength) --For Gun ammo, Data3 should always be Propellant - RunConsoleCommand("acfmenu_data4", Data.ProjLength) --And Data4 total round mass - RunConsoleCommand("acfmenu_data5", Data.Flechettes) - RunConsoleCommand("acfmenu_data6", Data.FlechetteSpread) - RunConsoleCommand("acfmenu_data10", Data.Tracer) - - acfmenupanel:AmmoUpdate() - acfmenupanel:AmmoSlider("PropLength", Data.PropLength, Data.MinPropLength, Data["MaxTotalLength"], 3, "Propellant Length", "Propellant Mass : " .. (math.floor(Data.PropMass * 1000)) .. " g") --Propellant Length Slider (Name, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("ProjLength", Data.ProjLength, Data.MinProjLength, Data["MaxTotalLength"], 3, "Projectile Length", "Projectile Mass : " .. (math.floor(Data.ProjMass * 1000)) .. " g") --Projectile Length Slider (Name, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("Flechettes", Data.Flechettes, Data.MinFlechettes, Data.MaxFlechettes, 0, "Flechettes", "Flechette Radius: " .. math.Round(Data["FlechetteRadius"] * 10, 2) .. " mm") - acfmenupanel:AmmoSlider("FlechetteSpread", Data.FlechetteSpread, Data.MinSpread, Data.MaxSpread, 1, "Flechette Spread", "") - acfmenupanel:AmmoCheckbox("Tracer", "Tracer : " .. (math.floor(Data.Tracer * 10) / 10) .. "cm\n", "") --Tracer checkbox (Name, Title, Desc) - acfmenupanel:CPanelText("Desc", ACF.RoundTypes[PlayerData["Type"]]["desc"]) --Description (Name, Desc) - acfmenupanel:CPanelText("LengthDisplay", "Cartridge Length : " .. (math.floor((Data.PropLength + Data.ProjLength + Data.Tracer) * 100) / 100) .. "/" .. Data.MaxTotalLength .. " cm") --Total round length (Name, Desc) - acfmenupanel:CPanelText("VelocityDisplay", "Muzzle Velocity : " .. math.floor(Data.MuzzleVel * ACF.Scale) .. " m\\s") --Proj muzzle velocity (Name, Desc) - --local RicoAngs = ACF_RicoProbability( Data.Ricochet, Data.MuzzleVel*ACF.Scale ) - --acfmenupanel:CPanelText("RicoDisplay", "Ricochet probability vs impact angle:\n".." 0% @ "..RicoAngs.Min.." degrees\n 50% @ "..RicoAngs.Mean.." degrees\n100% @ "..RicoAngs.Max.." degrees") - local R1V, R1P = ACF_PenRanging(Data.MuzzleVel, Data.FlechetteDragCoef, Data.FlechetteMass, Data.FlechettePenArea, Data.LimitVel, 300) - local R2V, R2P = ACF_PenRanging(Data.MuzzleVel, Data.FlechetteDragCoef, Data.FlechetteMass, Data.FlechettePenArea, Data.LimitVel, 800) - acfmenupanel:CPanelText("PenetrationDisplay", "Maximum Penetration : " .. math.floor(Data.MaxPen) .. " mm RHA\n\n300m pen: " .. math.Round(R1P, 0) .. "mm @ " .. math.Round(R1V, 0) .. " m\\s\n800m pen: " .. math.Round(R2P, 0) .. "mm @ " .. math.Round(R2V, 0) .. " m\\s\n\nThe range data is an approximation and may not be entirely accurate.") --Proj muzzle penetration (Name, Desc) -end - -ACF.RoundTypes.FL = Round -- DELETE - -ACF.RegisterAmmoDecal("FL", "damage/ap_pen", "damage/ap_rico") \ No newline at end of file diff --git a/lua/acf/shared/rounds/he.lua b/lua/acf/shared/rounds/he.lua deleted file mode 100644 index e5de4c1d7..000000000 --- a/lua/acf/shared/rounds/he.lua +++ /dev/null @@ -1,218 +0,0 @@ -ACF.AmmoBlacklist.HE = {"MG", "RAC"} -local Round = {} -Round.type = "Ammo" --Tells the spawn menu what entity to spawn -Round.name = "High Explosive (HE)" --Human readable name -Round.model = "models/munitions/round_100mm_shot.mdl" --Shell flight model -Round.desc = "A shell filled with explosives, detonating on impact" - -function Round.create(_, BulletData) - ACF_CreateBullet(BulletData) -end - --- Function to convert the player's slider data into the complete round data -function Round.convert(_, PlayerData) - local Data = {} - local ServerData = {} - local GUIData = {} - - if not PlayerData.PropLength then - PlayerData.PropLength = 0 - end - - if not PlayerData.ProjLength then - PlayerData.ProjLength = 0 - end - - PlayerData.Data5 = math.max(PlayerData.Data5 or 0, 0) - - if not PlayerData.Data10 then - PlayerData.Data10 = 0 - end - - PlayerData, Data, ServerData, GUIData = ACF_RoundBaseGunpowder(PlayerData, Data, ServerData, GUIData) - --Shell sturdiness calcs - Data.ProjMass = math.max(GUIData.ProjVolume - PlayerData.Data5, 0) * 7.9 / 1000 + math.min(PlayerData.Data5, GUIData.ProjVolume) * ACF.HEDensity / 1000 --Volume of the projectile as a cylinder - Volume of the filler * density of steel + Volume of the filler * density of TNT - Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass, Data.Caliber) - local Energy = ACF_Kinetic(Data.MuzzleVel * 39.37, Data.ProjMass, Data.LimitVel) - local MaxVol = ACF_RoundShellCapacity(Energy.Momentum, Data.FrArea, Data.Caliber, Data.ProjLength) - GUIData.MinFillerVol = 0 - GUIData.MaxFillerVol = math.min(GUIData.ProjVolume, MaxVol) - GUIData.FillerVol = math.min(PlayerData.Data5, GUIData.MaxFillerVol) - Data.FillerMass = GUIData.FillerVol * ACF.HEDensity / 1000 - Data.ProjMass = math.max(GUIData.ProjVolume - GUIData.FillerVol, 0) * 7.9 / 1000 + Data.FillerMass - Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass, Data.Caliber) - --Random bullshit left - Data.ShovePower = 0.1 - Data.PenArea = Data.FrArea ^ ACF.PenAreaMod - Data.DragCoef = ((Data.FrArea / 10000) / Data.ProjMass) - Data.LimitVel = 100 --Most efficient penetration speed in m/s - Data.KETransfert = 0.1 --Kinetic energy transfert to the target for movement purposes - Data.Ricochet = 60 --Base ricochet angle - Data.DetonatorAngle = 80 - Data.CanFuze = Data.Caliber > ACF.MinFuzeCaliber * 0.1 -- Can fuze on calibers > 20mm - Data.CartMass = Data.PropMass + Data.ProjMass - - --Only the crates need this part - if SERVER then - ServerData.Id = PlayerData.Id - ServerData.Type = PlayerData.Type - - return table.Merge(Data, ServerData) - end - - --Only the GUI needs this part - if CLIENT then - GUIData = table.Merge(GUIData, Round.getDisplayData(Data)) - - return table.Merge(Data, GUIData) - end -end - -function Round.getDisplayData(Data) - local GUIData = {} - GUIData.BlastRadius = Data.FillerMass ^ 0.33 * 8 - local FragMass = Data.ProjMass - Data.FillerMass - GUIData.Fragments = math.max(math.floor((Data.FillerMass / FragMass) * ACF.HEFrag), 2) - GUIData.FragMass = FragMass / GUIData.Fragments - GUIData.FragVel = (Data.FillerMass * ACF.HEPower * 1000 / GUIData.FragMass / GUIData.Fragments) ^ 0.5 - - return GUIData -end - -function Round.network(Crate, BulletData) - Crate:SetNWString("AmmoType", "HE") - Crate:SetNWString("AmmoID", BulletData.Id) - Crate:SetNWFloat("Caliber", BulletData.Caliber) - Crate:SetNWFloat("ProjMass", BulletData.ProjMass) - Crate:SetNWFloat("FillerMass", BulletData.FillerMass) - Crate:SetNWFloat("PropMass", BulletData.PropMass) - Crate:SetNWFloat("DragCoef", BulletData.DragCoef) - Crate:SetNWFloat("MuzzleVel", BulletData.MuzzleVel) - Crate:SetNWFloat("Tracer", BulletData.Tracer) -end - -function Round.cratetxt(BulletData) - local DData = Round.getDisplayData(BulletData) - local str = { - "Muzzle Velocity: ", math.Round(BulletData.MuzzleVel, 1), " m/s\n", - "Blast Radius: ",math.Round(DData.BlastRadius, 1), "m\n", - "Blast Energy: ", math.floor(BulletData.FillerMass * ACF.HEPower), "kJ\n", - "Filler Mass: ", math.Round(BulletData.FillerMass * 1000, 2), "g\n", - "Avg. Frag Mass: ", math.Round(DData.FragMass * 1000, 2), "g\n", - "Case Mass: ", math.Round((BulletData.ProjMass - BulletData.FillerMass) * 1000, 2), "g", - } - - return table.concat(str) -end - -function Round.propimpact(_, Bullet, Target, HitNormal, HitPos, Bone) - if ACF_Check(Target) then - local Speed = Bullet.Flight:Length() / ACF.Scale - local Energy = ACF_Kinetic(Speed, Bullet.ProjMass - Bullet.FillerMass, Bullet.LimitVel) - local HitRes = ACF_RoundImpact(Bullet, Speed, Energy, Target, HitPos, HitNormal, Bone) - if HitRes.Ricochet then return "Ricochet" end - end - - return false -end - -function Round.worldimpact() - return false -end - -function Round.endflight(Index, Bullet, HitPos) - ACF_HE(HitPos, Bullet.FillerMass, Bullet.ProjMass - Bullet.FillerMass, Bullet.Owner, nil, Bullet.Gun) - ACF_RemoveBullet(Index) -end - -local DecalIndex = ACF.GetAmmoDecalIndex - -function Round.endeffect(_, Bullet) - local Effect = EffectData() - Effect:SetOrigin(Bullet.SimPos) - Effect:SetNormal(Bullet.SimFlight:GetNormalized()) - Effect:SetScale(math.max(Bullet.FillerMass ^ 0.33 * 8 * 39.37, 1)) - Effect:SetRadius(Bullet.Caliber) - - util.Effect("ACF_Explosion", Effect) -end - -function Round.pierceeffect(_, Bullet) - local Effect = EffectData() - Effect:SetOrigin(Bullet.SimPos) - Effect:SetNormal(Bullet.SimFlight:GetNormalized()) - Effect:SetScale(Bullet.SimFlight:Length()) - Effect:SetMagnitude(Bullet.RoundMass) - Effect:SetRadius(Bullet.Caliber) - Effect:SetDamageType(DecalIndex(Bullet.AmmoType)) - - util.Effect("ACF_Penetration", Effect) -end - -function Round.ricocheteffect(_, Bullet) - local Effect = EffectData() - Effect:SetOrigin(Bullet.SimPos) - Effect:SetNormal(Bullet.SimFlight:GetNormalized()) - Effect:SetScale(Bullet.SimFlight:Length()) - Effect:SetMagnitude(Bullet.RoundMass) - Effect:SetRadius(Bullet.Caliber) - Effect:SetDamageType(DecalIndex(Bullet.AmmoType)) - - util.Effect("ACF_Ricochet", Effect) -end - -function Round.guicreate(Panel, Table) - acfmenupanel:AmmoSelect(ACF.AmmoBlacklist.HE) - - acfmenupanel:CPanelText("Desc", "") --Description (Name, Desc) - acfmenupanel:CPanelText("LengthDisplay", "") --Total round length (Name, Desc) - acfmenupanel:AmmoSlider("PropLength", 0, 0, 1000, 3, "Propellant Length", "") --Slider (Name, Value, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("ProjLength", 0, 0, 1000, 3, "Projectile Length", "") --Slider (Name, Value, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("FillerVol", 0, 0, 1000, 3, "HE Filler", "") --Slider (Name, Value, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoCheckbox("Tracer", "Tracer", "") --Tracer checkbox (Name, Title, Desc) - acfmenupanel:CPanelText("VelocityDisplay", "") --Proj muzzle velocity (Name, Desc) - acfmenupanel:CPanelText("BlastDisplay", "") --HE Blast data (Name, Desc) - acfmenupanel:CPanelText("FragDisplay", "") --HE Fragmentation data (Name, Desc) - --acfmenupanel:CPanelText("RicoDisplay", "") --estimated rico chance - Round.guiupdate(Panel, Table) -end - -function Round.guiupdate(Panel) - local PlayerData = {} - PlayerData.Id = acfmenupanel.AmmoData.Data.id --AmmoSelect GUI - PlayerData.Type = "HE" --Hardcoded, match ACFRoundTypes table index - PlayerData.PropLength = acfmenupanel.AmmoData.PropLength --PropLength slider - PlayerData.ProjLength = acfmenupanel.AmmoData.ProjLength --ProjLength slider - PlayerData.Data5 = acfmenupanel.AmmoData.FillerVol - local Tracer = 0 - - if acfmenupanel.AmmoData.Tracer then - Tracer = 1 - end - - PlayerData.Data10 = Tracer --Tracer - local Data = Round.convert(Panel, PlayerData) - RunConsoleCommand("acfmenu_data1", acfmenupanel.AmmoData.Data.id) - RunConsoleCommand("acfmenu_data2", PlayerData.Type) - RunConsoleCommand("acfmenu_data3", Data.PropLength) --For Gun ammo, Data3 should always be Propellant - RunConsoleCommand("acfmenu_data4", Data.ProjLength) --And Data4 total round mass - RunConsoleCommand("acfmenu_data5", Data.FillerVol) - RunConsoleCommand("acfmenu_data10", Data.Tracer) - - acfmenupanel:AmmoUpdate() - acfmenupanel:AmmoSlider("PropLength", Data.PropLength, Data.MinPropLength, Data.MaxTotalLength, 3, "Propellant Length", "Propellant Mass : " .. (math.floor(Data.PropMass * 1000)) .. " g") --Propellant Length Slider (Name, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("ProjLength", Data.ProjLength, Data.MinProjLength, Data.MaxTotalLength, 3, "Projectile Length", "Projectile Mass : " .. (math.floor(Data.ProjMass * 1000)) .. " g") --Projectile Length Slider (Name, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("FillerVol", Data.FillerVol, Data.MinFillerVol, Data.MaxFillerVol, 3, "HE Filler Volume", "HE Filler Mass : " .. (math.floor(Data.FillerMass * 1000)) .. " g") --HE Filler Slider (Name, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoCheckbox("Tracer", "Tracer : " .. (math.floor(Data.Tracer * 10) / 10) .. "cm\n", "") --Tracer checkbox (Name, Title, Desc) - acfmenupanel:CPanelText("Desc", ACF.RoundTypes[PlayerData.Type].desc) --Description (Name, Desc) - acfmenupanel:CPanelText("LengthDisplay", "Cartridge Length : " .. (math.floor((Data.PropLength + Data.ProjLength + Data.Tracer) * 100) / 100) .. "/" .. Data.MaxTotalLength .. " cm") --Total round length (Name, Desc) - acfmenupanel:CPanelText("VelocityDisplay", "Muzzle Velocity : " .. math.floor(Data.MuzzleVel * ACF.Scale) .. " m/s") --Proj muzzle velocity (Name, Desc) - acfmenupanel:CPanelText("BlastDisplay", "Blast Radius : " .. (math.floor(Data.BlastRadius * 100) / 100) .. " m") --Proj muzzle velocity (Name, Desc) - acfmenupanel:CPanelText("FragDisplay", "Fragments : " .. Data.Fragments .. "\n Average Fragment Weight : " .. (math.floor(Data.FragMass * 10000) / 10) .. " g \n Average Fragment Velocity : " .. math.floor(Data.FragVel) .. " m/s") --Proj muzzle penetration (Name, Desc) - --local RicoAngs = ACF_RicoProbability( Data.Ricochet, Data.MuzzleVel*ACF.Scale ) - --acfmenupanel:CPanelText("RicoDisplay", "Ricochet probability vs impact angle:\n".." 0% @ "..RicoAngs.Min.." degrees\n 50% @ "..RicoAngs.Mean.." degrees\n100% @ "..RicoAngs.Max.." degrees") -end - -ACF.RoundTypes.HE = Round -- DELETE - -ACF.RegisterAmmoDecal("HE", "damage/he_pen", "damage/he_rico") \ No newline at end of file diff --git a/lua/acf/shared/rounds/heat.lua b/lua/acf/shared/rounds/heat.lua deleted file mode 100644 index 164a745d8..000000000 --- a/lua/acf/shared/rounds/heat.lua +++ /dev/null @@ -1,379 +0,0 @@ -ACF.AmmoBlacklist.HEAT = {"MG", "HMG", "RAC", "AC", "SL", "SB"} -local Round = {} -Round.type = "Ammo" --Tells the spawn menu what entity to spawn -Round.name = "High Explosive Anti-Tank (HEAT)" --Human readable name -Round.model = "models/munitions/round_100mm_shot.mdl" --Shell flight model -Round.desc = "A shell with a shaped charge. When the round detonates, the explosive energy is focused into driving a small molten metal penetrator into the victim with extreme force, though this results in reduced damage from the explosion itself. Multiple layers of armor will dissipate the penetrator quickly." - -function Round.create(_, BulletData) - ACF_CreateBullet(BulletData) -end - -function Round.ConeCalc(ConeAngle, Radius) - local ConeLength = math.tan(math.rad(ConeAngle)) * Radius - local ConeArea = 3.1416 * Radius * (Radius ^ 2 + ConeLength ^ 2) ^ 0.5 - local ConeVol = (3.1416 * Radius ^ 2 * ConeLength) / 3 - - return ConeLength, ConeArea, ConeVol -end - --- calculates conversion of filler from powering HEAT jet to raw HE based on crush vel --- above a threshold vel, HEAT jet doesn't have time to form properly, converting to raw HE proportionally --- Vel needs to be in m/s (gmu*0.0254) -function Round.CrushCalc(Vel, FillerMass) - local Crushed = math.Clamp((Vel - ACF.HEATMinCrush) / (ACF.HEATMaxCrush - ACF.HEATMinCrush), 0, 1) - local HE_Filler = Lerp(Crushed, FillerMass * ACF.HEATBoomConvert, FillerMass) - local HEAT_Filler = Lerp(Crushed, FillerMass, 0) - --local HE_Filler = FillerMass * ACF.HEATBoomConvert + Crushed * FillerMass * (1-ACF.HEATBoomConvert) - --local HEAT_Filler = (1-Crushed) * FillerMass - - return Crushed, HEAT_Filler, HE_Filler -end - --- coneang now required for slug recalculation at detonation, defaults to 55 if not present -function Round.CalcSlugMV(Data, HEATFillerMass) - --keep fillermass/2 so that penetrator stays the same. - return (HEATFillerMass / 2 * ACF.HEPower * math.sin(math.rad(10 + (Data.ConeAng or 55)) / 2) / Data.SlugMass) ^ ACF.HEATMVScale -end - --- Function to convert the player's slider data into the complete round data -function Round.convert(_, PlayerData) - local Data = {} - local ServerData = {} - local GUIData = {} - - if not PlayerData.PropLength then - PlayerData.PropLength = 0 - end - - if not PlayerData.ProjLength then - PlayerData.ProjLength = 0 - end - - PlayerData.Data5 = math.max(PlayerData.Data5 or 0, 0) - - if not PlayerData.Data6 then - PlayerData.Data6 = 0 - end - - if not PlayerData.Data7 then - PlayerData.Data7 = 0 - end - - if not PlayerData.Data10 then - PlayerData.Data10 = 0 - end - - PlayerData, Data, ServerData, GUIData = ACF_RoundBaseGunpowder(PlayerData, Data, ServerData, GUIData) - local ConeThick = Data.Caliber / 50 - local ConeArea = 0 - local AirVol = 0 - ConeLength, ConeArea, AirVol = Round.ConeCalc(PlayerData.Data6, Data.Caliber / 2, PlayerData.ProjLength) - Data.ProjMass = math.max(GUIData.ProjVolume - PlayerData.Data5, 0) * 7.9 / 1000 + math.min(PlayerData.Data5, GUIData.ProjVolume) * ACF.HEDensity / 1000 + ConeArea * ConeThick * 7.9 / 1000 --Volume of the projectile as a cylinder - Volume of the filler - Volume of the crush cone * density of steel + Volume of the filler * density of TNT + Area of the cone * thickness * density of steel - Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass, Data.Caliber) - local Energy = ACF_Kinetic(Data.MuzzleVel * 39.37, Data.ProjMass, Data.LimitVel) - local MaxVol = 0 - MaxVol, MaxLength, MaxRadius = ACF_RoundShellCapacity(Energy.Momentum, Data.FrArea, Data.Caliber, Data.ProjLength) - GUIData.MinConeAng = 0 - GUIData.MaxConeAng = math.deg(math.atan((Data.ProjLength - ConeThick) / (Data.Caliber / 2))) - Data.ConeAng = math.Clamp(PlayerData.Data6 * 1, GUIData.MinConeAng, GUIData.MaxConeAng) - ConeLength, ConeArea, AirVol = Round.ConeCalc(Data.ConeAng, Data.Caliber / 2, Data.ProjLength) - local ConeVol = ConeArea * ConeThick - GUIData.MinFillerVol = 0 - GUIData.MaxFillerVol = math.max(MaxVol - AirVol - ConeVol, GUIData.MinFillerVol) - GUIData.FillerVol = math.Clamp(PlayerData.Data5 * 1, GUIData.MinFillerVol, GUIData.MaxFillerVol) - -- fillermass used for shell mass calcs - -- heatfillermass is how much fillermass is used to power heat jet - -- boomfillermass is how much fillermass creates HE damage on detonation. technically get 1/3 extra fillermass free as HE with no crushing, but screw trying to rebalance heat pen to properly use 1/3 of filler for HE and 2/3 for jet - -- distribution of heat and boom fillermass is calculated at detonation, or for GUI stuff - Data.FillerMass = GUIData.FillerVol * ACF.HEDensity / 1450 - Data.ProjMass = math.max(GUIData.ProjVolume - GUIData.FillerVol - AirVol - ConeVol, 0) * 7.9 / 1000 + Data.FillerMass + ConeVol * 7.9 / 1000 - Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass, Data.Caliber) - - --Let's calculate the actual HEAT slug - Data.SlugMass = ConeVol * 7.9 / 1000 - local Rad = math.rad(Data.ConeAng / 2) - Data.SlugCaliber = Data.Caliber - Data.Caliber * (math.sin(Rad) * 0.5 + math.cos(Rad) * 1.5) / 2 - local SlugFrArea = 3.1416 * (Data.SlugCaliber / 2) ^ 2 - Data.SlugPenArea = SlugFrArea ^ ACF.PenAreaMod - Data.SlugDragCoef = ((SlugFrArea / 10000) / Data.SlugMass) - Data.SlugRicochet = 500 --Base ricochet angle (The HEAT slug shouldn't ricochet at all) - -- these are only for compatibility with other stuff. it's recalculated when the round is detonated - local _, heatfiller, boomfiller = Round.CrushCalc(Data.MuzzleVel, Data.FillerMass) - Data.BoomFillerMass = boomfiller - Data.SlugMV = Round.CalcSlugMV(Data, heatfiller) - --Random bullshit left - Data.CasingMass = Data.ProjMass - Data.FillerMass - ConeVol * 7.9 / 1000 - Data.ShovePower = 0.1 - Data.PenArea = Data.FrArea ^ ACF.PenAreaMod - Data.DragCoef = ((Data.FrArea / 10000) / Data.ProjMass) - Data.LimitVel = 100 --Most efficient penetration speed in m/s - Data.KETransfert = 0.1 --Kinetic energy transfert to the target for movement purposes - Data.Ricochet = 60 --Base ricochet angle - Data.DetonatorAngle = 75 - Data.Detonated = false - Data.NotFirstPen = false - Data.CanFuze = Data.Caliber > ACF.MinFuzeCaliber * 0.1 -- Can fuze on calibers > 20mm - Data.CartMass = Data.PropMass + Data.ProjMass - - --Only the crates need this part - if SERVER then - ServerData.Id = PlayerData.Id - ServerData.Type = PlayerData.Type - - return table.Merge(Data, ServerData) - end - - --Only the GUI needs this part - if CLIENT then - GUIData = table.Merge(GUIData, Round.getDisplayData(Data)) - - return table.Merge(Data, GUIData) - end -end - -function Round.getDisplayData(Data) - local GUIData = {} - -- these are only GUI info, it's recalculated when the round is detonated since it's vel dependent - GUIData.Crushed, GUIData.HEATFillerMass, GUIData.BoomFillerMass = Round.CrushCalc(Data.MuzzleVel, Data.FillerMass) - GUIData.SlugMV = Round.CalcSlugMV(Data, GUIData.HEATFillerMass) * (Data.SlugPenMul or 1) -- slugpenmul is a missiles thing - GUIData.SlugMassUsed = Data.SlugMass * (1 - GUIData.Crushed) - local SlugEnergy = ACF_Kinetic(Data.MuzzleVel * 39.37 + GUIData.SlugMV * 39.37, GUIData.SlugMassUsed, 999999) - GUIData.MaxPen = (SlugEnergy.Penetration / Data.SlugPenArea) * ACF.KEtoRHA - GUIData.TotalFragMass = Data.CasingMass + Data.SlugMass * GUIData.Crushed - GUIData.BlastRadius = GUIData.BoomFillerMass ^ 0.33 * 8 --*39.37 - GUIData.Fragments = math.max(math.floor((GUIData.BoomFillerMass / GUIData.TotalFragMass) * ACF.HEFrag), 2) - GUIData.FragMass = GUIData.TotalFragMass / GUIData.Fragments - GUIData.FragVel = (GUIData.BoomFillerMass * ACF.HEPower * 1000 / GUIData.TotalFragMass) ^ 0.5 - - return GUIData -end - -function Round.network(Crate, BulletData) - Crate:SetNWString("AmmoType", "HEAT") - Crate:SetNWString("AmmoID", BulletData.Id) - Crate:SetNWFloat("Caliber", BulletData.Caliber) - Crate:SetNWFloat("ProjMass", BulletData.ProjMass) - Crate:SetNWFloat("FillerMass", BulletData.FillerMass) - Crate:SetNWFloat("PropMass", BulletData.PropMass) - Crate:SetNWFloat("DragCoef", BulletData.DragCoef) - Crate:SetNWFloat("SlugMass", BulletData.SlugMass) - Crate:SetNWFloat("SlugCaliber", BulletData.SlugCaliber) - Crate:SetNWFloat("SlugDragCoef", BulletData.SlugDragCoef) - Crate:SetNWFloat("MuzzleVel", BulletData.MuzzleVel) - Crate:SetNWFloat("Tracer", BulletData.Tracer) -end - ---local fakeent = {ACF = {Armour = 0}} ---local fakepen = {Penetration = 999999999} -function Round.cratetxt(BulletData) - local DData = Round.getDisplayData(BulletData) - local str = {"Muzzle Velocity: ", math.Round(BulletData.MuzzleVel, 1), " m/s\n", "Max Penetration: ", math.floor(DData.MaxPen), " mm\n", "Blast Radius: ", math.Round(DData.BlastRadius, 1), " m\n", "Blast Energy: ", math.floor(DData.BoomFillerMass * ACF.HEPower), " KJ"} - - return table.concat(str) -end - -function Round.detonate(_, Bullet, HitPos) - local Crushed, HEATFillerMass, BoomFillerMass = Round.CrushCalc(Bullet.Flight:Length() * 0.0254, Bullet.FillerMass) - ACF_HE(HitPos, BoomFillerMass, Bullet.CasingMass + Bullet.SlugMass * Crushed, Bullet.Owner, nil, Bullet.Gun) - if Crushed == 1 then return false end -- no HEAT jet to fire off, it was all converted to HE - - Bullet.Detonated = true - Bullet.InitTime = ACF.CurTime - Bullet.Flight = Bullet.Flight + Bullet.Flight:GetNormalized() * Round.CalcSlugMV(Bullet, HEATFillerMass) * 39.37 - Bullet.NextPos = HitPos - Bullet.DragCoef = Bullet.SlugDragCoef - Bullet.ProjMass = Bullet.SlugMass * (1 - Crushed) - Bullet.Caliber = Bullet.SlugCaliber - Bullet.PenArea = Bullet.SlugPenArea - Bullet.Ricochet = Bullet.SlugRicochet - - return true -end - -function Round.propimpact(Index, Bullet, Target, HitNormal, HitPos, Bone) - if ACF_Check(Target) then - if Bullet.Detonated then - Bullet.NotFirstPen = true - local Speed = Bullet.Flight:Length() / ACF.Scale - local Energy = ACF_Kinetic(Speed, Bullet.ProjMass, 999999) - local HitRes = ACF_RoundImpact(Bullet, Speed, Energy, Target, HitPos, HitNormal, Bone) - - if HitRes.Overkill > 0 then - table.insert(Bullet.Filter, Target) --"Penetrate" (Ingoring the prop for the retry trace) - Bullet.Flight = Bullet.Flight:GetNormalized() * math.sqrt(Energy.Kinetic * (1 - HitRes.Loss) * ((Bullet.NotFirstPen and ACF.HEATPenLayerMul) or 1) * 2000 / Bullet.ProjMass) * 39.37 - - return "Penetrated" - else - return false - end - else - local Speed = Bullet.Flight:Length() / ACF.Scale - local Energy = ACF_Kinetic(Speed, Bullet.ProjMass - Bullet.FillerMass, Bullet.LimitVel) - local HitRes = ACF_RoundImpact(Bullet, Speed, Energy, Target, HitPos, HitNormal, Bone) - - if HitRes.Ricochet then - return "Ricochet" - else - local jet = Round.detonate(Index, Bullet, HitPos, HitNormal) - - if jet then - return "Penetrated" - else - return false - end - end - end - else - table.insert(Bullet.Filter, Target) - - return "Penetrated" - end - - return false -end - -function Round.worldimpact(Index, Bullet, HitPos, HitNormal) - if not Bullet.Detonated then - local jet = Round.detonate(Index, Bullet, HitPos, HitNormal) - - if jet then - return "Penetrated" - else - return false - end - end - - local Energy = ACF_Kinetic(Bullet.Flight:Length() / ACF.Scale, Bullet.ProjMass, 999999) - local HitRes = ACF_PenetrateGround(Bullet, Energy, HitPos, HitNormal) - - if HitRes.Penetrated then - --elseif HitRes.Ricochet then --penetrator won't ricochet - -- return "Ricochet" - return "Penetrated" - else - return false - end -end - -function Round.endflight(Index) - ACF_RemoveBullet(Index) -end - -local DecalIndex = ACF.GetAmmoDecalIndex - -function Round.endeffect(_, Bullet) - local Effect = EffectData() - Effect:SetOrigin(Bullet.SimPos) - Effect:SetNormal(Bullet.SimFlight:GetNormalized()) - Effect:SetRadius(Bullet.Caliber) - Effect:SetDamageType(DecalIndex(Bullet.AmmoType)) - - util.Effect("ACF_Impact", Effect) -end - -function Round.pierceeffect(Effect, Bullet) - if Bullet.Detonated then - local Data = EffectData() - Data:SetOrigin(Bullet.SimPos) - Data:SetNormal(Bullet.SimFlight:GetNormalized()) - Data:SetScale(Bullet.SimFlight:Length()) - Data:SetMagnitude(Bullet.RoundMass) - Data:SetRadius(Bullet.Caliber) - Data:SetDamageType(DecalIndex(Bullet.AmmoType)) - - util.Effect("ACF_Penetration", Data) - else - local _, _, BoomFillerMass = Round.CrushCalc(Bullet.SimFlight:Length() * 0.0254, Bullet.FillerMass) - local Data = EffectData() - Data:SetOrigin(Bullet.SimPos) - Data:SetNormal(Bullet.SimFlight:GetNormalized()) - Data:SetRadius(math.max(BoomFillerMass ^ 0.33 * 8 * 39.37, 1)) - - util.Effect("ACF_HEAT_Explosion", Data) - - Bullet.Detonated = true - - Effect:SetModel("models/Gibs/wood_gib01e.mdl") - end -end - -function Round.ricocheteffect(_, Bullet) - local Detonated = Bullet.Detonated - local Effect = EffectData() - Effect:SetOrigin(Bullet.SimPos) - Effect:SetNormal(Bullet.SimFlight:GetNormalized()) - Effect:SetScale(Bullet.SimFlight:Length()) - Effect:SetMagnitude(Bullet.RoundMass) - Effect:SetRadius(Bullet.Caliber) - Effect:SetDamageType(DecalIndex(Detonated and Bullet.AmmoType or "AP")) - - util.Effect("ACF_Ricochet", Effect) -end - -function Round.guicreate(Panel, Table) - acfmenupanel:AmmoSelect(ACF.AmmoBlacklist.HEAT) - - acfmenupanel:CPanelText("Desc", "") --Description (Name, Desc) - acfmenupanel:CPanelText("LengthDisplay", "") --Total round length (Name, Desc) - --Slider (Name, Value, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("PropLength", 0, 0, 1000, 3, "Propellant Length", "") - acfmenupanel:AmmoSlider("ProjLength", 0, 0, 1000, 3, "Projectile Length", "") - acfmenupanel:AmmoSlider("ConeAng", 0, 0, 1000, 3, "HEAT Cone Angle", "") - acfmenupanel:AmmoSlider("FillerVol", 0, 0, 1000, 3, "Total HEAT Warhead volume", "") - acfmenupanel:AmmoCheckbox("Tracer", "Tracer", "") --Tracer checkbox (Name, Title, Desc) - acfmenupanel:CPanelText("VelocityDisplay", "") --Proj muzzle velocity (Name, Desc) - acfmenupanel:CPanelText("BlastDisplay", "") --HE Blast data (Name, Desc) - acfmenupanel:CPanelText("FragDisplay", "") --HE Fragmentation data (Name, Desc) - --acfmenupanel:CPanelText("RicoDisplay", "") --estimated rico chance - acfmenupanel:CPanelText("SlugDisplay", "") --HEAT Slug data (Name, Desc) - Round.guiupdate(Panel, Table) -end - -function Round.guiupdate(Panel) - local PlayerData = {} - PlayerData.Id = acfmenupanel.AmmoData.Data.id --AmmoSelect GUI - PlayerData.Type = "HEAT" --Hardcoded, match ACFRoundTypes table index - PlayerData.PropLength = acfmenupanel.AmmoData.PropLength --PropLength slider - PlayerData.ProjLength = acfmenupanel.AmmoData.ProjLength --ProjLength slider - PlayerData.Data5 = acfmenupanel.AmmoData.FillerVol - PlayerData.Data6 = acfmenupanel.AmmoData.ConeAng - local Tracer = 0 - - if acfmenupanel.AmmoData.Tracer then - Tracer = 1 - end - - PlayerData.Data10 = Tracer --Tracer - local Data = Round.convert(Panel, PlayerData) - RunConsoleCommand("acfmenu_data1", acfmenupanel.AmmoData.Data.id) - RunConsoleCommand("acfmenu_data2", PlayerData.Type) - RunConsoleCommand("acfmenu_data3", Data.PropLength) --For Gun ammo, Data3 should always be Propellant - RunConsoleCommand("acfmenu_data4", Data.ProjLength) - RunConsoleCommand("acfmenu_data5", Data.FillerVol) - RunConsoleCommand("acfmenu_data6", Data.ConeAng) - RunConsoleCommand("acfmenu_data10", Data.Tracer) - - acfmenupanel:AmmoUpdate() - acfmenupanel:AmmoSlider("PropLength", Data.PropLength, Data.MinPropLength, Data.MaxTotalLength, 3, "Propellant Length", "Propellant Mass : " .. (math.floor(Data.PropMass * 1000)) .. " g") --Propellant Length Slider (Name, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("ProjLength", Data.ProjLength, Data.MinProjLength, Data.MaxTotalLength, 3, "Projectile Length", "Projectile Mass : " .. (math.floor(Data.ProjMass * 1000)) .. " g") --Projectile Length Slider (Name, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("ConeAng", Data.ConeAng, Data.MinConeAng, Data.MaxConeAng, 0, "Crush Cone Angle", "") --HE Filler Slider (Name, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("FillerVol", Data.FillerVol, Data.MinFillerVol, Data.MaxFillerVol, 3, "HE Filler Volume", "HE Filler Mass : " .. (math.floor(Data.FillerMass * 1000)) .. " g") --HE Filler Slider (Name, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoCheckbox("Tracer", "Tracer : " .. (math.floor(Data.Tracer * 10) / 10) .. "cm\n", "") --Tracer checkbox (Name, Title, Desc) - acfmenupanel:CPanelText("Desc", ACF.RoundTypes[PlayerData.Type].desc) --Description (Name, Desc) - acfmenupanel:CPanelText("LengthDisplay", "Cartridge Length : " .. (math.floor((Data.PropLength + Data.ProjLength + Data.Tracer) * 100) / 100) .. "/" .. Data.MaxTotalLength .. " cm") --Total round length (Name, Desc) - acfmenupanel:CPanelText("VelocityDisplay", "Muzzle Velocity : " .. math.floor(Data.MuzzleVel * ACF.Scale) .. " m/s") --Proj muzzle velocity (Name, Desc) - acfmenupanel:CPanelText("BlastDisplay", "Blast Radius : " .. (math.floor(Data.BlastRadius * 100) / 100) .. " m") --Proj muzzle velocity (Name, Desc) - acfmenupanel:CPanelText("FragDisplay", "Fragments : " .. Data.Fragments .. "\n Average Fragment Weight : " .. (math.floor(Data.FragMass * 10000) / 10) .. " g \n Average Fragment Velocity : " .. math.floor(Data.FragVel) .. " m/s") --Proj muzzle penetration (Name, Desc) - --local RicoAngs = ACF_RicoProbability( Data.Ricochet, Data.MuzzleVel*ACF.Scale ) - --acfmenupanel:CPanelText("RicoDisplay", "Ricochet probability vs impact angle:\n".." 0% @ "..RicoAngs.Min.." degrees\n 50% @ "..RicoAngs.Mean.." degrees\n100% @ "..RicoAngs.Max.." degrees") - local R1V, R1P = ACF_PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 300) - R1P = (ACF_Kinetic((R1V + Data.SlugMV) * 39.37, Data.SlugMassUsed, 999999).Penetration / Data.SlugPenArea) * ACF.KEtoRHA - local R2V, R2P = ACF_PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 800) - R2P = (ACF_Kinetic((R2V + Data.SlugMV) * 39.37, Data.SlugMassUsed, 999999).Penetration / Data.SlugPenArea) * ACF.KEtoRHA - acfmenupanel:CPanelText("SlugDisplay", "Penetrator Mass : " .. (math.floor(Data.SlugMassUsed * 10000) / 10) .. " g \n Penetrator Caliber : " .. (math.floor(Data.SlugCaliber * 100) / 10) .. " mm \n Penetrator Velocity : " .. math.floor(Data.MuzzleVel + Data.SlugMV) .. " m/s \n Penetrator Maximum Penetration : " .. math.floor(Data.MaxPen) .. " mm RHA\n\n300m pen: " .. math.Round(R1P, 0) .. "mm @ " .. math.Round(R1V, 0) .. " m\\s\n800m pen: " .. math.Round(R2P, 0) .. "mm @ " .. math.Round(R2V, 0) .. " m\\s\n\nThe range data is an approximation and may not be entirely accurate.") --Proj muzzle penetration (Name, Desc) -end - -ACF.RoundTypes.HEAT = Round -- DELETE - -ACF.RegisterAmmoDecal("HEAT", "damage/heat_pen", "damage/heat_rico", function(Caliber) return Caliber * 0.1667 end) \ No newline at end of file diff --git a/lua/acf/shared/rounds/heatfs.lua b/lua/acf/shared/rounds/heatfs.lua deleted file mode 100644 index 48217de36..000000000 --- a/lua/acf/shared/rounds/heatfs.lua +++ /dev/null @@ -1,405 +0,0 @@ -ACF.AmmoBlacklist.HEATFS = { "MO", "SL", "C", "HW", "AC", "SC", "SA", "MG", "AL", "RAC", "GL", "HMG", "AAM", "ARTY", "ASM", "BOMB", "GBU", "POD", "SAM", "UAR", "FFAR", "FGL" } - -local Round = {} - -Round.type = "Ammo" --Tells the spawn menu what entity to spawn -Round.name = "High Explosive Anti-Tank Fin Stabilized (HEAT-FS)" --Human readable name -Round.model = "models/munitions/round_100mm_shot.mdl" --Shell flight model -Round.desc = "HEAT, but fin stabilized with a fixed minimum propellant charge. Smoothbores only." - -function Round.create(_, BulletData) - ACF_CreateBullet(BulletData) -end - -function Round.ConeCalc(ConeAngle, Radius) - local ConeLength = math.tan(math.rad(ConeAngle)) * Radius - local ConeArea = 3.1416 * Radius * (Radius ^ 2 + ConeLength ^ 2) ^ 0.5 - local ConeVol = (3.1416 * Radius ^ 2 * ConeLength) / 3 - - return ConeLength, ConeArea, ConeVol -end - --- calculates conversion of filler from powering HEAT jet to raw HE based on crush vel --- above a threshold vel, HEAT jet doesn't have time to form properly, converting to raw HE proportionally --- Vel needs to be in m/s (gmu*0.0254) -function Round.CrushCalc(Vel, FillerMass) - local Crushed = math.Clamp((Vel - ACF.HEATMinCrush) / (ACF.HEATMaxCrush - ACF.HEATMinCrush), 0,1) - local HE_Filler = Lerp(Crushed, FillerMass * ACF.HEATBoomConvert, FillerMass) - local HEAT_Filler = Lerp(Crushed, FillerMass, 0) - - return Crushed, HEAT_Filler, HE_Filler -end - --- coneang now required for slug recalculation at detonation, defaults to 55 if not present -function Round.CalcSlugMV(Data, HEATFillerMass) - --keep fillermass/2 so that penetrator stays the same. - return (HEATFillerMass / 2 * ACF.HEPower * math.sin(math.rad(10 + (Data.ConeAng or 55)) / 2) / Data.SlugMass) ^ ACF.HEATMVScale -end - --- Function to convert the player's slider data into the complete round data -function Round.convert(_, PlayerData) - local Data = {} - local ServerData = {} - local GUIData = {} - - if not PlayerData.PropLength then - PlayerData.PropLength = 0 - end - - if not PlayerData.ProjLength then - PlayerData.ProjLength = 0 - end - - PlayerData.Data5 = math.max(PlayerData.Data5 or 0, 0) - - if not PlayerData.Data6 then - PlayerData.Data6 = 0 - end - - if not PlayerData.Data7 then - PlayerData.Data7 = 0 - end - - if not PlayerData.Data10 then - PlayerData.Data10 = 0 - end - - PlayerData, Data, ServerData, GUIData = ACF_RoundBaseGunpowder(PlayerData, Data, ServerData, GUIData) - - local ConeThick = Data.Caliber / 50 - local ConeArea = 0 - local AirVol = 0 - ConeLength, ConeArea, AirVol = Round.ConeCalc(PlayerData.Data6, Data.Caliber / 2, PlayerData.ProjLength) - Data.ProjMass = math.max(GUIData.ProjVolume - PlayerData.Data5, 0) * 7.9 / 1000 + math.min(PlayerData.Data5, GUIData.ProjVolume) * ACF.HEDensity / 1000 + ConeArea * ConeThick * 7.9 / 1000 --Volume of the projectile as a cylinder - Volume of the filler - Volume of the crush cone * density of steel + Volume of the filler * density of TNT + Area of the cone * thickness * density of steel - Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass, Data.Caliber) - local Energy = ACF_Kinetic(Data.MuzzleVel * 39.37, Data.ProjMass, Data.LimitVel) - - local MaxVol = 0 - MaxVol, MaxLength, MaxRadius = ACF_RoundShellCapacity(Energy.Momentum, Data.FrArea, Data.Caliber, Data.ProjLength) - - GUIData.MinConeAng = 0 - GUIData.MaxConeAng = math.deg(math.atan((Data.ProjLength - ConeThick) / (Data.Caliber / 2))) - Data.ConeAng = math.Clamp(PlayerData.Data6 * 1, GUIData.MinConeAng, GUIData.MaxConeAng) - ConeLength, ConeArea, AirVol = Round.ConeCalc(Data.ConeAng, Data.Caliber / 2, Data.ProjLength) - local ConeVol = ConeArea * ConeThick - - GUIData.MinFillerVol = 0 - GUIData.MaxFillerVol = math.max(MaxVol - AirVol - ConeVol, GUIData.MinFillerVol) - GUIData.FillerVol = math.Clamp(PlayerData.Data5 * 1, GUIData.MinFillerVol, GUIData.MaxFillerVol) - - -- fillermass used for shell mass calcs - -- heatfillermass is how much fillermass is used to power heat jet - -- boomfillermass is how much fillermass creates HE damage on detonation. technically get 1/3 extra fillermass free as HE with no crushing, but screw trying to rebalance heat pen to properly use 1/3 of filler for HE and 2/3 for jet - -- distribution of heat and boom fillermass is calculated at detonation, or for GUI stuff - - Data.FillerMass = GUIData.FillerVol * ACF.HEDensity / 1450 - Data.ProjMass = math.max(GUIData.ProjVolume - GUIData.FillerVol - AirVol - ConeVol, 0) * 7.9 / 1000 + Data.FillerMass + ConeVol * 7.9 / 1000 - Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass, Data.Caliber) - - --Let's calculate the actual HEAT slug - Data.SlugMass = ConeVol * 7.9 / 1000 - local Rad = math.rad(Data.ConeAng / 2) - Data.SlugCaliber = Data.Caliber - Data.Caliber * (math.sin(Rad) * 0.5 + math.cos(Rad) * 1.5) / 2 - - local SlugFrArea = 3.1416 * (Data.SlugCaliber / 2) ^ 2 - Data.SlugPenArea = (SlugFrArea ^ ACF.PenAreaMod) / 1.6 - Data.SlugDragCoef = (SlugFrArea / 10000) / Data.SlugMass - Data.SlugRicochet = 500 --Base ricochet angle (The HEAT slug shouldn't ricochet at all) - - -- these are only for compatibility with other stuff. it's recalculated when the round is detonated - local _, heatfiller, boomfiller = Round.CrushCalc(Data.MuzzleVel, Data.FillerMass) - Data.BoomFillerMass = boomfiller - Data.SlugMV = Round.CalcSlugMV(Data, heatfiller) - - --Random bullshit left - Data.CasingMass = Data.ProjMass - Data.FillerMass - ConeVol * 7.9 / 1000 - Data.ShovePower = 0.1 - Data.PenArea = Data.FrArea ^ ACF.PenAreaMod - Data.DragCoef = (Data.FrArea / 10000) / Data.ProjMass - Data.LimitVel = 100 --Most efficient penetration speed in m/s - Data.KETransfert = 0.1 --Kinetic energy transfert to the target for movement purposes - Data.Ricochet = 60 --Base ricochet angle - Data.DetonatorAngle = 75 - - Data.Detonated = false - Data.NotFirstPen = false - Data.CanFuze = Data.Caliber > ACF.MinFuzeCaliber * 0.1 -- Can fuze on calibers > 20mm - Data.CartMass = Data.PropMass + Data.ProjMass - - --Only the crates need this part - if SERVER then - ServerData.Id = PlayerData.Id - ServerData.Type = PlayerData.Type - return table.Merge(Data,ServerData) - end - - --Only the GUI needs this part - if CLIENT then - GUIData = table.Merge(GUIData, Round.getDisplayData(Data)) - return table.Merge(Data, GUIData) - end -end - - -function Round.getDisplayData(Data) - local GUIData = {} - - -- these are only GUI info, it's recalculated when the round is detonated since it's vel dependent - GUIData.Crushed, GUIData.HEATFillerMass, GUIData.BoomFillerMass = Round.CrushCalc(Data.MuzzleVel, Data.FillerMass) - GUIData.SlugMV = Round.CalcSlugMV(Data, GUIData.HEATFillerMass) * (Data.SlugPenMul or 1) -- slugpenmul is a missiles thing - GUIData.SlugMassUsed = Data.SlugMass * (1 - GUIData.Crushed) - - local SlugEnergy = ACF_Kinetic(Data.MuzzleVel * 39.37 + GUIData.SlugMV * 39.37, GUIData.SlugMassUsed, 999999) - GUIData.MaxPen = (SlugEnergy.Penetration / Data.SlugPenArea) * ACF.KEtoRHA - - GUIData.TotalFragMass = Data.CasingMass + Data.SlugMass * GUIData.Crushed - GUIData.BlastRadius = GUIData.BoomFillerMass ^ 0.33 * 8 --*39.37 - GUIData.Fragments = math.max(math.floor((GUIData.BoomFillerMass / GUIData.TotalFragMass) * ACF.HEFrag), 2) - GUIData.FragMass = GUIData.TotalFragMass / GUIData.Fragments - GUIData.FragVel = (GUIData.BoomFillerMass * ACF.HEPower * 1000 / GUIData.TotalFragMass) ^ 0.5 - - return GUIData -end - - -function Round.network(Crate, BulletData) - Crate:SetNWString("AmmoType", "HEATFS") - Crate:SetNWString("AmmoID", BulletData.Id) - Crate:SetNWFloat("Caliber", BulletData.Caliber) - Crate:SetNWFloat("ProjMass", BulletData.ProjMass) - Crate:SetNWFloat("FillerMass", BulletData.FillerMass) - Crate:SetNWFloat("PropMass", BulletData.PropMass) - Crate:SetNWFloat("DragCoef", BulletData.DragCoef) - Crate:SetNWFloat("SlugMass", BulletData.SlugMass) - Crate:SetNWFloat("SlugCaliber", BulletData.SlugCaliber) - Crate:SetNWFloat("SlugDragCoef", BulletData.SlugDragCoef) - Crate:SetNWFloat("MuzzleVel", BulletData.MuzzleVel) - Crate:SetNWFloat("Tracer", BulletData.Tracer) -end - -function Round.cratetxt(BulletData) - local DData = Round.getDisplayData(BulletData) - - local str = - { - "Muzzle Velocity: ", math.Round(BulletData.MuzzleVel, 1), " m/s\n", - "Max Penetration: ", math.floor(DData.MaxPen), " mm\n", - "Blast Radius: ", math.Round(DData.BlastRadius, 1), " m\n", - "Blast Energy: ", math.floor(DData.BoomFillerMass * ACF.HEPower), " KJ" - } - - return table.concat(str) -end - -function Round.detonate(_, Bullet, HitPos) - local Crushed, HEATFillerMass, BoomFillerMass = Round.CrushCalc(Bullet.Flight:Length() * 0.0254, Bullet.FillerMass) - - ACF_HE(HitPos, BoomFillerMass, Bullet.CasingMass + Bullet.SlugMass * Crushed, Bullet.Owner, nil, Bullet.Gun) - - if Crushed == 1 then return false end -- no HEAT jet to fire off, it was all converted to HE - - Bullet.Detonated = true - Bullet.InitTime = ACF.CurTime - Bullet.Flight = Bullet.Flight + Bullet.Flight:GetNormalized() * Round.CalcSlugMV(Bullet, HEATFillerMass) * 39.37 - Bullet.NextPos = HitPos - Bullet.DragCoef = Bullet.SlugDragCoef - Bullet.ProjMass = Bullet.SlugMass * (1 - Crushed) - Bullet.Caliber = Bullet.SlugCaliber - Bullet.PenArea = Bullet.SlugPenArea - Bullet.Ricochet = Bullet.SlugRicochet - - return true -end - -function Round.propimpact(Index, Bullet, Target, HitNormal, HitPos, Bone) - if ACF_Check(Target) then - if Bullet.Detonated then - Bullet.NotFirstPen = true - - local Speed = Bullet.Flight:Length() / ACF.Scale - local Energy = ACF_Kinetic(Speed, Bullet.ProjMass, 999999) - local HitRes = ACF_RoundImpact(Bullet, Speed, Energy, Target, HitPos, HitNormal, Bone) - - if HitRes.Overkill > 0 then - table.insert(Bullet.Filter, Target) --"Penetrate" (Ingoring the prop for the retry trace) - Bullet.Flight = Bullet.Flight:GetNormalized() * math.sqrt(Energy.Kinetic * (1 - HitRes.Loss) * ((Bullet.NotFirstPen and ACF.HEATPenLayerMul) or 1) * 2000 / Bullet.ProjMass) * 39.37 - - return "Penetrated" - else - return false - end - else - local Speed = Bullet.Flight:Length() / ACF.Scale - local Energy = ACF_Kinetic(Speed, Bullet.ProjMass - Bullet.FillerMass, Bullet.LimitVel) - local HitRes = ACF_RoundImpact(Bullet, Speed, Energy, Target, HitPos, HitNormal, Bone) - - if HitRes.Ricochet then - return "Ricochet" - else - local jet = Round.detonate(Index, Bullet, HitPos, HitNormal) - - if jet then - return "Penetrated" - else - return false - end - end - end - else - table.insert(Bullet.Filter, Target) - return "Penetrated" - end - - return false -end - -function Round.worldimpact(Index, Bullet, HitPos, HitNormal) - if not Bullet.Detonated then - local jet = Round.detonate(Index, Bullet, HitPos, HitNormal) - - if jet then - return "Penetrated" - else - return false - end - end - - local Energy = ACF_Kinetic(Bullet.Flight:Length() / ACF.Scale, Bullet.ProjMass, 999999) - local HitRes = ACF_PenetrateGround(Bullet, Energy, HitPos, HitNormal) - - if HitRes.Penetrated then - return "Penetrated" - else - return false - end -end - -function Round.endflight(Index) - ACF_RemoveBullet(Index) -end - -local DecalIndex = ACF.GetAmmoDecalIndex - -function Round.endeffect(_, Bullet) - local Effect = EffectData() - Effect:SetOrigin(Bullet.SimPos) - Effect:SetNormal(Bullet.SimFlight:GetNormalized()) - Effect:SetRadius(Bullet.Caliber) - Effect:SetDamageType(DecalIndex(Bullet.AmmoType)) - - util.Effect("ACF_Impact", Effect) -end - -function Round.pierceeffect(Effect, Bullet) - if Bullet.Detonated then - local Data = EffectData() - Data:SetOrigin(Bullet.SimPos) - Data:SetNormal(Bullet.SimFlight:GetNormalized()) - Data:SetScale(Bullet.SimFlight:Length()) - Data:SetMagnitude(Bullet.RoundMass) - Data:SetRadius(Bullet.Caliber) - Data:SetDamageType(DecalIndex(Bullet.AmmoType)) - - util.Effect("ACF_Penetration", Data) - else - local _, _, BoomFillerMass = Round.CrushCalc(Bullet.SimFlight:Length() * 0.0254, Bullet.FillerMass) - local Data = EffectData() - Data:SetOrigin(Bullet.SimPos) - Data:SetNormal(Bullet.SimFlight:GetNormalized()) - Data:SetRadius(math.max(BoomFillerMass ^ 0.33 * 8 * 39.37, 1)) - - util.Effect("ACF_HEAT_Explosion", Data) - - Bullet.Detonated = true - - Effect:SetModel("models/Gibs/wood_gib01e.mdl") - end -end - -function Round.ricocheteffect(_, Bullet) - local Detonated = Bullet.Detonated - local Effect = EffectData() - Effect:SetOrigin(Bullet.SimPos) - Effect:SetNormal(Bullet.SimFlight:GetNormalized()) - Effect:SetScale(Bullet.SimFlight:Length()) - Effect:SetMagnitude(Bullet.RoundMass) - Effect:SetRadius(Bullet.Caliber) - Effect:SetDamageType(DecalIndex(Detonated and Bullet.AmmoType or "AP")) - - util.Effect("ACF_Ricochet", Effect) -end - -function Round.guicreate(Panel, Table) - acfmenupanel:AmmoSelect(ACF.AmmoBlacklist.HEATFS) - - acfmenupanel:CPanelText("Desc", "") --Description (Name, Desc) - acfmenupanel:CPanelText("LengthDisplay", "") --Total round length (Name, Desc) - - --Slider (Name, Value, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("PropLength", 0, 0, 1000, 3, "Propellant Length", "") - acfmenupanel:AmmoSlider("ProjLength", 0, 0, 1000, 3, "Projectile Length", "") - acfmenupanel:AmmoSlider("ConeAng", 0, 0, 1000, 3, "HEAT Cone Angle", "") - acfmenupanel:AmmoSlider("FillerVol", 0, 0, 1000, 3, "Total HEAT Warhead volume", "") - - acfmenupanel:AmmoCheckbox("Tracer", "Tracer", "") --Tracer checkbox (Name, Title, Desc) - - acfmenupanel:CPanelText("VelocityDisplay", "") --Proj muzzle velocity (Name, Desc) - acfmenupanel:CPanelText("BlastDisplay", "") --HE Blast data (Name, Desc) - acfmenupanel:CPanelText("FragDisplay", "") --HE Fragmentation data (Name, Desc) - - acfmenupanel:CPanelText("SlugDisplay", "") --HEAT Slug data (Name, Desc) - - Round.guiupdate(Panel, Table) -end - -function Round.guiupdate(Panel) - local PlayerData = {} - PlayerData.Id = acfmenupanel.AmmoData.Data.id --AmmoSelect GUI - PlayerData.Type = "HEATFS" --Hardcoded, match ACFRoundTypes table index - PlayerData.PropLength = acfmenupanel.AmmoData.PropLength --PropLength slider - PlayerData.ProjLength = acfmenupanel.AmmoData.ProjLength --ProjLength slider - PlayerData.Data5 = acfmenupanel.AmmoData.FillerVol - PlayerData.Data6 = acfmenupanel.AmmoData.ConeAng - local Tracer = 0 - - if acfmenupanel.AmmoData.Tracer then - Tracer = 1 - end - - PlayerData.Data10 = Tracer --Tracer - - local Data = Round.convert(Panel, PlayerData) - - RunConsoleCommand("acfmenu_data1", acfmenupanel.AmmoData.Data.id) - RunConsoleCommand("acfmenu_data2", PlayerData.Type) - RunConsoleCommand("acfmenu_data3", Data.PropLength) --For Gun ammo, Data3 should always be Propellant - RunConsoleCommand("acfmenu_data4", Data.ProjLength) - RunConsoleCommand("acfmenu_data5", Data.FillerVol) - RunConsoleCommand("acfmenu_data6", Data.ConeAng) - RunConsoleCommand("acfmenu_data10", Data.Tracer) - - acfmenupanel:AmmoUpdate() - acfmenupanel:AmmoSlider("PropLength", Data.PropLength, Data.MinPropLength + (Data.Caliber * 3.75), Data.MaxTotalLength, 3, "Propellant Length", "Propellant Mass : " .. (math.floor(Data.PropMass * 1000)) .. " g") --Propellant Length Slider (Name, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("ProjLength", Data.ProjLength, Data.MinProjLength, Data.MaxTotalLength, 3, "Projectile Length", "Projectile Mass : " .. (math.floor(Data.ProjMass * 1000)) .. " g") --Projectile Length Slider (Name, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("ConeAng", Data.ConeAng, Data.MinConeAng, Data.MaxConeAng, 0, "Crush Cone Angle", "") --HE Filler Slider (Name, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("FillerVol", Data.FillerVol, Data.MinFillerVol, Data.MaxFillerVol, 3, "HE Filler Volume", "HE Filler Mass : " .. (math.floor(Data.FillerMass * 1000)) .. " g") --HE Filler Slider (Name, Min, Max, Decimals, Title, Desc) - - acfmenupanel:AmmoCheckbox("Tracer", "Tracer : " .. (math.floor(Data.Tracer * 10) / 10) .. "cm\n", "") --Tracer checkbox (Name, Title, Desc) - - acfmenupanel:CPanelText("Desc", ACF.RoundTypes[PlayerData.Type].desc) --Description (Name, Desc) - acfmenupanel:CPanelText("LengthDisplay", "Cartridge Length : " .. (math.floor((Data.PropLength + Data.ProjLength + Data.Tracer) * 100) / 100) .. "/" .. Data.MaxTotalLength .. " cm") --Total round length (Name, Desc) - acfmenupanel:CPanelText("VelocityDisplay", "Muzzle Velocity : " .. math.floor(Data.MuzzleVel * ACF.Scale) .. " m/s") --Proj muzzle velocity (Name, Desc) - acfmenupanel:CPanelText("BlastDisplay", "Blast Radius : " .. (math.floor(Data.BlastRadius * 100) / 100) .. " m") --Proj muzzle velocity (Name, Desc) - acfmenupanel:CPanelText("FragDisplay", "Fragments : " .. Data.Fragments .. "\n Average Fragment Weight : " .. (math.floor(Data.FragMass * 10000) / 10) .. " g \n Average Fragment Velocity : " .. math.floor(Data.FragVel) .. " m/s") --Proj muzzle penetration (Name, Desc) - - local R1V, R1P = ACF_PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 300) - R1P = (ACF_Kinetic((R1V + Data.SlugMV) * 39.37, Data.SlugMassUsed, 999999).Penetration / Data.SlugPenArea) * ACF.KEtoRHA - local R2V, R2P = ACF_PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 800) - R2P = (ACF_Kinetic((R2V + Data.SlugMV) * 39.37, Data.SlugMassUsed, 999999).Penetration / Data.SlugPenArea) * ACF.KEtoRHA - - acfmenupanel:CPanelText("SlugDisplay", "Penetrator Mass : " .. (math.floor(Data.SlugMassUsed * 10000) / 10) .. " g \n Penetrator Caliber : " .. (math.floor(Data.SlugCaliber * 100) / 10) .. " mm \n Penetrator Velocity : " .. math.floor(Data.MuzzleVel + Data.SlugMV) .. " m/s \n Penetrator Maximum Penetration : " .. math.floor(Data.MaxPen) .. " mm RHA\n\n300m pen: " .. math.Round(R1P,0) .. "mm @ " .. math.Round(R1V,0) .. " m\\s\n800m pen: " .. math.Round(R2P,0) .. "mm @ " .. math.Round(R2V,0) .. " m\\s\n\nThe range data is an approximation and may not be entirely accurate.") --Proj muzzle penetration (Name, Desc) -end - -ACF.RoundTypes.HEATFS = Round -- DELETE - -ACF.RegisterAmmoDecal("HEATFS", "damage/heat_pen", "damage/heat_rico", function(Caliber) return Caliber * 0.1667 end) diff --git a/lua/acf/shared/rounds/hp.lua b/lua/acf/shared/rounds/hp.lua deleted file mode 100644 index 2d39c53c7..000000000 --- a/lua/acf/shared/rounds/hp.lua +++ /dev/null @@ -1,151 +0,0 @@ -local Round = table.Copy(ACF.RoundTypes.AP) -- inherit from AP - -ACF.AmmoBlacklist.HP = ACF.AmmoBlacklist.AP -Round.type = "Ammo" --Tells the spawn menu what entity to spawn -Round.name = "Hollow Point (HP)" --Human readable name -Round.model = "models/munitions/round_100mm_shot.mdl" --Shell flight model -Round.desc = "A solid shell with a soft point, meant to flatten against armour" - --- Function to convert the player's slider data into the complete round data -function Round.convert(_, PlayerData) - local Data = {} - local ServerData = {} - local GUIData = {} - - if not PlayerData.PropLength then - PlayerData.PropLength = 0 - end - - if not PlayerData.ProjLength then - PlayerData.ProjLength = 0 - end - - PlayerData.Data5 = math.max(PlayerData.Data5 or 0, 0) - - if not PlayerData.Data10 then - PlayerData.Data10 = 0 - end - - PlayerData, Data, ServerData, GUIData = ACF_RoundBaseGunpowder(PlayerData, Data, ServerData, GUIData) - --if GUIData.MaxCavVol != nil then PlayerData.Data5 = math.min(PlayerData.Data5, GUIData.MaxCavVol) end - --Shell sturdiness calcs - Data.ProjMass = Data.FrArea * (Data.ProjLength * 7.9 / 1000) --Volume of the projectile as a cylinder * density of steel - Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass, Data.Caliber) - local Energy = ACF_Kinetic(Data.MuzzleVel * 39.37, Data.ProjMass, Data.LimitVel) - local MaxVol = ACF_RoundShellCapacity(Energy.Momentum, Data.FrArea, Data.Caliber, Data.ProjLength) - GUIData.MinCavVol = 0 - GUIData.MaxCavVol = math.min(GUIData.ProjVolume, MaxVol) - Data.CavVol = math.Clamp(PlayerData.Data5, GUIData.MinCavVol, GUIData.MaxCavVol) - Data.ProjMass = ((Data.FrArea * Data.ProjLength) - Data.CavVol) * 7.9 / 1000 --Volume of the projectile as a cylinder * fraction missing due to hollow point (Data5) * density of steel - Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass, Data.Caliber) - local ExpRatio = (Data.CavVol / GUIData.ProjVolume) - Data.ShovePower = 0.2 + ExpRatio / 2 - Data.ExpCaliber = Data.Caliber + ExpRatio * Data.ProjLength - Data.PenArea = 3.1416 * ((Data.ExpCaliber / 2) ^ 2 ) ^ ACF.PenAreaMod - Data.DragCoef = ((Data.FrArea / 10000) / Data.ProjMass) - Data.LimitVel = 800 --Most efficient penetration speed in m/s - Data.KETransfert = 0.1 --Kinetic energy transfert to the target for movement purposes - Data.Ricochet = 60 --Base ricochet angle - Data.CartMass = Data.PropMass + Data.ProjMass - - --Only the crates need this part - if SERVER then - ServerData.Id = PlayerData.Id - ServerData.Type = PlayerData.Type - - return table.Merge(Data, ServerData) - end - - --Only the GUI needs this part - if CLIENT then - GUIData = table.Merge(GUIData, Round.getDisplayData(Data)) - - return table.Merge(Data, GUIData) - end -end - -function Round.getDisplayData(Data) - local GUIData = {} - local Energy = ACF_Kinetic(Data.MuzzleVel * 39.37, Data.ProjMass, Data.LimitVel) - GUIData.MaxKETransfert = Energy.Kinetic * Data.ShovePower - GUIData.MaxPen = (Energy.Penetration / Data.PenArea) * ACF.KEtoRHA - - return GUIData -end - -function Round.network(Crate, BulletData) - Crate:SetNWString("AmmoType", "HP") - Crate:SetNWString("AmmoID", BulletData.Id) - Crate:SetNWFloat("Caliber", BulletData.Caliber) - Crate:SetNWFloat("ProjMass", BulletData.ProjMass) - Crate:SetNWFloat("PropMass", BulletData.PropMass) - Crate:SetNWFloat("ExpCaliber", BulletData.ExpCaliber) - Crate:SetNWFloat("DragCoef", BulletData.DragCoef) - Crate:SetNWFloat("MuzzleVel", BulletData.MuzzleVel) - Crate:SetNWFloat("Tracer", BulletData.Tracer) -end - -function Round.cratetxt(BulletData) - local DData = Round.getDisplayData(BulletData) - local str = {"Muzzle Velocity: ", math.Round(BulletData.MuzzleVel, 1), " m/s\n", "Max Penetration: ", math.floor(DData.MaxPen), " mm\n", "Expanded Caliber: ", math.floor(BulletData.ExpCaliber * 10), " mm\n", "Imparted Energy: ", math.floor(DData.MaxKETransfert), " KJ"} - - return table.concat(str) -end - -function Round.guicreate(Panel) - acfmenupanel:AmmoSelect(ACF.AmmoBlacklist.HP) - - acfmenupanel:CPanelText("Desc", "") --Description (Name, Desc) - acfmenupanel:CPanelText("LengthDisplay", "") --Total round length (Name, Desc) - acfmenupanel:AmmoSlider("PropLength", 0, 0, 1000, 3, "Propellant Length", "") --Propellant Length Slider (Name, Value, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("ProjLength", 0, 0, 1000, 3, "Projectile Length", "") --Projectile Length Slider (Name, Value, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("CavVol", 0, 0, 1000, 2, "Hollow Point Length", "") --Hollow Point Cavity Slider (Name, Value, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoCheckbox("Tracer", "Tracer", "") --Tracer checkbox (Name, Title, Desc) - acfmenupanel:CPanelText("VelocityDisplay", "") --Proj muzzle velocity (Name, Desc) - acfmenupanel:CPanelText("KEDisplay", "") --Proj muzzle KE (Name, Desc) - --acfmenupanel:CPanelText("RicoDisplay", "") --estimated rico chance - acfmenupanel:CPanelText("PenetrationDisplay", "") --Proj muzzle penetration (Name, Desc) - Round.guiupdate(Panel, nil) -end - -function Round.guiupdate(Panel) - local PlayerData = {} - PlayerData.Id = acfmenupanel.AmmoData.Data.id --AmmoSelect GUI - PlayerData.Type = "HP" --Hardcoded, match ACFRoundTypes table index - PlayerData.PropLength = acfmenupanel.AmmoData.PropLength --PropLength slider - PlayerData.ProjLength = acfmenupanel.AmmoData.ProjLength --ProjLength slider - PlayerData.Data5 = acfmenupanel.AmmoData.CavVol - local Tracer = 0 - - if acfmenupanel.AmmoData.Tracer then - Tracer = 1 - end - - PlayerData.Data10 = Tracer --Tracer - local Data = Round.convert(Panel, PlayerData) - RunConsoleCommand("acfmenu_data1", acfmenupanel.AmmoData.Data.id) - RunConsoleCommand("acfmenu_data2", PlayerData.Type) - RunConsoleCommand("acfmenu_data3", Data.PropLength) --For Gun ammo, Data3 should always be Propellant - RunConsoleCommand("acfmenu_data4", Data.ProjLength) --And Data4 total round mass - RunConsoleCommand("acfmenu_data5", Data.CavVol) - RunConsoleCommand("acfmenu_data10", Data.Tracer) - - acfmenupanel:AmmoUpdate() - acfmenupanel:AmmoSlider("PropLength", Data.PropLength, Data.MinPropLength, Data.MaxTotalLength, 3, "Propellant Length", "Propellant Mass : " .. (math.floor(Data.PropMass * 1000)) .. " g") --Propellant Length Slider (Name, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("ProjLength", Data.ProjLength, Data.MinProjLength, Data.MaxTotalLength, 3, "Projectile Length", "Projectile Mass : " .. (math.floor(Data.ProjMass * 1000)) .. " g") --Projectile Length Slider (Name, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("CavVol", Data.CavVol, Data.MinCavVol, Data.MaxCavVol, 2, "Hollow Point cavity Volume", "Expanded caliber : " .. (math.floor(Data.ExpCaliber * 10)) .. " mm") --Hollow Point Cavity Slider (Name, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoCheckbox("Tracer", "Tracer : " .. (math.floor(Data.Tracer * 10) / 10) .. "cm\n", "") --Tracer checkbox (Name, Title, Desc) - acfmenupanel:CPanelText("Desc", ACF.RoundTypes[PlayerData.Type].desc) --Description (Name, Desc) - acfmenupanel:CPanelText("LengthDisplay", "Cartridge Length : " .. (math.floor((Data.PropLength + Data.ProjLength + Data.Tracer) * 100) / 100) .. "/" .. Data.MaxTotalLength .. " cm") --Total round length (Name, Desc) - acfmenupanel:CPanelText("VelocityDisplay", "Muzzle Velocity : " .. math.floor(Data.MuzzleVel * ACF.Scale) .. " m/s") --Proj muzzle velocity (Name, Desc) - acfmenupanel:CPanelText("KEDisplay", "Kinetic Energy Transfered : " .. math.floor(Data.MaxKETransfert) .. " KJ") --Proj muzzle KE (Name, Desc) - --local RicoAngs = ACF_RicoProbability( Data.Ricochet, Data.MuzzleVel*ACF.Scale ) - --acfmenupanel:CPanelText("RicoDisplay", "Ricochet probability vs impact angle:\n".." 0% @ "..RicoAngs.Min.." degrees\n 50% @ "..RicoAngs.Mean.." degrees\n100% @ "..RicoAngs.Max.." degrees") - local R1V, R1P = ACF_PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 300) - local R2V, R2P = ACF_PenRanging(Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenArea, Data.LimitVel, 800) - acfmenupanel:CPanelText("PenetrationDisplay", "Maximum Penetration : " .. math.floor(Data.MaxPen) .. " mm RHA\n\n300m pen: " .. math.Round(R1P, 0) .. "mm @ " .. math.Round(R1V, 0) .. " m\\s\n800m pen: " .. math.Round(R2P, 0) .. "mm @ " .. math.Round(R2V, 0) .. " m\\s\n\nThe range data is an approximation and may not be entirely accurate.") --Proj muzzle penetration (Name, Desc) -end - -ACF.RoundTypes.HP = Round -- DELETE - -ACF.RegisterAmmoDecal("HP", "damage/ap_pen", "damage/ap_rico") \ No newline at end of file diff --git a/lua/acf/shared/rounds/refill.lua b/lua/acf/shared/rounds/refill.lua deleted file mode 100644 index 35e9ffd66..000000000 --- a/lua/acf/shared/rounds/refill.lua +++ /dev/null @@ -1,85 +0,0 @@ -local Round = {} -Round.type = "Ammo" --Tells the spawn menu what entity to spawn -Round.name = "Refill" --Human readable name -Round.model = "models/munitions/round_100mm_shot.mdl" --Shell flight model -Round.desc = "Ammo Refill" - --- Function to convert the player's slider data into the complete round data -function Round.convert(_, PlayerData) - local BulletData = { - Id = PlayerData.Id, - Type = PlayerData.Type, - Caliber = ACF.Weapons.Guns[PlayerData.Id].caliber, - ProjMass = 5.5 * 7.9 / 100, --Volume of the projectile as a cylinder * streamline factor (Data5) * density of steel - PropMass = 5.5 * ACF.PDensity / 1000, --Volume of the case as a cylinder * Powder density converted from g to kg - FillerMass = 0, - DragCoef = 0, - Tracer = 0, - MuzzleVel = 0, - RoundVolume = 35, - } - - BulletData.CartMass = BulletData.ProjMass + BulletData.PropMass - - return BulletData -end - -function Round.getDisplayData() - return {} -end - -function Round.network(Crate, BulletData) - Crate:SetNWString("AmmoType", "Refill") - Crate:SetNWString("AmmoID", BulletData.Id) - Crate:SetNWFloat("Caliber", BulletData.Caliber) - Crate:SetNWFloat("ProjMass", BulletData.ProjMass) - Crate:SetNWFloat("FillerMass", BulletData.FillerMass) - Crate:SetNWFloat("PropMass", BulletData.PropMass) - Crate:SetNWFloat("DragCoef", BulletData.DragCoef) - Crate:SetNWFloat("MuzzleVel", BulletData.MuzzleVel) - Crate:SetNWFloat("Tracer", BulletData.Tracer) -end - -function Round.cratetxt() - return "" -end - -function Round.OnFirst(Entity) - if not Entity.SupplyingTo then - Entity.SupplyingTo = {} - end - - timer.Create("ACF Refill " .. Entity:EntIndex(), 1, 0, function() - if not IsValid(Entity) then return end - - RefillCrates(Entity) - end) -end - -function Round.OnLast(Entity) - local CallName = "ACF Refill " .. Entity:EntIndex() - - for Crate in pairs(Entity.SupplyingTo) do - Crate:RemoveCallOnRemove(CallName) - end - - Entity.SupplyingTo = nil - - timer.Remove(CallName) -end - -function Round.guicreate(Panel, Table) - acfmenupanel:AmmoSelect() - acfmenupanel:CPanelText("Desc", "") --Description (Name, Desc) - Round.guiupdate(Panel, Table) -end - -function Round.guiupdate() - RunConsoleCommand("acfmenu_data1", acfmenupanel.CData.AmmoId or "12.7mmMG") - RunConsoleCommand("acfmenu_data2", "Refill") - - acfmenupanel:AmmoUpdate() - acfmenupanel.CustomDisplay:PerformLayout() -end - -ACF.RoundTypes.Refill = Round -- DELETE \ No newline at end of file diff --git a/lua/acf/shared/rounds/smoke.lua b/lua/acf/shared/rounds/smoke.lua deleted file mode 100644 index 3288afe56..000000000 --- a/lua/acf/shared/rounds/smoke.lua +++ /dev/null @@ -1,243 +0,0 @@ -ACF.AmmoBlacklist.SM = {"MG", "C", "GL", "HMG", "AL", "AC", "RAC", "SA", "SC"} -local Round = {} -Round.type = "Ammo" --Tells the spawn menu what entity to spawn -Round.name = "Smoke (SM)" --Human readable name -Round.model = "models/munitions/round_100mm_shot.mdl" --Shell flight model -Round.desc = "A shell filled white phosporous, detonating on impact. Smoke filler produces a long lasting cloud but takes a while to be effective, whereas WP filler quickly creates a cloud that also dissipates quickly." - -function Round.create(_, BulletData) - ACF_CreateBullet(BulletData) -end - --- Function to convert the player's slider data into the complete round data -function Round.convert(_, PlayerData) - local Data = {} - local ServerData = {} - local GUIData = {} - - if not PlayerData.PropLength then - PlayerData.PropLength = 0 - end - - if not PlayerData.ProjLength then - PlayerData.ProjLength = 0 - end - - PlayerData.Data5 = math.max(PlayerData.Data5 or 0, 0) - PlayerData.Data6 = math.max(PlayerData.Data6 or 0, 0) - - if not PlayerData.Data10 then - PlayerData.Data10 = 0 - end - - PlayerData, Data, ServerData, GUIData = ACF_RoundBaseGunpowder(PlayerData, Data, ServerData, GUIData) - --Shell sturdiness calcs - Data.ProjMass = math.max(GUIData.ProjVolume - PlayerData.Data5, 0) * 7.9 / 1000 + math.min(PlayerData.Data5, GUIData.ProjVolume) * ACF.HEDensity / 2000 --Volume of the projectile as a cylinder - Volume of the filler * density of steel + Volume of the filler * density of TNT - Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass, Data.Caliber) - local Energy = ACF_Kinetic(Data.MuzzleVel * 39.37, Data.ProjMass, Data.LimitVel) - local MaxVol = ACF_RoundShellCapacity(Energy.Momentum, Data.FrArea, Data.Caliber, Data.ProjLength) - GUIData.MinFillerVol = 0 - GUIData.MaxFillerVol = math.min(GUIData.ProjVolume, MaxVol) - GUIData.MaxSmokeVol = math.max(GUIData.MaxFillerVol - PlayerData.Data6, GUIData.MinFillerVol) - GUIData.MaxWPVol = math.max(GUIData.MaxFillerVol - PlayerData.Data5, GUIData.MinFillerVol) - local Ratio = math.min(GUIData.MaxFillerVol / (PlayerData.Data5 + PlayerData.Data6), 1) - GUIData.FillerVol = math.min(PlayerData.Data5 * Ratio, GUIData.MaxSmokeVol) - GUIData.WPVol = math.min(PlayerData.Data6 * Ratio, GUIData.MaxWPVol) - Data.FillerMass = GUIData.FillerVol * ACF.HEDensity / 2000 - Data.WPMass = GUIData.WPVol * ACF.HEDensity / 2000 - Data.ProjMass = math.max(GUIData.ProjVolume - (GUIData.FillerVol + GUIData.WPVol), 0) * 7.9 / 1000 + Data.FillerMass + Data.WPMass - Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass, Data.Caliber) - --Random bullshit left - Data.ShovePower = 0.1 - Data.PenArea = Data.FrArea ^ ACF.PenAreaMod - Data.DragCoef = ((Data.FrArea / 10000) / Data.ProjMass) - Data.LimitVel = 100 --Most efficient penetration speed in m/s - Data.KETransfert = 0.1 --Kinetic energy transfert to the target for movement purposes - Data.Ricochet = 60 --Base ricochet angle - Data.DetonatorAngle = 80 - Data.CanFuze = Data.Caliber > ACF.MinFuzeCaliber * 0.1 -- Can fuze on calibers > 20mm - Data.CartMass = Data.PropMass + Data.ProjMass - - --Only the crates need this part - if SERVER then - ServerData.Id = PlayerData.Id - ServerData.Type = PlayerData.Type - - return table.Merge(Data, ServerData) - end - - --Only the GUI needs this part - if CLIENT then - GUIData = table.Merge(GUIData, Round.getDisplayData(Data)) - - return table.Merge(Data, GUIData) - end -end - -function Round.network(Crate, BulletData) - Crate:SetNWString("AmmoType", "SM") - Crate:SetNWString("AmmoID", BulletData.Id) - Crate:SetNWFloat("Caliber", BulletData.Caliber) - Crate:SetNWFloat("ProjMass", BulletData.ProjMass) - Crate:SetNWFloat("FillerMass", BulletData.FillerMass) - Crate:SetNWFloat("WPMass", BulletData.WPMass) - Crate:SetNWFloat("PropMass", BulletData.PropMass) - Crate:SetNWFloat("DragCoef", BulletData.DragCoef) - Crate:SetNWFloat("MuzzleVel", BulletData.MuzzleVel) - Crate:SetNWFloat("Tracer", BulletData.Tracer) -end - -function Round.getDisplayData(Data) - local GUIData = {} - GUIData.SMFiller = math.min(math.log(1 + Data.FillerMass * 8 * 39.37) / 0.02303, 350) --smoke filler - GUIData.SMLife = math.Round(20 + GUIData.SMFiller / 4, 1) - GUIData.SMRadiusMin = math.Round(GUIData.SMFiller * 1.25 * 0.15 * 0.0254, 1) - GUIData.SMRadiusMax = math.Round(GUIData.SMFiller * 1.25 * 2 * 0.0254, 1) - GUIData.WPFiller = math.min(math.log(1 + Data.WPMass * 8 * 39.37) / 0.02303, 350) --wp filler - GUIData.WPLife = math.Round(6 + GUIData.WPFiller / 10, 1) - GUIData.WPRadiusMin = math.Round(GUIData.WPFiller * 1.25 * 0.0254, 1) - GUIData.WPRadiusMax = math.Round(GUIData.WPFiller * 1.25 * 2 * 0.0254, 1) - - return GUIData -end - -function Round.cratetxt(BulletData) - local GUIData = Round.getDisplayData(BulletData) - local str = {"Muzzle Velocity: ", math.Round(BulletData.MuzzleVel, 1), " m/s"} - - if GUIData.WPFiller > 0 then - local temp = {"\nWP Radius: ", GUIData.WPRadiusMin, " m to ", GUIData.WPRadiusMax, " m\n", "WP Lifetime: ", GUIData.WPLife, " s"} - - for i = 1, #temp do - str[#str + 1] = temp[i] - end - end - - if GUIData.SMFiller > 0 then - local temp = {"\nSM Radius: ", GUIData.SMRadiusMin, " m to ", GUIData.SMRadiusMax, " m\n", "SM Lifetime: ", GUIData.SMLife, " s"} - - for i = 1, #temp do - str[#str + 1] = temp[i] - end - end - - return table.concat(str) -end - -function Round.propimpact(_, Bullet, Target, HitNormal, HitPos, Bone) - if ACF_Check(Target) then - local Speed = Bullet.Flight:Length() / ACF.Scale - local Energy = ACF_Kinetic(Speed, Bullet.ProjMass - (Bullet.FillerMass + Bullet.WPMass), Bullet.LimitVel) - local HitRes = ACF_RoundImpact(Bullet, Speed, Energy, Target, HitPos, HitNormal, Bone) - if HitRes.Ricochet then return "Ricochet" end - end - - return false -end - -function Round.worldimpact() - return false -end - -function Round.endflight(Index) - ACF_RemoveBullet(Index) -end - -local DecalIndex = ACF.GetAmmoDecalIndex - -function Round.endeffect(_, Bullet) - local Crate = Bullet.Crate - local Color = IsValid(Crate) and Crate:GetColor() or Color(255, 255, 255) - - local Effect = EffectData() - Effect:SetOrigin(Bullet.SimPos) - Effect:SetNormal(Bullet.SimFlight:GetNormalized()) - Effect:SetScale(math.max(Bullet.FillerMass * 8 * 39.37, 0)) - Effect:SetMagnitude(math.max(Bullet.WPMass * 8 * 39.37, 0)) - Effect:SetStart(Vector(Color.r, Color.g, Color.b)) - Effect:SetRadius(Bullet.Caliber) - - util.Effect("ACF_Smoke", Effect) -end - -function Round.pierceeffect(_, Bullet) - local Effect = EffectData() - Effect:SetOrigin(Bullet.SimPos) - Effect:SetNormal(Bullet.SimFlight:GetNormalized()) - Effect:SetScale(Bullet.SimFlight:Length()) - Effect:SetMagnitude(Bullet.RoundMass) - Effect:SetRadius(Bullet.Caliber) - Effect:SetDamageType(DecalIndex(Bullet.AmmoType)) - - util.Effect("ACF_Penetration", Effect) -end - -function Round.ricocheteffect(_, Bullet) - local Effect = EffectData() - Effect:SetOrigin(Bullet.SimPos) - Effect:SetNormal(Bullet.SimFlight:GetNormalized()) - Effect:SetScale(Bullet.SimFlight:Length()) - Effect:SetMagnitude(Bullet.RoundMass) - Effect:SetRadius(Bullet.Caliber) - Effect:SetDamageType(DecalIndex(Bullet.AmmoType)) - - util.Effect("ACF_Ricochet", Effect) -end - -function Round.guicreate(Panel, Table) - acfmenupanel:AmmoSelect(ACF.AmmoBlacklist.SM) - - acfmenupanel:CPanelText("Desc", "") --Description (Name, Desc) - acfmenupanel:CPanelText("LengthDisplay", "") --Total round length (Name, Desc) - acfmenupanel:AmmoSlider("PropLength", 0, 0, 1000, 3, "Propellant Length", "") --Slider (Name, Value, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("ProjLength", 0, 0, 1000, 3, "Projectile Length", "") --Slider (Name, Value, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("FillerVol", 0, 0, 1000, 3, "Smoke Filler", "") --Slider (Name, Value, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("WPVol", 0, 0, 1000, 3, "WP Filler", "") --Slider (Name, Value, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoCheckbox("Tracer", "Tracer", "") --Tracer checkbox (Name, Title, Desc) - acfmenupanel:CPanelText("VelocityDisplay", "") --Proj muzzle velocity (Name, Desc) - acfmenupanel:CPanelText("BlastDisplay", "") --HE Blast data (Name, Desc) - acfmenupanel:CPanelText("FragDisplay", "") --HE Fragmentation data (Name, Desc) - Round.guiupdate(Panel, Table) -end - -function Round.guiupdate(Panel) - local PlayerData = {} - PlayerData.Id = acfmenupanel.AmmoData.Data.id --AmmoSelect GUI - PlayerData.Type = "SM" --Hardcoded, match ACFRoundTypes table index - PlayerData.PropLength = acfmenupanel.AmmoData.PropLength --PropLength slider - PlayerData.ProjLength = acfmenupanel.AmmoData.ProjLength --ProjLength slider - PlayerData.Data5 = acfmenupanel.AmmoData.FillerVol - PlayerData.Data6 = acfmenupanel.AmmoData.WPVol - - local Tracer = 0 - - if acfmenupanel.AmmoData.Tracer then - Tracer = 1 - end - - PlayerData.Data10 = Tracer --Tracer - local Data = Round.convert(Panel, PlayerData) - RunConsoleCommand("acfmenu_data1", acfmenupanel.AmmoData.Data.id) - RunConsoleCommand("acfmenu_data2", PlayerData.Type) - RunConsoleCommand("acfmenu_data3", Data.PropLength) --For Gun ammo, Data3 should always be Propellant - RunConsoleCommand("acfmenu_data4", Data.ProjLength) --And Data4 total round mass - RunConsoleCommand("acfmenu_data5", Data.FillerVol) - RunConsoleCommand("acfmenu_data6", Data.WPVol) - RunConsoleCommand("acfmenu_data10", Data.Tracer) - - acfmenupanel:AmmoUpdate() - acfmenupanel:AmmoSlider("PropLength", Data.PropLength, Data.MinPropLength, Data.MaxTotalLength, 3, "Propellant Length", "Propellant Mass : " .. (math.floor(Data.PropMass * 1000)) .. " g") --Propellant Length Slider (Name, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("ProjLength", Data.ProjLength, Data.MinProjLength, Data.MaxTotalLength, 3, "Projectile Length", "Projectile Mass : " .. (math.floor(Data.ProjMass * 1000)) .. " g") --Projectile Length Slider (Name, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("FillerVol", Data.FillerVol, Data.MinFillerVol, Data.MaxFillerVol, 3, "Smoke Filler Volume", "Smoke Filler Mass : " .. (math.floor(Data.FillerMass * 1000)) .. " g") --HE Filler Slider (Name, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoSlider("WPVol", Data.WPVol, Data.MinFillerVol, Data.MaxFillerVol, 3, "WP Filler Volume", "WP Filler Mass : " .. (math.floor(Data.WPMass * 1000)) .. " g") --HE Filler Slider (Name, Min, Max, Decimals, Title, Desc) - acfmenupanel:AmmoCheckbox("Tracer", "Tracer : " .. (math.floor(Data.Tracer * 10) / 10) .. "cm\n", "") --Tracer checkbox (Name, Title, Desc) - acfmenupanel:CPanelText("Desc", ACF.RoundTypes[PlayerData.Type].desc) --Description (Name, Desc) - acfmenupanel:CPanelText("LengthDisplay", "Cartridge Length : " .. (math.floor((Data.PropLength + Data.ProjLength + Data.Tracer) * 100) / 100) .. "/" .. Data.MaxTotalLength .. " cm") --Total round length (Name, Desc) - acfmenupanel:CPanelText("VelocityDisplay", "Muzzle Velocity : " .. math.floor(Data.MuzzleVel * ACF.Scale) .. " m/s") --Proj muzzle velocity (Name, Desc) - ---acfmenupanel:CPanelText("BlastDisplay", "Blast Radius : "..(math.floor(Data.BlastRadius*100)/1000).." m\n") --Proj muzzle velocity (Name, Desc) - ---acfmenupanel:CPanelText("FragDisplay", "Fragments : "..(Data.Fragments).."\n Average Fragment Weight : "..(math.floor(Data.FragMass*10000)/10).." ---g \n Average Fragment Velocity : "..math.floor(Data.FragVel).." m/s") --Proj muzzle penetration (Name, Desc) -end - -ACF.RoundTypes.SM = Round -- DELETE - -ACF.RegisterAmmoDecal("SM", "damage/he_pen", "damage/he_rico") \ No newline at end of file diff --git a/lua/acf/shared/tool_operations/acf_menu.lua b/lua/acf/shared/tool_operations/acf_menu.lua index 426cb6cc4..e3bb60dbf 100644 --- a/lua/acf/shared/tool_operations/acf_menu.lua +++ b/lua/acf/shared/tool_operations/acf_menu.lua @@ -185,6 +185,7 @@ do -- Linker operation UnselectEntity(Tool, Player, K) end + -- TODO: Add list of reasons for failed links if Done > 0 then local Status = (Unlink and "unlinked " or "linked ") .. Done .. " out of " .. Total diff --git a/lua/autorun/acf_loader.lua b/lua/autorun/acf_loader.lua index 657a50fd8..f5bb94298 100644 --- a/lua/autorun/acf_loader.lua +++ b/lua/autorun/acf_loader.lua @@ -15,93 +15,8 @@ ]]-- MsgN("\n===========[ Loading ACF ]============\n|") -local GunClasses = {} -- DELETE -local GunTable = {} -- DELETE -local MobilityTable = {} -- DELETE -local FuelTankTable = {} -- DELETE - if not ACF then ACF = {} end -ACF.RoundTypes = ACF.RoundTypes or {} -- DELETE - -ACF.Classes = ACF.Classes or { -- DELETE - GunClass = GunClasses -} - -ACF.Weapons = ACF.Weapons or { -- DELETE - Guns = GunTable, - Mobility = MobilityTable, - FuelTanks = FuelTankTable -} - -local gun_base = { -- DELETE - ent = "acf_gun", - type = "Guns" -} - -local engine_base = { -- DELETE - ent = "acf_engine", - type = "Mobility" -} - -local gearbox_base = { -- DELETE - ent = "acf_gearbox", - type = "Mobility", - sound = "vehicles/junker/jnk_fourth_cruise_loop2.wav" -} - -local fueltank_base = { -- DELETE - ent = "acf_fueltank", - type = "Mobility", - explosive = true -} - -do - -- REPLACE - function ACF_defineGunClass( id, data ) - data.id = id - GunClasses[ id ] = data - - PrecacheParticleSystem(data["muzzleflash"]) - end - - -- REPLACE - function ACF_defineGun( id, data ) - data.id = id - data.round.id = id - table.Inherit( data, gun_base ) - GunTable[ id ] = data - end - - -- REPLACE - function ACF_DefineEngine( id, data ) - data.id = id - table.Inherit( data, engine_base ) - MobilityTable[ id ] = data - end - - -- REPLACE - function ACF_DefineGearbox( id, data ) - data.id = id - table.Inherit( data, gearbox_base ) - MobilityTable[ id ] = data - end - - -- REPLACE - function ACF_DefineFuelTank( id, data ) - data.id = id - table.Inherit( data, fueltank_base ) - MobilityTable[ id ] = data - end - - -- REPLACE - function ACF_DefineFuelTankSize( id, data ) - data.id = id - table.Inherit( data, fueltank_base ) - FuelTankTable[ id ] = data - end -end - if SERVER then local Realms = {client = "client", server = "server", shared = "shared"} local Text = "| > Loaded %s serverside file(s).\n| > Loaded %s shared file(s).\n| > Loaded %s clientside file(s)." @@ -166,16 +81,6 @@ if SERVER then MsgN(Text:format(ServerCount, SharedCount, ClientCount)) elseif CLIENT then - - gun_base.guicreate = function( _, tbl ) ACFGunGUICreate( tbl ) end or nil - gun_base.guiupdate = function() return end - engine_base.guicreate = function( _, tbl ) ACFEngineGUICreate( tbl ) end or nil - engine_base.guiupdate = function() return end - gearbox_base.guicreate = function( _, tbl ) ACFGearboxGUICreate( tbl ) end or nil - gearbox_base.guiupdate = function() return end - fueltank_base.guicreate = function( _, tbl ) ACFFuelTankGUICreate( tbl ) end or nil - fueltank_base.guiupdate = function( _, tbl ) ACFFuelTankGUIUpdate( tbl ) end or nil - local Text = "| > Loaded %s clientside file(s).\n| > Skipped %s clientside file(s)." local FileCount, SkipCount = 0, 0 diff --git a/lua/effects/acf_bullet_effect.lua b/lua/effects/acf_bullet_effect.lua index ee73ce5d5..65945f96f 100644 --- a/lua/effects/acf_bullet_effect.lua +++ b/lua/effects/acf_bullet_effect.lua @@ -54,6 +54,7 @@ function EFFECT:Init(Data) return end + -- TODO: Force crates to network and store this information on the client when they're created local Tracer = Crate:GetNW2Float("Tracer") > 0 local BulletData = { Crate = Crate, diff --git a/lua/entities/acf_engine/cl_init.lua b/lua/entities/acf_engine/cl_init.lua index 15acdf0a0..0e407ea96 100644 --- a/lua/entities/acf_engine/cl_init.lua +++ b/lua/entities/acf_engine/cl_init.lua @@ -20,55 +20,3 @@ function ENT:Draw() Wire_DrawTracerBeam(self, 1, self.GetBeamHighlight and self:GetBeamHighlight() or false) end end - --- DELETE -function ACFEngineGUICreate(Table) - acfmenupanel:CPanelText("Name", Table.name) - acfmenupanel.CData.DisplayModel = vgui.Create("DModelPanel", acfmenupanel.CustomDisplay) - acfmenupanel.CData.DisplayModel:SetModel(Table.model) - acfmenupanel.CData.DisplayModel:SetCamPos(Vector(250, 500, 250)) - acfmenupanel.CData.DisplayModel:SetLookAt(Vector(0, 0, 0)) - acfmenupanel.CData.DisplayModel:SetFOV(20) - acfmenupanel.CData.DisplayModel:SetSize(acfmenupanel:GetWide(), acfmenupanel:GetWide()) - acfmenupanel.CData.DisplayModel.LayoutEntity = function() end - acfmenupanel.CustomDisplay:AddItem(acfmenupanel.CData.DisplayModel) - acfmenupanel:CPanelText("Desc", Table.desc) - local peakkw - local peakkwrpm - local pbmin - local pbmax - - --elecs and turbs get peak power in middle of rpm range - if (Table.iselec == true) then - peakkw = (Table.torque * (1 + Table.peakmaxrpm / Table.limitrpm)) * Table.limitrpm / (4 * 9548.8) --adjust torque to 1 rpm maximum, assuming a linear decrease from a max @ 1 rpm to min @ limiter - peakkwrpm = math.floor(Table.limitrpm / 2) - pbmin = Table.idlerpm - pbmax = peakkwrpm - else - peakkw = Table.torque * Table.peakmaxrpm / 9548.8 - peakkwrpm = Table.peakmaxrpm - pbmin = Table.peakminrpm - pbmax = Table.peakmaxrpm - end - - acfmenupanel:CPanelText("Power", "\nPeak Power : " .. math.floor(peakkw) .. " kW / " .. math.Round(peakkw * 1.34) .. " HP @ " .. peakkwrpm .. " RPM") - acfmenupanel:CPanelText("Torque", "Peak Torque : " .. Table.torque .. " n/m / " .. math.Round(Table.torque * 0.73) .. " ft-lb") - acfmenupanel:CPanelText("RPM", "Idle : " .. Table.idlerpm .. " RPM\nPowerband : " .. pbmin .. "-" .. pbmax .. " RPM\nRedline : " .. Table.limitrpm .. " RPM") - acfmenupanel:CPanelText("Weight", "Weight : " .. Table.weight .. " kg") - acfmenupanel:CPanelText("FuelType", "\nFuel Type : " .. Table.fuel) - - if Table.fuel == "Electric" then - local cons = ACF.FuelRate * peakkw / ACF.Efficiency[Table.enginetype] - acfmenupanel:CPanelText("FuelCons", "Peak energy use : " .. math.Round(cons, 1) .. " kW / " .. math.Round(0.06 * cons, 1) .. " MJ/min") - elseif Table.fuel == "Multifuel" then - local petrolcons = ACF.FuelRate * ACF.Efficiency[Table.enginetype] * peakkw / (60 * ACF.FuelDensity.Petrol) - local dieselcons = ACF.FuelRate * ACF.Efficiency[Table.enginetype] * peakkw / (60 * ACF.FuelDensity.Diesel) - acfmenupanel:CPanelText("FuelConsP", "Petrol Use at " .. peakkwrpm .. " rpm : " .. math.Round(petrolcons, 2) .. " liters/min / " .. math.Round(0.264 * petrolcons, 2) .. " gallons/min") - acfmenupanel:CPanelText("FuelConsD", "Diesel Use at " .. peakkwrpm .. " rpm : " .. math.Round(dieselcons, 2) .. " liters/min / " .. math.Round(0.264 * dieselcons, 2) .. " gallons/min") - else - local fuelcons = ACF.FuelRate * ACF.Efficiency[Table.enginetype] * peakkw / (60 * ACF.FuelDensity[Table.fuel]) - acfmenupanel:CPanelText("FuelCons", Table.fuel .. " Use at " .. peakkwrpm .. " rpm : " .. math.Round(fuelcons, 2) .. " liters/min / " .. math.Round(0.264 * fuelcons, 2) .. " gallons/min") - end - - acfmenupanel.CustomDisplay:PerformLayout() -end diff --git a/lua/entities/acf_fueltank/cl_init.lua b/lua/entities/acf_fueltank/cl_init.lua index 13c315bd6..e8929ba31 100644 --- a/lua/entities/acf_fueltank/cl_init.lua +++ b/lua/entities/acf_fueltank/cl_init.lua @@ -31,111 +31,3 @@ function ENT:Draw() Wire_DrawTracerBeam(self, 1, self.GetBeamHighlight and self:GetBeamHighlight() or false) end end - --- DELETE -function ACFFuelTankGUICreate(Table) - if not acfmenupanel.CustomDisplay then return end - - if not acfmenupanel.FuelTankData then - acfmenupanel.FuelTankData = {} - acfmenupanel.FuelTankData.Id = "Tank_4x4x2" - acfmenupanel.FuelTankData.FuelID = "Petrol" - end - - local Tanks = ACF.Weapons.FuelTanks - local SortedTanks = {} - - for n in pairs(Tanks) do - table.insert(SortedTanks, n) - end - - table.sort(SortedTanks) - acfmenupanel:CPanelText("Name", Table.name) - acfmenupanel:CPanelText("Desc", Table.desc) - -- tank size dropbox - acfmenupanel.CData.TankSizeSelect = vgui.Create("DComboBox", acfmenupanel.CustomDisplay) - acfmenupanel.CData.TankSizeSelect:SetSize(100, 30) - - for _, v in ipairs(SortedTanks) do - acfmenupanel.CData.TankSizeSelect:AddChoice(v) - end - - acfmenupanel.CData.TankSizeSelect.OnSelect = function(_, _, data) - RunConsoleCommand("acfmenu_data1", data) - acfmenupanel.FuelTankData.Id = data - ACFFuelTankGUIUpdate(Table) - end - - acfmenupanel.CData.TankSizeSelect:SetText(acfmenupanel.FuelTankData.Id) - RunConsoleCommand("acfmenu_data1", acfmenupanel.FuelTankData.Id) - acfmenupanel.CustomDisplay:AddItem(acfmenupanel.CData.TankSizeSelect) - -- fuel type dropbox - acfmenupanel.CData.FuelSelect = vgui.Create("DComboBox", acfmenupanel.CustomDisplay) - acfmenupanel.CData.FuelSelect:SetSize(100, 30) - - for Key in pairs(ACF.FuelDensity) do - acfmenupanel.CData.FuelSelect:AddChoice(Key) - end - - acfmenupanel.CData.FuelSelect.OnSelect = function(_, _, data) - RunConsoleCommand("acfmenu_data2", data) - acfmenupanel.FuelTankData.FuelID = data - ACFFuelTankGUIUpdate(Table) - end - - acfmenupanel.CData.FuelSelect:SetText(acfmenupanel.FuelTankData.FuelID) - RunConsoleCommand("acfmenu_data2", acfmenupanel.FuelTankData.FuelID) - acfmenupanel.CustomDisplay:AddItem(acfmenupanel.CData.FuelSelect) - ACFFuelTankGUIUpdate(Table) - acfmenupanel.CustomDisplay:PerformLayout() -end - --- DELETE -function ACFFuelTankGUIUpdate() - if not acfmenupanel.CustomDisplay then return end - local Tanks = ACF.Weapons.FuelTanks - local TankID = acfmenupanel.FuelTankData.Id - local FuelID = acfmenupanel.FuelTankData.FuelID - local Dims = Tanks[TankID].dims - local Wall = 0.03937 --wall thickness in inches (1mm) - local Volume = Dims.V - (Dims.S * Wall) -- total volume of tank (cu in), reduced by wall thickness - local Capacity = Volume * ACF.CuIToLiter * ACF.TankVolumeMul * 0.4774 --internal volume available for fuel in liters, with magic realism number - local EmptyMass = ((Dims.S * Wall) * 16.387) * (7.9 / 1000) -- total wall volume * cu in to cc * density of steel (kg/cc) - local Mass = EmptyMass + Capacity * ACF.FuelDensity[FuelID] -- weight of tank + weight of fuel - - --fuel and tank info - if FuelID == "Electric" then - local kwh = Capacity * ACF.LiIonED - acfmenupanel:CPanelText("TankName", Tanks[TankID].name .. " Li-Ion Battery") - acfmenupanel:CPanelText("TankDesc", Tanks[TankID].desc .. "\n") - acfmenupanel:CPanelText("Cap", "Charge: " .. math.Round(kwh, 1) .. " kW hours / " .. math.Round(kwh * 3.6, 1) .. " MJ") - acfmenupanel:CPanelText("Mass", "Mass: " .. math.Round(Mass, 1) .. " kg") - else - acfmenupanel:CPanelText("TankName", Tanks[TankID].name .. " fuel tank") - acfmenupanel:CPanelText("TankDesc", Tanks[TankID].desc .. "\n") - acfmenupanel:CPanelText("Cap", "Capacity: " .. math.Round(Capacity, 1) .. " liters / " .. math.Round(Capacity * 0.264172, 1) .. " gallons") - acfmenupanel:CPanelText("Mass", "Full mass: " .. math.Round(Mass, 1) .. " kg, Empty mass: " .. math.Round(EmptyMass, 1) .. " kg") - end - - local text = "\n" - - if Tanks[TankID].nolinks then - text = "\nThis fuel tank won\'t link to engines. It's intended to resupply fuel to other fuel tanks." - end - - acfmenupanel:CPanelText("Links", text) - - --fuel tank model display - if not acfmenupanel.CData.DisplayModel then - acfmenupanel.CData.DisplayModel = vgui.Create("DModelPanel", acfmenupanel.CustomDisplay) - acfmenupanel.CData.DisplayModel:SetModel(Tanks[TankID].model) - acfmenupanel.CData.DisplayModel:SetCamPos(Vector(250, 500, 200)) - acfmenupanel.CData.DisplayModel:SetLookAt(Vector(0, 0, 0)) - acfmenupanel.CData.DisplayModel:SetFOV(10) - acfmenupanel.CData.DisplayModel:SetSize(acfmenupanel:GetWide(), acfmenupanel:GetWide()) - acfmenupanel.CData.DisplayModel.LayoutEntity = function() end - acfmenupanel.CustomDisplay:AddItem(acfmenupanel.CData.DisplayModel) - end - - acfmenupanel.CData.DisplayModel:SetModel(Tanks[TankID].model) -end \ No newline at end of file diff --git a/lua/entities/acf_gearbox/cl_init.lua b/lua/entities/acf_gearbox/cl_init.lua index 535061202..ced6f6e7e 100644 --- a/lua/entities/acf_gearbox/cl_init.lua +++ b/lua/entities/acf_gearbox/cl_init.lua @@ -20,233 +20,3 @@ function ENT:Draw() Wire_DrawTracerBeam(self, 1, self.GetBeamHighlight and self:GetBeamHighlight() or false) end end - -function ACFGearboxGUICreate(Table) - if not acfmenupanel.Serialize then - acfmenupanel.Serialize = function(tbl, factor) - local str = "" - - for i = 1, 7 do - str = str .. math.Round(tbl[i] * factor, 1) .. "," - end - - RunConsoleCommand("acfmenu_data9", str) - end - end - - if not acfmenupanel.GearboxData then - acfmenupanel.GearboxData = {} - end - - if not acfmenupanel.GearboxData[Table.id] then - acfmenupanel.GearboxData[Table.id] = {} - acfmenupanel.GearboxData[Table.id].GearTable = Table.geartable - end - - if Table.auto and not acfmenupanel.GearboxData[Table.id].ShiftTable then - acfmenupanel.GearboxData[Table.id].ShiftTable = {10, 20, 30, 40, 50, 60, 70} - end - - acfmenupanel:CPanelText("Name", Table.name) - acfmenupanel.CData.DisplayModel = vgui.Create("DModelPanel", acfmenupanel.CustomDisplay) - acfmenupanel.CData.DisplayModel:SetModel(Table.model) - acfmenupanel.CData.DisplayModel:SetCamPos(Vector(250, 500, 250)) - acfmenupanel.CData.DisplayModel:SetLookAt(Vector(0, 0, 0)) - acfmenupanel.CData.DisplayModel:SetFOV(20) - acfmenupanel.CData.DisplayModel:SetSize(acfmenupanel:GetWide(), acfmenupanel:GetWide()) - acfmenupanel.CData.DisplayModel.LayoutEntity = function() end - acfmenupanel.CustomDisplay:AddItem(acfmenupanel.CData.DisplayModel) - acfmenupanel:CPanelText("Desc", Table.desc) --Description (Name, Desc) - - if Table.auto and not acfmenupanel.CData.UnitsInput then - acfmenupanel.CData.UnitsInput = vgui.Create("DComboBox", acfmenupanel.CustomDisplay) - acfmenupanel.CData.UnitsInput.ID = Table.id - acfmenupanel.CData.UnitsInput.Gears = Table.gears - acfmenupanel.CData.UnitsInput:SetSize(60, 22) - acfmenupanel.CData.UnitsInput:SetTooltip("If using the shift point generator, recalc after changing units.") - acfmenupanel.CData.UnitsInput:AddChoice("KPH", 10.936, true) - acfmenupanel.CData.UnitsInput:AddChoice("MPH", 17.6) - acfmenupanel.CData.UnitsInput:AddChoice("GMU", 1) - acfmenupanel.CData.UnitsInput:SetDark(true) - - acfmenupanel.CData.UnitsInput.OnSelect = function(panel, _, _, data) - acfmenupanel.Serialize(acfmenupanel.GearboxData[panel.ID].ShiftTable, data) --dot intentional - end - - acfmenupanel.CustomDisplay:AddItem(acfmenupanel.CData.UnitsInput) - end - - if Table.cvt then - ACF_GearsSlider(2, acfmenupanel.GearboxData[Table.id].GearTable[2], Table.id) - ACF_GearsSlider(3, acfmenupanel.GearboxData[Table.id].GearTable[-3], Table.id, "Min Target RPM", true) - ACF_GearsSlider(4, acfmenupanel.GearboxData[Table.id].GearTable[-2], Table.id, "Max Target RPM", true) - ACF_GearsSlider(10, acfmenupanel.GearboxData[Table.id].GearTable[-1], Table.id, "Final Drive") - RunConsoleCommand("acfmenu_data1", 0.01) - else - for ID, Value in pairs(acfmenupanel.GearboxData[Table.id].GearTable) do - if ID > 0 and not (Table.auto and ID == 8) then - ACF_GearsSlider(ID, Value, Table.id) - - if Table.auto then - ACF_ShiftPoint(ID, acfmenupanel.GearboxData[Table.id].ShiftTable[ID], Table.id, "Gear " .. ID .. " upshift speed: ") - end - elseif Table.auto and (ID == -2 or ID == 8) then - ACF_GearsSlider(8, Value, Table.id, "Reverse") - elseif ID == -1 then - ACF_GearsSlider(10, Value, Table.id, "Final Drive") - end - end - end - - acfmenupanel:CPanelText("Desc", Table.desc) - acfmenupanel:CPanelText("MaxTorque", "Clutch Maximum Torque Rating : " .. Table.maxtq .. "n-m / " .. math.Round(Table.maxtq * 0.73) .. "ft-lb") - acfmenupanel:CPanelText("Weight", "Weight : " .. Table.weight .. "kg") - - if Table.parentable then - acfmenupanel:CPanelText("Parentable", "\nThis gearbox can be parented without welding.") - end - - if Table.auto then - acfmenupanel:CPanelText("ShiftPointGen", "\nShift Point Generator:") - - if not acfmenupanel.CData.ShiftGenPanel then - acfmenupanel.CData.ShiftGenPanel = vgui.Create("DPanel") - acfmenupanel.CData.ShiftGenPanel:SetPaintBackground(false) - acfmenupanel.CData.ShiftGenPanel:DockPadding(4, 0, 4, 0) - acfmenupanel.CData.ShiftGenPanel:SetTall(60) - acfmenupanel.CData.ShiftGenPanel:SizeToContentsX() - acfmenupanel.CData.ShiftGenPanel.Gears = Table.gears - acfmenupanel.CData.ShiftGenPanel.Calc = acfmenupanel.CData.ShiftGenPanel:Add("DButton") - acfmenupanel.CData.ShiftGenPanel.Calc:SetText("Calculate") - acfmenupanel.CData.ShiftGenPanel.Calc:Dock(BOTTOM) - --acfmenupanel.CData.ShiftGenPanel.Calc:SetWide( 80 ) - acfmenupanel.CData.ShiftGenPanel.Calc:SetTall(20) - - acfmenupanel.CData.ShiftGenPanel.Calc.DoClick = function() - local _, factor = acfmenupanel.CData.UnitsInput:GetSelected() - local mul = math.pi * acfmenupanel.CData.ShiftGenPanel.RPM:GetValue() * acfmenupanel.CData.ShiftGenPanel.Ratio:GetValue() * acfmenupanel.CData[10]:GetValue() * acfmenupanel.CData.ShiftGenPanel.Wheel:GetValue() / (60 * factor) - - for i = 1, acfmenupanel.CData.ShiftGenPanel.Gears do - acfmenupanel.CData[10 + i].Input:SetValue(math.Round(math.abs(mul * acfmenupanel.CData[i]:GetValue()), 2)) - acfmenupanel.GearboxData[acfmenupanel.CData.UnitsInput.ID].ShiftTable[i] = tonumber(acfmenupanel.CData[10 + i].Input:GetValue()) - end - - acfmenupanel.Serialize(acfmenupanel.GearboxData[acfmenupanel.CData.UnitsInput.ID].ShiftTable, factor) --dot intentional - end - - acfmenupanel.CData.WheelPanel = acfmenupanel.CData.ShiftGenPanel:Add("DPanel") - acfmenupanel.CData.WheelPanel:SetPaintBackground(false) - acfmenupanel.CData.WheelPanel:DockMargin(4, 0, 4, 0) - acfmenupanel.CData.WheelPanel:Dock(RIGHT) - acfmenupanel.CData.WheelPanel:SetWide(76) - acfmenupanel.CData.WheelPanel:SetTooltip("If you use default spherical settings, add 0.5 to your wheel diameter.\nFor treaded vehicles, use the diameter of road wheels, not drive wheels.") - acfmenupanel.CData.ShiftGenPanel.WheelLabel = acfmenupanel.CData.WheelPanel:Add("DLabel") - acfmenupanel.CData.ShiftGenPanel.WheelLabel:Dock(TOP) - acfmenupanel.CData.ShiftGenPanel.WheelLabel:SetDark(true) - acfmenupanel.CData.ShiftGenPanel.WheelLabel:SetText("Wheel Diameter:") - acfmenupanel.CData.ShiftGenPanel.Wheel = acfmenupanel.CData.WheelPanel:Add("DNumberWang") - acfmenupanel.CData.ShiftGenPanel.Wheel:HideWang() - acfmenupanel.CData.ShiftGenPanel.Wheel:SetDrawBorder(false) - acfmenupanel.CData.ShiftGenPanel.Wheel:Dock(BOTTOM) - acfmenupanel.CData.ShiftGenPanel.Wheel:SetDecimals(2) - acfmenupanel.CData.ShiftGenPanel.Wheel:SetMinMax(0, 9999) - acfmenupanel.CData.ShiftGenPanel.Wheel:SetValue(30) - acfmenupanel.CData.RatioPanel = acfmenupanel.CData.ShiftGenPanel:Add("DPanel") - acfmenupanel.CData.RatioPanel:SetPaintBackground(false) - acfmenupanel.CData.RatioPanel:DockMargin(4, 0, 4, 0) - acfmenupanel.CData.RatioPanel:Dock(RIGHT) - acfmenupanel.CData.RatioPanel:SetWide(76) - acfmenupanel.CData.RatioPanel:SetTooltip("Total ratio is the ratio of all gearboxes (exluding this one) multiplied together.\nFor example, if you use engine to automatic to diffs to wheels, your total ratio would be (diff gear ratio * diff final ratio).") - acfmenupanel.CData.ShiftGenPanel.RatioLabel = acfmenupanel.CData.RatioPanel:Add("DLabel") - acfmenupanel.CData.ShiftGenPanel.RatioLabel:Dock(TOP) - acfmenupanel.CData.ShiftGenPanel.RatioLabel:SetDark(true) - acfmenupanel.CData.ShiftGenPanel.RatioLabel:SetText("Total ratio:") - acfmenupanel.CData.ShiftGenPanel.Ratio = acfmenupanel.CData.RatioPanel:Add("DNumberWang") - acfmenupanel.CData.ShiftGenPanel.Ratio:HideWang() - acfmenupanel.CData.ShiftGenPanel.Ratio:SetDrawBorder(false) - acfmenupanel.CData.ShiftGenPanel.Ratio:Dock(BOTTOM) - acfmenupanel.CData.ShiftGenPanel.Ratio:SetDecimals(2) - acfmenupanel.CData.ShiftGenPanel.Ratio:SetMinMax(0, 9999) - acfmenupanel.CData.ShiftGenPanel.Ratio:SetValue(0.1) - acfmenupanel.CData.RPMPanel = acfmenupanel.CData.ShiftGenPanel:Add("DPanel") - acfmenupanel.CData.RPMPanel:SetPaintBackground(false) - acfmenupanel.CData.RPMPanel:DockMargin(4, 0, 4, 0) - acfmenupanel.CData.RPMPanel:Dock(RIGHT) - acfmenupanel.CData.RPMPanel:SetWide(76) - acfmenupanel.CData.RPMPanel:SetTooltip("Target engine RPM to upshift at.") - acfmenupanel.CData.ShiftGenPanel.RPMLabel = acfmenupanel.CData.RPMPanel:Add("DLabel") - acfmenupanel.CData.ShiftGenPanel.RPMLabel:Dock(TOP) - acfmenupanel.CData.ShiftGenPanel.RPMLabel:SetDark(true) - acfmenupanel.CData.ShiftGenPanel.RPMLabel:SetText("Upshift RPM:") - acfmenupanel.CData.ShiftGenPanel.RPM = acfmenupanel.CData.RPMPanel:Add("DNumberWang") - acfmenupanel.CData.ShiftGenPanel.RPM:HideWang() - acfmenupanel.CData.ShiftGenPanel.RPM:SetDrawBorder(false) - acfmenupanel.CData.ShiftGenPanel.RPM:Dock(BOTTOM) - acfmenupanel.CData.ShiftGenPanel.RPM:SetDecimals(2) - acfmenupanel.CData.ShiftGenPanel.RPM:SetMinMax(0, 9999) - acfmenupanel.CData.ShiftGenPanel.RPM:SetValue(5000) - acfmenupanel.CustomDisplay:AddItem(acfmenupanel.CData.ShiftGenPanel) - end - end - - acfmenupanel.CustomDisplay:PerformLayout() - maxtorque = Table.maxtq -end - -function ACF_GearsSlider(Gear, Value, ID, Desc, CVT) - if Gear and not acfmenupanel.CData[Gear] then - acfmenupanel.CData[Gear] = vgui.Create("DNumSlider", acfmenupanel.CustomDisplay) - acfmenupanel.CData[Gear]:SetText(Desc or "Gear " .. Gear) - acfmenupanel.CData[Gear].Label:SizeToContents() - acfmenupanel.CData[Gear]:SetDark(true) - acfmenupanel.CData[Gear]:SetMin(CVT and 1 or -1) - acfmenupanel.CData[Gear]:SetMax(CVT and 10000 or 1) - acfmenupanel.CData[Gear]:SetDecimals((not CVT) and 2 or 0) - acfmenupanel.CData[Gear].Gear = Gear - acfmenupanel.CData[Gear].ID = ID - acfmenupanel.CData[Gear]:SetValue(Value) - RunConsoleCommand("acfmenu_data" .. Gear, Value) - - acfmenupanel.CData[Gear].OnValueChanged = function(slider, val) - acfmenupanel.GearboxData[slider.ID].GearTable[slider.Gear] = val - RunConsoleCommand("acfmenu_data" .. Gear, val) - end - - acfmenupanel.CustomDisplay:AddItem(acfmenupanel.CData[Gear]) - end -end - -function ACF_ShiftPoint(Gear, Value, ID, Desc) - local Index = Gear + 10 - - if Gear and not acfmenupanel.CData[Index] then - acfmenupanel.CData[Index] = vgui.Create("DPanel") - acfmenupanel.CData[Index]:SetPaintBackground(false) - acfmenupanel.CData[Index]:SetTall(20) - acfmenupanel.CData[Index]:SizeToContentsX() - acfmenupanel.CData[Index].Input = acfmenupanel.CData[Index]:Add("DNumberWang") - acfmenupanel.CData[Index].Input.Gear = Gear - acfmenupanel.CData[Index].Input.ID = ID - acfmenupanel.CData[Index].Input:HideWang() - acfmenupanel.CData[Index].Input:SetDrawBorder(false) - acfmenupanel.CData[Index].Input:SetDecimals(2) - acfmenupanel.CData[Index].Input:SetMinMax(0, 9999) - acfmenupanel.CData[Index].Input:SetValue(Value) - acfmenupanel.CData[Index].Input:Dock(RIGHT) - acfmenupanel.CData[Index].Input:SetWide(45) - - acfmenupanel.CData[Index].Input.OnValueChanged = function(box, value) - acfmenupanel.GearboxData[box.ID].ShiftTable[box.Gear] = value - local _, factor = acfmenupanel.CData.UnitsInput:GetSelected() - acfmenupanel.Serialize(acfmenupanel.GearboxData[acfmenupanel.CData.UnitsInput.ID].ShiftTable, factor) --dot intentional - end - - RunConsoleCommand("acfmenu_data9", "10,20,30,40,50,60,70") - acfmenupanel.CData[Index].Label = acfmenupanel.CData[Index]:Add("DLabel") - acfmenupanel.CData[Index].Label:Dock(RIGHT) - acfmenupanel.CData[Index].Label:SetWide(120) - acfmenupanel.CData[Index].Label:SetDark(true) - acfmenupanel.CData[Index].Label:SetText(Desc) - acfmenupanel.CustomDisplay:AddItem(acfmenupanel.CData[Index]) - end -end diff --git a/lua/entities/acf_gun/cl_init.lua b/lua/entities/acf_gun/cl_init.lua index 4db336711..c2cf87913 100644 --- a/lua/entities/acf_gun/cl_init.lua +++ b/lua/entities/acf_gun/cl_init.lua @@ -73,35 +73,3 @@ function ENT:Animate(ReloadTime, LoadOnly) self.LastFire = CurTime() self.Reload = ReloadTime end - --- DELETE -function ACFGunGUICreate(Table) - acfmenupanel:CPanelText("Name", Table.name) - acfmenupanel.CData.DisplayModel = vgui.Create("DModelPanel", acfmenupanel.CustomDisplay) - acfmenupanel.CData.DisplayModel:SetModel(Table.model) - acfmenupanel.CData.DisplayModel:SetCamPos(Vector(250, 500, 250)) - acfmenupanel.CData.DisplayModel:SetLookAt(Vector(0, 0, 0)) - acfmenupanel.CData.DisplayModel:SetFOV(20) - acfmenupanel.CData.DisplayModel:SetSize(acfmenupanel:GetWide(), acfmenupanel:GetWide()) - acfmenupanel.CData.DisplayModel.LayoutEntity = function() end - acfmenupanel.CustomDisplay:AddItem(acfmenupanel.CData.DisplayModel) - local GunClass = ACF.Classes.GunClass[Table.gunclass] - acfmenupanel:CPanelText("ClassDesc", GunClass.desc) - acfmenupanel:CPanelText("GunDesc", Table.desc) - acfmenupanel:CPanelText("Caliber", "Caliber : " .. (Table.caliber * 10) .. "mm") - acfmenupanel:CPanelText("Weight", "Weight : " .. Table.weight .. "kg") - - if not Table.rack then - local RoundVolume = 3.1416 * (Table.caliber / 2) ^ 2 * Table.round.maxlength - local RoF = 60 / (((RoundVolume / 500) ^ 0.60) * GunClass.rofmod * (Table.rofmod or 1)) -- TODO: FIX THIS (USING OLD RELOAD CALC) - acfmenupanel:CPanelText("Firerate", "RoF : " .. math.Round(RoF, 1) .. " rounds/min") - - if Table.magsize then - acfmenupanel:CPanelText("Magazine", "Magazine : " .. Table.magsize .. " rounds\nReload : " .. Table.magreload .. " s") - end - - acfmenupanel:CPanelText("Spread", "Spread : " .. GunClass.spread .. " degrees") - end - - acfmenupanel.CustomDisplay:PerformLayout() -end diff --git a/lua/entities/base_scalable_box/init.lua b/lua/entities/base_scalable_box/init.lua index 8d15f28c1..f484ee24b 100644 --- a/lua/entities/base_scalable_box/init.lua +++ b/lua/entities/base_scalable_box/init.lua @@ -13,7 +13,7 @@ function CreateScalableBox(Player, Pos, Angle, Size) Ent:SetPos(Pos) Ent:Spawn() - Ent:SetSize(Size) + Ent:SetSize(Size or VectorRand(3, 96)) Ent.Owner = Player diff --git a/lua/starfall/libs_sv/acffunctions.lua b/lua/starfall/libs_sv/acffunctions.lua index dca112428..debe2c7c4 100644 --- a/lua/starfall/libs_sv/acffunctions.lua +++ b/lua/starfall/libs_sv/acffunctions.lua @@ -174,7 +174,7 @@ function acf_library.createMobility(pos, ang, id, frozen, gear_ratio) local pos = vunwrap(pos) local ang = aunwrap(ang) - local list_entries = ACF.Weapons.Mobility + local list_entries = ACF.Weapons.Mobility -- REPLACE -- Not a valid id, try name if not list_entries[id] then @@ -236,7 +236,7 @@ end function acf_library.getMobilitySpecs(id) checkluatype(id, TYPE_STRING) - local list_entries = ACF.Weapons.Mobility + local list_entries = ACF.Weapons.Mobility -- REPLACE -- Not a valid id, try name if not list_entries[id] then @@ -324,7 +324,7 @@ function acf_library.createFuelTank(pos, ang, id, fueltype, frozen) if fueltype ~= "Diesel" and fueltype ~= "Electric" and fueltype ~= "Petrol" then SF.Throw("Invalid fuel type") end - local list_entries = ACF.Weapons.FuelTanks + local list_entries = ACF.Weapons.FuelTanks -- REPLACE if not list_entries[id] then SF.Throw("Invalid id", 2) end local type_id = list_entries[id] @@ -363,7 +363,7 @@ end function acf_library.getFuelTankSpecs(id) checkluatype(id, TYPE_STRING) - local list_entries = ACF.Weapons.FuelTanks + local list_entries = ACF.Weapons.FuelTanks -- REPLACE if not list_entries[id] then SF.Throw("Invalid id", 2) end local specs = table.Copy(list_entries[id]) @@ -407,7 +407,7 @@ function acf_library.createGun(pos, ang, id, frozen) local pos = vunwrap(pos) local ang = aunwrap(ang) - local list_entries = ACF.Weapons.Guns + local list_entries = ACF.Weapons.Guns -- REPLACE -- Not a valid id, try name if not list_entries[id] then @@ -455,7 +455,7 @@ end function acf_library.getGunSpecs(id) checkluatype(id, TYPE_STRING) - local list_entries = ACF.Weapons.Guns + local list_entries = ACF.Weapons.Guns -- REPLACE -- Not a valid id, try name if not list_entries[id] then @@ -494,7 +494,7 @@ for id, data in pairs(ACF.RoundTypes) do -- REPLACE name = data.name, desc = data.desc, model = data.model, - gun_blacklist = ACF.AmmoBlacklist[id], + gun_blacklist = ACF.AmmoBlacklist[id], -- REPLACE create_data = {} } end @@ -695,7 +695,7 @@ function acf_library.createAmmo(pos, ang, id, gun_id, ammo_id, frozen, ammo_data local size if type(id) == "string" then - local list_entries = ACF.Weapons.Ammo + local list_entries = ACF.Weapons.Ammo -- REPLACE local type_id = list_entries[id] if not type_id then SF.Throw("Invalid id", 2) end @@ -708,7 +708,7 @@ function acf_library.createAmmo(pos, ang, id, gun_id, ammo_id, frozen, ammo_data local ammo = ammo_properties[ammo_id] if not ammo then SF.Throw("Invalid ammo id", 2) end - local gun_list_entries = ACF.Weapons.Guns + local gun_list_entries = ACF.Weapons.Guns -- REPLACE if not gun_list_entries[gun_id] then gun_id = idFromName(gun_list_entries, gun_id) @@ -1978,7 +1978,7 @@ function ents_methods:acfCaliber () if not this.BulletData then return 0 end -- If not a a rack if not this.BulletData.Id then return 0 end - local GunData = ACF.Weapons.Guns[this.BulletData.Id] + local GunData = ACF.Weapons.Guns[this.BulletData.Id] -- REPLACE if not GunData then return 0 end @@ -2140,7 +2140,7 @@ function ents_methods:acfFinMul() if restrictInfo( this ) then return 0 end if not this.BulletData.Id then return 0 end - local GunData = ACF.Weapons.Guns[this.BulletData.Id] + local GunData = ACF.Weapons.Guns[this.BulletData.Id] -- REPLACE if not GunData then return 0 end if not GunData.round then return 0 end @@ -2160,7 +2160,7 @@ function ents_methods:acfMissileWeight() if restrictInfo( this ) then return 0 end if not this.BulletData.Id then return 0 end - local GunData = ACF.Weapons.Guns[this.BulletData.Id] + local GunData = ACF.Weapons.Guns[this.BulletData.Id] -- REPLACE if not GunData then return 0 end return ( GunData.weight or 0 ) @@ -2178,7 +2178,7 @@ function ents_methods:acfMissileLength() if restrictInfo( this ) then return 0 end if not this.BulletData.Id then return 0 end - local GunData = ACF.Weapons.Guns[this.BulletData.Id] + local GunData = ACF.Weapons.Guns[this.BulletData.Id] -- REPLACE if not GunData then return 0 end return ( GunData.length or 0 ) diff --git a/lua/weapons/acf_base/init.lua b/lua/weapons/acf_base/init.lua index acf3db620..10e149673 100644 --- a/lua/weapons/acf_base/init.lua +++ b/lua/weapons/acf_base/init.lua @@ -1,20 +1,31 @@ AddCSLuaFile("cl_init.lua") AddCSLuaFile("shared.lua") + include("shared.lua") + +local AmmoTypes = ACF.Classes.AmmoTypes + SWEP.AutoSwitchTo = false SWEP.AutoSwitchFrom = false function SWEP:Initialize() - self.Primary.BulletData = {} - self.ConvertData = ACF.RoundTypes[self.Primary.UserData["Type"]]["convert"] -- REPLACE - self.Primary.BulletData = self:ConvertData(self.Primary.UserData) --Put the results into the BulletData table - self.NetworkData = ACF.RoundTypes[self.Primary.UserData["Type"]]["network"] -- REPLACE - self:NetworkData(self.Primary.BulletData) + local UserData = self.Primary.UserData + local AmmoType = AmmoTypes[UserData.Type] + local BulletData + + if SERVER then + BulletData = AmmoType:ServerConvert(UserData) + + AmmoType:Network(self, BulletData) - if (SERVER) then self:SetWeaponHoldType("ar2") - --self.Owner:GiveAmmo( self.Primary.DefaultClip, self.Primary.Ammo ) + --self.Owner:GiveAmmo( self.Primary.DefaultClip, self.Primary.Ammo ) + else + BulletData = AmmoType:ClientConvert(UserData) end + + self.Primary.BulletData = BulletData + self.Primary.RoundData = AmmoType end function SWEP:Reload() @@ -46,19 +57,24 @@ function SWEP:CrateReload() ViewTr.start = self.Owner:GetShootPos() ViewTr.endpos = self.Owner:GetShootPos() + self.Owner:GetAimVector() * 128 ViewTr.filter = {self.Owner, self} + local ViewRes = util.TraceLine(ViewTr) --Trace to see if it will hit anything if SERVER then local AmmoEnt = ViewRes.Entity - if AmmoEnt and AmmoEnt:IsValid() and AmmoEnt.Ammo > 0 and AmmoEnt.RoundId == self.Primary.UserData["Id"] then + if IsValid(AmmoEnt) and AmmoEnt.Ammo > 0 and AmmoEnt.RoundId == self.Primary.UserData["Id"] then local CurAmmo = self.Owner:GetAmmoCount(self.Primary.Ammo) local Transfert = math.min(AmmoEnt.Ammo, self.Primary.DefaultClip - CurAmmo) + local AmmoType = AmmoTypes[AmmoEnt.AmmoType] + AmmoEnt.Ammo = AmmoEnt.Ammo - Transfert + self.Owner:GiveAmmo(Transfert, self.Primary.Ammo) self.Primary.BulletData = AmmoEnt.BulletData - self.NetworkData = ACF.RoundTypes[AmmoEnt.RoundType]["network"] -- REPLACE - self:NetworkData(self.Primary.BulletData) + self.Primary.RoundData = AmmoType + + AmmoType:Network(self, self.Primary.BulletData) return true end diff --git a/lua/weapons/acf_base/shared.lua b/lua/weapons/acf_base/shared.lua index ddd806cc9..308628291 100644 --- a/lua/weapons/acf_base/shared.lua +++ b/lua/weapons/acf_base/shared.lua @@ -77,8 +77,8 @@ function SWEP:PrimaryAttack() self.Primary.BulletData["Owner"] = self.Owner self.Primary.BulletData["Gun"] = self.Owner self.Primary.BulletData["Crate"] = self:EntIndex() - self.CreateShell = ACF.RoundTypes[self.Primary.BulletData["Type"]]["create"] -- REPLACE - self:CreateShell( self.Primary.BulletData ) + + self.Primary.RoundData:Create(self, self.Primary.BulletData) self:TakePrimaryAmmo(1) diff --git a/lua/weapons/gmod_tool/stools/acfmenu.lua b/lua/weapons/gmod_tool/stools/acfmenu.lua deleted file mode 100644 index 8b359c8ef..000000000 --- a/lua/weapons/gmod_tool/stools/acfmenu.lua +++ /dev/null @@ -1,232 +0,0 @@ - -local cat = ((ACF.CustomToolCategory and ACF.CustomToolCategory:GetBool()) and "ACF" or "Construction"); - -TOOL.Category = cat -TOOL.Name = "#Tool.acfmenu.listname" -TOOL.Command = nil -TOOL.ConfigName = "" - -TOOL.ClientConVar[ "type" ] = "gun" -TOOL.ClientConVar[ "id" ] = "12.7mmMG" - -TOOL.ClientConVar[ "data1" ] = "12.7mmMG" -TOOL.ClientConVar[ "data2" ] = "AP" -TOOL.ClientConVar[ "data3" ] = 0 -TOOL.ClientConVar[ "data4" ] = 0 -TOOL.ClientConVar[ "data5" ] = 0 -TOOL.ClientConVar[ "data6" ] = 0 -TOOL.ClientConVar[ "data7" ] = 0 -TOOL.ClientConVar[ "data8" ] = 0 -TOOL.ClientConVar[ "data9" ] = 0 -TOOL.ClientConVar[ "data10" ] = 0 -TOOL.ClientConVar[ "data11" ] = 24 -TOOL.ClientConVar[ "data12" ] = 24 -TOOL.ClientConVar[ "data13" ] = 24 - -cleanup.Register( "acfmenu" ) - -if CLIENT then - language.Add( "Tool.acfmenu.listname", "ACF Menu" ) - language.Add( "Tool.acfmenu.name", "Armored Combat Framework" ) - language.Add( "Tool.acfmenu.desc", "Spawn the Armored Combat Framework weapons and ammo" ) - language.Add( "Tool.acfmenu.0", "Left click to spawn the entity of your choice, Right click to link an entity to another (+Use to unlink)" ) - language.Add( "Tool.acfmenu.1", "Right click to link the selected sensor to a pod" ) - - language.Add( "SBoxLimit_acf_rack", "You've reached the ACF Launchers limit!" ) - language.Add( "SBoxLimit_acf_sensor", "You've reached the ACF Sensors limit!" ) - - local DrawBoxes = GetConVar("acf_drawboxes") - - function TOOL.BuildCPanel( CPanel ) - - local pnldef_ACFmenu = vgui.RegisterFile( "acf/client/sk_menu.lua" ) - - -- create - local DPanel = vgui.CreateFromTable( pnldef_ACFmenu ) - CPanel:AddPanel( DPanel ) - - end - - -- "Hitbox" colors - local Sensitive = Color(255, 0, 0, 50) - local NotSoSensitive = Color(255, 255, 0, 50) - - -- Ammo overlay colors - local Blue = Color(0, 127, 255, 65) - local Orange = Color(255, 127, 0, 65) - local Green = Color(0, 255, 0, 65) - local Red = Color(255,0,0,65) - - function TOOL:DrawHUD() - if not DrawBoxes:GetBool() then return end - - local Trace = LocalPlayer():GetEyeTrace() - local Distance = Trace.StartPos:DistToSqr(Trace.HitPos) - local Ent = Trace.Entity - - if not IsValid(Ent) then return end - if Distance > 65536 then return end - - cam.Start3D() - render.SetColorMaterial() - - if Ent.HitBoxes then -- Draw "hitboxes" - for _, Tab in pairs(Ent.HitBoxes) do - render.DrawWireframeBox(Ent:LocalToWorld(Tab.Pos), Ent:LocalToWorldAngles(Tab.Angle), Tab.Scale * -0.5, Tab.Scale * 0.5, Tab.Sensitive and Sensitive or NotSoSensitive) - end - end - - if not Ent.IsScalable then cam.End3D() return end - if not Ent.HasData then - if Ent.HasData == nil and Ent.RequestAmmoData then - Ent:RequestAmmoData() - end - - cam.End3D() - return - end - - local FinalAmmo = Ent.HasBoxedAmmo and math.floor(Ent.Ammo / Ent.MagSize) or Ent.Ammo - - if FinalAmmo > 0 and Ent.FitPerAxis then - local RoundsDisplay = 0 - local RoundAngle = Ent:LocalToWorldAngles(Ent.LocalAng) - local StartPos = ((Ent.FitPerAxis.x - 1) * (Ent.RoundSize.x + Ent.Spacing) * RoundAngle:Forward()) + - ((Ent.FitPerAxis.y - 1) * (Ent.RoundSize.y + Ent.Spacing) * RoundAngle:Right()) + - ((Ent.FitPerAxis.z - 1) * (Ent.RoundSize.z + Ent.Spacing) * RoundAngle:Up()) - - if not Ent.BulkDisplay then - for RX = 1, Ent.FitPerAxis.x do - for RY = 1, Ent.FitPerAxis.y do - for RZ = 1, Ent.FitPerAxis.z do - local LocalPos = ((RX - 1) * (Ent.RoundSize.x + Ent.Spacing) * -RoundAngle:Forward()) + - ((RY - 1) * (Ent.RoundSize.y + Ent.Spacing) * -RoundAngle:Right()) + - ((RZ - 1) * (Ent.RoundSize.Z + Ent.Spacing) * -RoundAngle:Up()) - - if RoundsDisplay < FinalAmmo then - local C = Ent.IsRound and Blue or Ent.HasBoxedAmmo and Green or Orange - - RoundsDisplay = RoundsDisplay + 1 - - render.DrawWireframeBox(Ent:LocalToWorld(Ent:OBBCenter()) + (StartPos / 2) + LocalPos, RoundAngle, -Ent.RoundSize / 2, Ent.RoundSize / 2, C) - end - - if RoundsDisplay == FinalAmmo then break end - end - end - end - else -- Basic bitch box that scales according to ammo, only for bulk display - local AmmoPerc = Ent.Ammo / Ent.Capacity - local SizeAdd = Vector(Ent.Spacing, Ent.Spacing, Ent.Spacing) * Ent.FitPerAxis - local BulkSize = (Ent.FitPerAxis * Ent.RoundSize * Vector(1, AmmoPerc, 1)) + SizeAdd - - render.DrawWireframeBox(Ent:LocalToWorld(Ent:OBBCenter()) + (RoundAngle:Right() * (Ent.FitPerAxis.y * Ent.RoundSize.y) * 0.5 * (1 - AmmoPerc)),RoundAngle,-BulkSize / 2, BulkSize / 2, Red) - end - end - - cam.End3D() - end -end - --- Spawn/update functions -function TOOL:LeftClick(Trace) - if CLIENT then return true end - if not IsValid(Trace.Entity) and not Trace.Entity:IsWorld() then return false end - - local Player = self:GetOwner() - local Type = self:GetClientInfo("type") - local Id = self:GetClientInfo("id") - local TypeId = ACF.Weapons[Type][Id] - - if not TypeId then return false end - - local DupeClass = duplicator.FindEntityClass(TypeId.ent) - - if not DupeClass then - print("Didn't find entity duplicator records") - return false - end - - local Class = TypeId.ent - local ArgList = list.Get("ACFCvars") - local ArgTable = { - Player, - Trace.HitPos + Trace.HitNormal * 96, - Trace.HitNormal:Angle():Up():Angle(), - } - - -- Reading the list packaged with the ent to see what client CVar it needs - for K, V in ipairs(ArgList[Class]) do - local Info = self:GetClientInfo(V) - - ArgTable[K + 3] = Info ~= "" and Info or false - end - - if Trace.Entity:GetClass() == Class and Trace.Entity.CanUpdate then - local Success, Message = Trace.Entity:Update(ArgTable) - - ACF_SendNotify(Player, Success, Message) - else - -- Using the Duplicator entity register to find the right factory function - local Ent = DupeClass.Func(unpack(ArgTable)) - - if not IsValid(Ent) then - ACF_SendNotify(Player, false, "Couldn't create entity.") - return false - end - - Ent:Activate() - Ent:DropToFloor() - - if CPPI then - Ent:CPPISetOwner(Player) - end - - local PhysObj = Ent:GetPhysicsObject() - - if IsValid(PhysObj) then - PhysObj:EnableMotion(false) - PhysObj:Sleep() - end - - undo.Create(Class) - undo.AddEntity(Ent) - undo.SetPlayer(Player) - undo.Finish() - end - - return true -end - --- Link/unlink functions -function TOOL:RightClick(Trace) - if not IsValid(Trace.Entity) then return false end - if CLIENT then return true end - - local Player = self:GetOwner() - local Entity = Trace.Entity - - if self:GetStage() == 0 and Entity.Link then - self.Master = Entity - self:SetStage(1) - - return true - elseif self:GetStage() == 1 then - local Success, Message - - if Player:KeyDown(IN_USE) or Player:KeyDown(IN_SPEED) then - Success, Message = self.Master:Unlink(Entity) - else - Success, Message = self.Master:Link(Entity) - end - - ACF_SendNotify(Player, Success, Message) - - self:SetStage(0) - self.Master = nil - - return true - end - - return false -end \ No newline at end of file From 6d590b65333c55a857fa9ab377103c8f8cd0685f Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Fri, 20 Nov 2020 02:33:17 -0300 Subject: [PATCH 153/279] Fixed crates getting no mass - Fixed crates getting getting no mass due to a division by 0. --- lua/entities/acf_ammo/init.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/entities/acf_ammo/init.lua b/lua/entities/acf_ammo/init.lua index 0ec2f1e33..2a6a476e9 100644 --- a/lua/entities/acf_ammo/init.lua +++ b/lua/entities/acf_ammo/init.lua @@ -776,7 +776,7 @@ end --------------------------------------------- do -- Mass Update ------------------------------- local function UpdateMass(Ent) - Ent.ACF.LegalMass = math.floor(Ent.EmptyMass + (Ent.AmmoMassMax * (Ent.Ammo / math.max(Ent.Capacity, 0)))) + Ent.ACF.LegalMass = math.floor(Ent.EmptyMass + (Ent.AmmoMassMax * (Ent.Ammo / math.max(Ent.Capacity, 1)))) local Phys = Ent:GetPhysicsObject() From 183a31fad8fa681b61a3eb043e4a43fdf464f6b7 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Fri, 20 Nov 2020 02:49:42 -0300 Subject: [PATCH 154/279] Updated new menu tool references - The new menu tool will be called acf_menu instead of acf_menu2. - Renamed guns folder to weapons. --- lua/acf/client/cl_spawn_menu.lua | 2 +- lua/acf/client/menu_items/components_menu.lua | 2 +- lua/acf/client/menu_items/engines_menu.lua | 2 +- lua/acf/client/menu_items/gearboxes_menu.lua | 2 +- lua/acf/client/menu_items/online_wiki.lua | 7 +++--- lua/acf/client/menu_items/sensors_menu.lua | 2 +- lua/acf/client/menu_items/weapons_menu.lua | 2 +- lua/acf/shared/tool_operations/acf_menu.lua | 22 +++++++++---------- .../shared/{guns => weapons}/autocannon.lua | 0 .../shared/{guns => weapons}/autoloader.lua | 0 lua/acf/shared/{guns => weapons}/cannon.lua | 0 .../{guns => weapons}/grenadelauncher.lua | 0 .../{guns => weapons}/heavymachinegun.lua | 0 lua/acf/shared/{guns => weapons}/howitzer.lua | 0 .../shared/{guns => weapons}/machinegun.lua | 0 lua/acf/shared/{guns => weapons}/mortar.lua | 0 .../{guns => weapons}/rotaryautocannon.lua | 0 lua/acf/shared/{guns => weapons}/semiauto.lua | 0 .../shared/{guns => weapons}/shortcannon.lua | 0 .../{guns => weapons}/smokelauncher.lua | 0 .../shared/{guns => weapons}/smoothbore.lua | 0 .../stools/{acf_menu2.lua => acf_menu.lua} | 4 ++-- 22 files changed, 23 insertions(+), 22 deletions(-) rename lua/acf/shared/{guns => weapons}/autocannon.lua (100%) rename lua/acf/shared/{guns => weapons}/autoloader.lua (100%) rename lua/acf/shared/{guns => weapons}/cannon.lua (100%) rename lua/acf/shared/{guns => weapons}/grenadelauncher.lua (100%) rename lua/acf/shared/{guns => weapons}/heavymachinegun.lua (100%) rename lua/acf/shared/{guns => weapons}/howitzer.lua (100%) rename lua/acf/shared/{guns => weapons}/machinegun.lua (100%) rename lua/acf/shared/{guns => weapons}/mortar.lua (100%) rename lua/acf/shared/{guns => weapons}/rotaryautocannon.lua (100%) rename lua/acf/shared/{guns => weapons}/semiauto.lua (100%) rename lua/acf/shared/{guns => weapons}/shortcannon.lua (100%) rename lua/acf/shared/{guns => weapons}/smokelauncher.lua (100%) rename lua/acf/shared/{guns => weapons}/smoothbore.lua (100%) rename lua/weapons/gmod_tool/stools/{acf_menu2.lua => acf_menu.lua} (90%) diff --git a/lua/acf/client/cl_spawn_menu.lua b/lua/acf/client/cl_spawn_menu.lua index 78f2273b1..9bee0e38e 100644 --- a/lua/acf/client/cl_spawn_menu.lua +++ b/lua/acf/client/cl_spawn_menu.lua @@ -203,7 +203,7 @@ do -- ACF Menu context panel Node.Parent.Selected = Node self.Selected = Node - ACF.SetToolMode("acf_menu2", "Main", "Idle") + ACF.SetToolMode("acf_menu", "Main", "Idle") ACF.WriteValue("Destiny") Menu:ClearTemporal() diff --git a/lua/acf/client/menu_items/components_menu.lua b/lua/acf/client/menu_items/components_menu.lua index 197aa2e8c..7b48f7446 100644 --- a/lua/acf/client/menu_items/components_menu.lua +++ b/lua/acf/client/menu_items/components_menu.lua @@ -5,7 +5,7 @@ local function CreateMenu(Menu) ACF.WriteValue("PrimaryClass", "N/A") ACF.WriteValue("SecondaryClass", "N/A") - ACF.SetToolMode("acf_menu2", "Main", "Spawner") + ACF.SetToolMode("acf_menu", "Main", "Spawner") if not next(Components) then Menu:AddTitle("No Components Registered") diff --git a/lua/acf/client/menu_items/engines_menu.lua b/lua/acf/client/menu_items/engines_menu.lua index 7d4b04b6d..90b167955 100644 --- a/lua/acf/client/menu_items/engines_menu.lua +++ b/lua/acf/client/menu_items/engines_menu.lua @@ -82,7 +82,7 @@ local function CreateMenu(Menu) ACF.WriteValue("PrimaryClass", "acf_engine") ACF.WriteValue("SecondaryClass", "acf_fueltank") - ACF.SetToolMode("acf_menu2", "Main", "Spawner") + ACF.SetToolMode("acf_menu", "Main", "Spawner") function EngineClass:OnSelect(Index, _, Data) if self.Selected == Data then return end diff --git a/lua/acf/client/menu_items/gearboxes_menu.lua b/lua/acf/client/menu_items/gearboxes_menu.lua index 91372c760..20463fcbe 100644 --- a/lua/acf/client/menu_items/gearboxes_menu.lua +++ b/lua/acf/client/menu_items/gearboxes_menu.lua @@ -15,7 +15,7 @@ local function CreateMenu(Menu) ACF.WriteValue("PrimaryClass", "acf_gearbox") ACF.WriteValue("SecondaryClass", "N/A") - ACF.SetToolMode("acf_menu2", "Main", "Spawner") + ACF.SetToolMode("acf_menu", "Main", "Spawner") function GearboxClass:OnSelect(Index, _, Data) if self.Selected == Data then return end diff --git a/lua/acf/client/menu_items/online_wiki.lua b/lua/acf/client/menu_items/online_wiki.lua index 5bece3133..1cecb67bc 100644 --- a/lua/acf/client/menu_items/online_wiki.lua +++ b/lua/acf/client/menu_items/online_wiki.lua @@ -1,7 +1,8 @@ local function CreateMenu(Menu) - Menu:AddTitle("A Reference Guide") - Menu:AddLabel("The new ACF wiki will have a greater focus on references about the addon's multiple mechanics.") - Menu:AddLabel("There's also gonna be more content aimed towards extension developers, allowing them to take advantage of all the features ACF has to offer.") + Menu:AddTitle("Online Wiki") + + Menu:AddLabel("The new ACF wiki will have a greater focus on providing content aimed towards the average builder.") + Menu:AddLabel("There's also gonna be a section where we'll document anything that could be useful for extension developers.") local Wiki = Menu:AddButton("Open the Wiki") diff --git a/lua/acf/client/menu_items/sensors_menu.lua b/lua/acf/client/menu_items/sensors_menu.lua index 1d646349b..028768a90 100644 --- a/lua/acf/client/menu_items/sensors_menu.lua +++ b/lua/acf/client/menu_items/sensors_menu.lua @@ -5,7 +5,7 @@ local function CreateMenu(Menu) ACF.WriteValue("PrimaryClass", "N/A") ACF.WriteValue("SecondaryClass", "N/A") - ACF.SetToolMode("acf_menu2", "Main", "Spawner") + ACF.SetToolMode("acf_menu", "Main", "Spawner") if not next(Sensors) then Menu:AddTitle("No Sensors Registered") diff --git a/lua/acf/client/menu_items/weapons_menu.lua b/lua/acf/client/menu_items/weapons_menu.lua index d5b249eaf..d8ec7bed4 100644 --- a/lua/acf/client/menu_items/weapons_menu.lua +++ b/lua/acf/client/menu_items/weapons_menu.lua @@ -21,7 +21,7 @@ local function CreateMenu(Menu) ACF.WriteValue("PrimaryClass", "acf_gun") ACF.WriteValue("SecondaryClass", "acf_ammo") - ACF.SetToolMode("acf_menu2", "Main", "Spawner") + ACF.SetToolMode("acf_menu", "Main", "Spawner") local function UpdateEntityData() local Class = ClassList.Selected diff --git a/lua/acf/shared/tool_operations/acf_menu.lua b/lua/acf/shared/tool_operations/acf_menu.lua index e3bb60dbf..54095c984 100644 --- a/lua/acf/shared/tool_operations/acf_menu.lua +++ b/lua/acf/shared/tool_operations/acf_menu.lua @@ -43,9 +43,9 @@ end local function CanTool(Player, Entity) if not IsValid(Entity) then return false end - if CPPI then return Entity:CPPICanTool(Player, "acf_menu2") end + if CPPI then return Entity:CPPICanTool(Player, "acf_menu") end - return hook.Run("CanTool", Player, { Hit = true, Entity = Entity }, "acf_menu2") + return hook.Run("CanTool", Player, { Hit = true, Entity = Entity }, "acf_menu") end do -- Spawner operation @@ -116,7 +116,7 @@ do -- Spawner operation return true end - ACF.RegisterOperation("acf_menu2", "Main", "Spawner", { + ACF.RegisterOperation("acf_menu", "Main", "Spawner", { OnLeftClick = function(Tool, Trace) if Trace.HitSky then return false end @@ -143,17 +143,17 @@ do -- Spawner operation end, }) - ACF.RegisterToolInfo("acf_menu2", "Main", "Spawner", { + ACF.RegisterToolInfo("acf_menu", "Main", "Spawner", { name = "left", text = "Spawn or update the selected primary entity.", }) - ACF.RegisterToolInfo("acf_menu2", "Main", "Spawner", { + ACF.RegisterToolInfo("acf_menu", "Main", "Spawner", { name = "right", text = "If valid, spawn or update the selected secondary entity.", }) - ACF.RegisterToolInfo("acf_menu2", "Main", "Spawner", { + ACF.RegisterToolInfo("acf_menu", "Main", "Spawner", { name = "right_shift", text = "(Hold Shift) Select the entity you want to link or unlink.", icon2 = "gui/info", @@ -197,7 +197,7 @@ do -- Linker operation end end - ACF.RegisterOperation("acf_menu2", "Main", "Linker", { + ACF.RegisterOperation("acf_menu", "Main", "Linker", { OnRightClick = function(Tool, Trace) local Player = Tool:GetOwner() local Entity = Trace.Entity @@ -232,24 +232,24 @@ do -- Linker operation end, }) - ACF.RegisterToolInfo("acf_menu2", "Main", "Linker", { + ACF.RegisterToolInfo("acf_menu", "Main", "Linker", { name = "right", text = "Link all the selected entities to an entity.", }) - ACF.RegisterToolInfo("acf_menu2", "Main", "Linker", { + ACF.RegisterToolInfo("acf_menu", "Main", "Linker", { name = "right_r", text = "Unlink all the selected entities from an entity.", icon2 = "gui/r.png", }) - ACF.RegisterToolInfo("acf_menu2", "Main", "Linker", { + ACF.RegisterToolInfo("acf_menu", "Main", "Linker", { name = "right_shift", text = "Select another entity to link.", icon2 = "gui/info", }) - ACF.RegisterToolInfo("acf_menu2", "Main", "Linker", { + ACF.RegisterToolInfo("acf_menu", "Main", "Linker", { name = "right_world", text = "(Hit the World) Unselected all selected entities.", icon2 = "gui/info", diff --git a/lua/acf/shared/guns/autocannon.lua b/lua/acf/shared/weapons/autocannon.lua similarity index 100% rename from lua/acf/shared/guns/autocannon.lua rename to lua/acf/shared/weapons/autocannon.lua diff --git a/lua/acf/shared/guns/autoloader.lua b/lua/acf/shared/weapons/autoloader.lua similarity index 100% rename from lua/acf/shared/guns/autoloader.lua rename to lua/acf/shared/weapons/autoloader.lua diff --git a/lua/acf/shared/guns/cannon.lua b/lua/acf/shared/weapons/cannon.lua similarity index 100% rename from lua/acf/shared/guns/cannon.lua rename to lua/acf/shared/weapons/cannon.lua diff --git a/lua/acf/shared/guns/grenadelauncher.lua b/lua/acf/shared/weapons/grenadelauncher.lua similarity index 100% rename from lua/acf/shared/guns/grenadelauncher.lua rename to lua/acf/shared/weapons/grenadelauncher.lua diff --git a/lua/acf/shared/guns/heavymachinegun.lua b/lua/acf/shared/weapons/heavymachinegun.lua similarity index 100% rename from lua/acf/shared/guns/heavymachinegun.lua rename to lua/acf/shared/weapons/heavymachinegun.lua diff --git a/lua/acf/shared/guns/howitzer.lua b/lua/acf/shared/weapons/howitzer.lua similarity index 100% rename from lua/acf/shared/guns/howitzer.lua rename to lua/acf/shared/weapons/howitzer.lua diff --git a/lua/acf/shared/guns/machinegun.lua b/lua/acf/shared/weapons/machinegun.lua similarity index 100% rename from lua/acf/shared/guns/machinegun.lua rename to lua/acf/shared/weapons/machinegun.lua diff --git a/lua/acf/shared/guns/mortar.lua b/lua/acf/shared/weapons/mortar.lua similarity index 100% rename from lua/acf/shared/guns/mortar.lua rename to lua/acf/shared/weapons/mortar.lua diff --git a/lua/acf/shared/guns/rotaryautocannon.lua b/lua/acf/shared/weapons/rotaryautocannon.lua similarity index 100% rename from lua/acf/shared/guns/rotaryautocannon.lua rename to lua/acf/shared/weapons/rotaryautocannon.lua diff --git a/lua/acf/shared/guns/semiauto.lua b/lua/acf/shared/weapons/semiauto.lua similarity index 100% rename from lua/acf/shared/guns/semiauto.lua rename to lua/acf/shared/weapons/semiauto.lua diff --git a/lua/acf/shared/guns/shortcannon.lua b/lua/acf/shared/weapons/shortcannon.lua similarity index 100% rename from lua/acf/shared/guns/shortcannon.lua rename to lua/acf/shared/weapons/shortcannon.lua diff --git a/lua/acf/shared/guns/smokelauncher.lua b/lua/acf/shared/weapons/smokelauncher.lua similarity index 100% rename from lua/acf/shared/guns/smokelauncher.lua rename to lua/acf/shared/weapons/smokelauncher.lua diff --git a/lua/acf/shared/guns/smoothbore.lua b/lua/acf/shared/weapons/smoothbore.lua similarity index 100% rename from lua/acf/shared/guns/smoothbore.lua rename to lua/acf/shared/weapons/smoothbore.lua diff --git a/lua/weapons/gmod_tool/stools/acf_menu2.lua b/lua/weapons/gmod_tool/stools/acf_menu.lua similarity index 90% rename from lua/weapons/gmod_tool/stools/acf_menu2.lua rename to lua/weapons/gmod_tool/stools/acf_menu.lua index 58506f295..6741fb237 100644 --- a/lua/weapons/gmod_tool/stools/acf_menu2.lua +++ b/lua/weapons/gmod_tool/stools/acf_menu.lua @@ -12,8 +12,8 @@ if CLIENT then local Sensitive = Color(255, 0, 0, 50) local NotSoSensitive = Color(255, 255, 0, 50) - language.Add("Tool.acf_menu2.name", "Armored Combat Framework") - language.Add("Tool.acf_menu2.desc", "Testing the new menu tool") + language.Add("Tool.acf_menu.name", "Armored Combat Framework") + language.Add("Tool.acf_menu.desc", "Main menu tool for the ACF addon") function TOOL:DrawHUD() local Trace = LocalPlayer():GetEyeTrace() From 0683ee627d613a914353aa291a44012254bb2fc6 Mon Sep 17 00:00:00 2001 From: Stoob Date: Fri, 20 Nov 2020 14:03:52 -0600 Subject: [PATCH 155/279] Fixed ricochets Fixed bullets applying new flight vector after a ricochet before stepping, causing them to veer off course before actually running into the object. --- lua/acf/server/ballistics.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lua/acf/server/ballistics.lua b/lua/acf/server/ballistics.lua index e680bb628..738646082 100644 --- a/lua/acf/server/ballistics.lua +++ b/lua/acf/server/ballistics.lua @@ -169,6 +169,7 @@ function ACF.CreateBullet(BulletData) Bullet.Mask = MASK_SOLID -- Note: MASK_SHOT removed for smaller projectiles as it ignores armor Bullet.Ricochets = 0 Bullet.GroundRicos = 0 + Bullet.Color = ColorRand(100, 255) if not next(Bullets) then hook.Add("Tick", "IterateBullets", IterateBullets) @@ -214,6 +215,7 @@ function ACF.DoBulletsFlight(Index, Bullet) local FlightRes, Filter = ACF.TraceF(FlightTr) -- Does not modify the bullet's original filter + debugoverlay.Line(Bullet.Pos, FlightRes.HitPos, 15, Bullet.Color) -- Something was hit, let's make sure we're not phasing through armor if Bullet.LastPos and IsValid(FlightRes.Entity) and not GlobalFilter[FlightRes.Entity:GetClass()] then BackTrace.start = Bullet.LastPos @@ -286,7 +288,6 @@ function ACF.DoBulletsFlight(Index, Bullet) end ACF.BulletClient(Index, Bullet, "Update", 3, FlightRes.HitPos) - ACF.CalcBulletFlight(Index, Bullet) else if Bullet.OnEndFlight then Bullet.OnEndFlight(Index, Bullet, FlightRes) @@ -313,7 +314,6 @@ function ACF.DoBulletsFlight(Index, Bullet) end ACF.BulletClient(Index, Bullet, "Update", 3, FlightRes.HitPos) - ACF.CalcBulletFlight(Index, Bullet) else if Bullet.OnEndFlight then Bullet.OnEndFlight(Index, Bullet, FlightRes) From 3f1ca1007673a0c0ae756b248c5cbc6748b092d5 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Fri, 20 Nov 2020 21:33:06 -0300 Subject: [PATCH 156/279] Readded missing engine - Re-added missing Tiny Electric Standalone Motor. --- lua/acf/shared/engines/electric.lua | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/lua/acf/shared/engines/electric.lua b/lua/acf/shared/engines/electric.lua index e5df57765..53c0b851c 100644 --- a/lua/acf/shared/engines/electric.lua +++ b/lua/acf/shared/engines/electric.lua @@ -74,6 +74,26 @@ do -- Electric Standalone Motors Description = "Electric motors provide huge amounts of torque, but are very heavy. Standalones also require external batteries.", }) + ACF.RegisterEngine("Electric-Tiny-NoBatt", "EL-S", { + Name = "Tiny Electric Standalone Motor", + Description = "A pint-size electric motor, for the lightest of light utility work. Can power electric razors, desk fans, or your hopes and dreams.", + Model = "models/engines/emotor-standalone-tiny.mdl", + Sound = "acf_base/engines/electric_small.wav", + Fuel = { Electric = true }, + Type = "Electric", + Mass = 50, + Torque = 40, + FlywheelMass = 0.025, + IsElectric = true, + RPM = { + Idle = 10, + PeakMin = 1, + PeakMax = 1, + Limit = 10000, + Override = 500, + }, + }) + ACF.RegisterEngine("Electric-Small-NoBatt", "EL-S", { Name = "Small Electric Standalone Motor", Description = "A small standalone electric motor, loads of torque, but low power.", From 19ffec2caadaaced3f071fa225b3cdbd735b256e Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sat, 21 Nov 2020 14:42:17 -0300 Subject: [PATCH 157/279] Fixed weapon and ammo fuzes - Fixed weapons not getting their Fuze input. - Fixed ammo types not being able to be fuzed. - Readded delay to clientside updating. - ACF guns will now use ACF_OnSetupInputs and ACF_OnSetupOutputs hooks. - APHE ammo can now be fuzed. - Cannons and Short Cannons can now fire Smoke rounds. --- lua/acf/base/acf_globals.lua | 10 +++--- lua/acf/shared/ammo_types/aphe.lua | 1 + lua/acf/shared/ammo_types/smoke.lua | 2 -- lua/entities/acf_gearbox/init.lua | 4 +-- lua/entities/acf_gun/init.lua | 55 ++++++++++++++++++++++++----- 5 files changed, 55 insertions(+), 17 deletions(-) diff --git a/lua/acf/base/acf_globals.lua b/lua/acf/base/acf_globals.lua index 5cde2a62b..6ec33febb 100644 --- a/lua/acf/base/acf_globals.lua +++ b/lua/acf/base/acf_globals.lua @@ -13,7 +13,7 @@ do -- ACF global vars ACF.EnableKillicons = true -- Enable killicons overwriting. -- Fuzes - ACF.MinFuzeCaliber = 20 -- Minimum caliber in millimeters that can be fuzed + ACF.MinFuzeCaliber = 2 -- Minimum caliber in centimeters that can be fuzed -- Reload Mechanics ACF.BaseReload = 1 -- Minimum reload time. Time it takes to move around a weightless projectile @@ -214,10 +214,12 @@ elseif CLIENT then net.Receive("ACF_UpdateEntity", function() local Entity = net.ReadEntity() - if not IsValid(Entity) then return end - if not isfunction(Entity.Update) then return end + timer.Simple(0.5, function() + if not IsValid(Entity) then return end + if not isfunction(Entity.Update) then return end - Entity:Update() + Entity:Update() + end) end) --------------------------------------------- end diff --git a/lua/acf/shared/ammo_types/aphe.lua b/lua/acf/shared/ammo_types/aphe.lua index 9c0d7096e..a123c1fdf 100644 --- a/lua/acf/shared/ammo_types/aphe.lua +++ b/lua/acf/shared/ammo_types/aphe.lua @@ -66,6 +66,7 @@ function Ammo:BaseConvert(ToolData) Data.LimitVel = 700 --Most efficient penetration speed in m/s Data.KETransfert = 0.1 --Kinetic energy transfert to the target for movement purposes Data.Ricochet = 65 --Base ricochet angle + Data.CanFuze = Data.Caliber > ACF.MinFuzeCaliber -- Can fuze on calibers > 20mm self:UpdateRoundData(ToolData, Data, GUIData) diff --git a/lua/acf/shared/ammo_types/smoke.lua b/lua/acf/shared/ammo_types/smoke.lua index dbd69762b..21d2e342f 100644 --- a/lua/acf/shared/ammo_types/smoke.lua +++ b/lua/acf/shared/ammo_types/smoke.lua @@ -4,13 +4,11 @@ function Ammo:OnLoaded() self.Name = "Smoke" self.Description = "A shell filled white phosporous, detonating on impact. Smoke filler produces a long lasting cloud but takes a while to be effective, whereas WP filler quickly creates a cloud that also dissipates quickly." self.Blacklist = { - C = true, AC = true, AL = true, GL = true, MG = true, SA = true, - SC = true, HMG = true, RAC = true, } diff --git a/lua/entities/acf_gearbox/init.lua b/lua/entities/acf_gearbox/init.lua index c47e75c09..4375855b6 100644 --- a/lua/entities/acf_gearbox/init.lua +++ b/lua/entities/acf_gearbox/init.lua @@ -352,8 +352,6 @@ do -- Spawn and Update functions CreateInputs(Entity, Data, Class, Gearbox) CreateOutputs(Entity, Data, Class, Gearbox) - WireLib.TriggerOutput(Entity, "Entity", Entity) - Entity:SetNWString("WireName", "ACF " .. Entity.Name) ACF_Activate(Entity, true) @@ -452,6 +450,8 @@ do -- Spawn and Update functions UpdateGearbox(Gearbox, Data, Class, GearboxData) + WireLib.TriggerOutput(Gearbox, "Entity", Gearbox) + if Class.OnSpawn then Class.OnSpawn(Gearbox, Data, Class, GearboxData) end diff --git a/lua/entities/acf_gun/init.lua b/lua/entities/acf_gun/init.lua index 7e861a441..8800caa12 100644 --- a/lua/entities/acf_gun/init.lua +++ b/lua/entities/acf_gun/init.lua @@ -63,6 +63,38 @@ do -- Spawn and Update functions -------------------------------- end end + local function CreateInputs(Entity, Data, Class, Weapon) + local List = { "Fire", "Unload", "Reload" } + + if Class.SetupInputs then + Class.SetupInputs(List, Entity, Data, Class, Weapon) + end + + HookRun("ACF_OnSetupInputs", "acf_gun", List, Entity, Data, Class, Weapon) + + if Entity.Inputs then + Entity.Inputs = WireLib.AdjustInputs(Entity, List) + else + Entity.Inputs = WireLib.CreateInputs(Entity, List) + end + end + + local function CreateOutputs(Entity, Data, Class, Weapon) + local List = { "Ready", "Status [STRING]", "Total Ammo", "Entity [ENTITY]", "Shots Left", "Rate of Fire", "Reload Time", "Projectile Mass", "Muzzle Velocity" } + + if Class.SetupOutputs then + Class.SetupOutputs(List, Entity, Data, Class, Weapon) + end + + HookRun("ACF_OnSetupOutputs", "acf_gun", List, Entity, Data, Class, Weapon) + + if Entity.Outputs then + Entity.Outputs = WireLib.AdjustOutputs(Entity, List) + else + Entity.Outputs = WireLib.CreateOutputs(Entity, List) + end + end + local function UpdateWeapon(Entity, Data, Class, Weapon) local Caliber = Weapon.Caliber * 0.1 @@ -71,12 +103,6 @@ do -- Spawn and Update functions -------------------------------- Entity:PhysicsInit(SOLID_VPHYSICS) Entity:SetMoveType(MOVETYPE_VPHYSICS) - if Caliber > ACF.MinFuzeCaliber then - Entity.Inputs = WireLib.CreateInputs(Entity, { "Fire", "Unload", "Reload", "Fuze" }) - else - Entity.Inputs = WireLib.CreateInputs(Entity, { "Fire", "Unload", "Reload" }) - end - -- Storing all the relevant information on the entity for duping for _, V in ipairs(Entity.DataStore) do Entity[V] = Data[V] @@ -100,6 +126,9 @@ do -- Spawn and Update functions -------------------------------- Entity.NormalMuzzle = Entity:WorldToLocal(Entity:GetAttachment(Entity:LookupAttachment("muzzle")).Pos) Entity.Muzzle = Entity.NormalMuzzle + CreateInputs(Entity, Data, Class, Weapon) + CreateOutputs(Entity, Data, Class, Weapon) + -- Set NWvars Entity:SetNWString("WireName", "ACF " .. Weapon.Name) Entity:SetNWString("Class", Entity.Class) @@ -126,6 +155,15 @@ do -- Spawn and Update functions -------------------------------- if IsValid(Phys) then Phys:SetMass(Weapon.Mass) end end + hook.Add("ACF_OnSetupInputs", "ACF Weapon Fuze", function(Class, List, Entity) + if Class ~= "acf_gun" then return end + if Entity.Caliber <= ACF.MinFuzeCaliber then return end + + List[#List + 1] = "Fuze" + end) + + ------------------------------------------------------------------------------- + function MakeACF_Weapon(Player, Pos, Angle, Data) VerifyData(Data) @@ -148,7 +186,6 @@ do -- Spawn and Update functions -------------------------------- Gun:Spawn() Gun.Owner = Player -- MUST be stored on ent for PP - Gun.Outputs = WireLib.CreateOutputs(Gun, { "Ready", "Status [STRING]", "Total Ammo", "Entity [ENTITY]", "Shots Left", "Rate of Fire", "Reload Time", "Projectile Mass", "Muzzle Velocity" }) Gun.SoundPath = Class.Sound Gun.DefaultSound = Class.Sound Gun.BarrelFilter = { Gun } @@ -160,13 +197,13 @@ do -- Spawn and Update functions -------------------------------- Gun:SetNWString("Sound", Class.Sound) + UpdateWeapon(Gun, Data, Class, Weapon) + WireLib.TriggerOutput(Gun, "Status", "Empty") WireLib.TriggerOutput(Gun, "Entity", Gun) WireLib.TriggerOutput(Gun, "Projectile Mass", 1000) WireLib.TriggerOutput(Gun, "Muzzle Velocity", 1000) - UpdateWeapon(Gun, Data, Class, Weapon) - if Class.OnSpawn then Class.OnSpawn(Gun, Data, Class, Weapon) end From 7f8bd4b8050ffc6cda04e9547a65939c30072963 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sat, 21 Nov 2020 14:46:28 -0300 Subject: [PATCH 158/279] Removed debug prints - Removed debug prints from tool data functions. --- lua/acf/base/util/cl_util.lua | 2 -- lua/acf/base/util/sv_util.lua | 4 +--- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/lua/acf/base/util/cl_util.lua b/lua/acf/base/util/cl_util.lua index 283f79cf7..9a2a44605 100644 --- a/lua/acf/base/util/cl_util.lua +++ b/lua/acf/base/util/cl_util.lua @@ -138,8 +138,6 @@ do -- Tool data functions net.WriteString(Key) net.WriteType(NewValue) net.SendToServer() - - print("Sent", LocalPlayer(), Key, NewValue, type(NewValue)) end) end end diff --git a/lua/acf/base/util/sv_util.lua b/lua/acf/base/util/sv_util.lua index e8bb2cc6b..8f54313c6 100644 --- a/lua/acf/base/util/sv_util.lua +++ b/lua/acf/base/util/sv_util.lua @@ -68,12 +68,10 @@ do -- Tool data functions net.Receive("ACF_ToolData", function(_, Player) if not IsValid(Player) then return end - local Key = net.ReadString() + local Key = net.ReadString() local Value = net.ReadType() ToolData[Player][Key] = Value - - print("Received", Player, Key, Value, type(Value)) end) hook.Add("PlayerInitialSpawn", "ACF Tool Data", function(Player) From d00828755fe4c98297f2a0cdcf0e0a356b74039b Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sat, 21 Nov 2020 19:16:49 -0300 Subject: [PATCH 159/279] Patched impact angle out of bounds - Patched impact angle out of the [-90, 90] bounds. The fix is not optimal, but it does the job for the moment. --- lua/acf/server/damage.lua | 72 +++++++----------------------- lua/acf/shared/ammo_types/heat.lua | 2 +- 2 files changed, 17 insertions(+), 57 deletions(-) diff --git a/lua/acf/server/damage.lua b/lua/acf/server/damage.lua index e5e0b90ab..0c3d50f12 100644 --- a/lua/acf/server/damage.lua +++ b/lua/acf/server/damage.lua @@ -1,21 +1,23 @@ -- Local Vars ----------------------------------- -local ACF_HEPUSH = GetConVar("acf_hepush") -local ACF_KEPUSH = GetConVar("acf_kepush") -local TimerCreate = timer.Create -local TraceRes = {} -local TraceData = { output = TraceRes, mask = MASK_SOLID, filter = false } -local Check = ACF_Check -local HookRun = hook.Run -local Trace = ACF.TraceF -local ValidDebris = ACF.ValidDebris -local ChildDebris = ACF.ChildDebris -local DragDiv = ACF.DragDiv -local GlobalFilter = ACF.GlobalFilter +local ACF = ACF +local ACF_HEPUSH = GetConVar("acf_hepush") +local ACF_KEPUSH = GetConVar("acf_kepush") +local TimerCreate = timer.Create +local TraceRes = {} +local TraceData = { output = TraceRes, mask = MASK_SOLID, filter = false } +local Check = ACF_Check +local HookRun = hook.Run +local Trace = ACF.TraceF +local ValidDebris = ACF.ValidDebris +local ChildDebris = ACF.ChildDebris +local DragDiv = ACF.DragDiv + -- Local Funcs ---------------------------------- local function CalcDamage(Entity, Energy, FrArea, Angle) + local FinalAngle = math.Clamp(Angle, -90, 90) -- TODO: Why are we getting impact angles outside these bounds? local armor = Entity.ACF.Armour -- Armor - local losArmor = armor / math.abs(math.cos(math.rad(Angle)) ^ ACF.SlopeEffectFactor) -- LOS Armor + local losArmor = armor / math.abs(math.cos(math.rad(FinalAngle)) ^ ACF.SlopeEffectFactor) -- LOS Armor local maxPenetration = (Energy.Penetration / FrArea) * ACF.KEtoRHA --RHA Penetration local HitRes = {} @@ -39,7 +41,7 @@ local function CalcDamage(Entity, Energy, FrArea, Angle) local Penetration = math.min(maxPenetration, losArmor) HitRes.Damage = (Penetration / losArmor) ^ 2 * FrArea HitRes.Overkill = (maxPenetration - Penetration) - HitRes.Loss = Penetration / maxPenetration + HitRes.Loss = Penetration / math.max(0.001, maxPenetration) return HitRes end @@ -127,45 +129,6 @@ do end end - local function BackCheck( MaxD, Last) -- Return the last entity hit - Trace(TraceData) - - -- Hit an entity going backwards thats between the origin and the original hitpos (phased through) - if TraceRes.HitNonWorld and IsValid(TraceRes.Entity) and not GlobalFilter[TraceRes.Entity:GetClass()] and TraceRes.HitPos:DistToSqr(TraceData.start) < MaxD then - Last = TraceRes.Entity - - TraceData.filter[#TraceData.filter + 1] = Last - - BackCheck(MaxD, Last) - end - - return Last - end - - local function BackCheckInit() - - local OStart = TraceData.start - local OEnd = TraceData.endpos - local OEnt = TraceRes.Entity - local OFilter = {}; for K, V in pairs(TraceData.filter) do OFilter[K] = V end - - TraceData.start = TraceRes.HitPos - TraceData.endpos = TraceRes.HitPos + (OStart - TraceRes.HitPos):GetNormalized() * 1000 - - local R = BackCheck(TraceRes.HitPos:DistToSqr(OStart)) - - if IsValid(R) then - TraceRes.Entity = R - --print("THANK YOU GARRY VERY COOL", OEnt, TraceRes.Entity) - else - TraceRes.Entity = OEnt - end - - TraceData.start = OStart - TraceData.endpos = OEnd - TraceData.filter = OFilter - end - function ACF_HE(Origin, FillerMass, FragMass, Inflictor, Filter, Gun) debugoverlay.Cross(Origin, 15, 15, Color( 255, 255, 255 ), true) Filter = Filter or {} @@ -228,9 +191,6 @@ do Trace(TraceData) -- Outputs to TraceRes if TraceRes.HitNonWorld then - - BackCheckInit() - Ent = TraceRes.Entity if Check(Ent) then diff --git a/lua/acf/shared/ammo_types/heat.lua b/lua/acf/shared/ammo_types/heat.lua index d0691d223..b0b72c749 100644 --- a/lua/acf/shared/ammo_types/heat.lua +++ b/lua/acf/shared/ammo_types/heat.lua @@ -184,7 +184,7 @@ if SERVER then function Ammo:Detonate(Bullet, HitPos) local Crushed, HEATFillerMass, BoomFillerMass = self:CrushCalc(Bullet.Flight:Length() * 0.0254, Bullet.FillerMass) - ACF_HE(HitPos, BoomFillerMass, Bullet.CasingMass + Bullet.SlugMass * Crushed, Bullet.Owner, nil, Bullet.Gun) + ACF_HE(HitPos, BoomFillerMass, Bullet.CasingMass + Bullet.SlugMass * Crushed, Bullet.Owner, Bullet.Filter, Bullet.Gun) if Crushed == 1 then return false end -- no HEAT jet to fire off, it was all converted to HE From ac7b08bb806dd8bc1e0e5080645419c0c2a8b56b Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Mon, 23 Nov 2020 01:28:48 -0300 Subject: [PATCH 160/279] Fixed HEAT jets "bouncing back" - Fixed HEAT jets bouncing back when the round first detonates. - Removed unused Bullet.InitTime from HEAT based munitions. --- lua/acf/server/ballistics.lua | 8 ++++---- lua/acf/shared/ammo_types/heat.lua | 5 ++--- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/lua/acf/server/ballistics.lua b/lua/acf/server/ballistics.lua index 738646082..a68ddfe29 100644 --- a/lua/acf/server/ballistics.lua +++ b/lua/acf/server/ballistics.lua @@ -108,11 +108,11 @@ function ACF.CalcBulletFlight(Index, Bullet) end local DeltaTime = ACF.CurTime - Bullet.LastThink - local Drag = Bullet.Flight:GetNormalized() * (Bullet.DragCoef * Bullet.Flight:LengthSqr()) / ACF.DragDiv - local Accel = Bullet.Accel or Gravity + local Drag = Bullet.Flight:GetNormalized() * (Bullet.DragCoef * Bullet.Flight:LengthSqr()) / ACF.DragDiv + local Accel = Bullet.Accel or Gravity - Bullet.Flight = Bullet.Flight + (Accel - Drag) * DeltaTime - Bullet.NextPos = Bullet.Pos + (Bullet.Flight * ACF.Scale * DeltaTime) + Bullet.NextPos = Bullet.Pos + (Bullet.Flight * ACF.Scale * DeltaTime) + Bullet.Flight = Bullet.Flight + (Accel - Drag) * DeltaTime Bullet.LastThink = ACF.CurTime Bullet.DeltaTime = DeltaTime diff --git a/lua/acf/shared/ammo_types/heat.lua b/lua/acf/shared/ammo_types/heat.lua index b0b72c749..7c325f517 100644 --- a/lua/acf/shared/ammo_types/heat.lua +++ b/lua/acf/shared/ammo_types/heat.lua @@ -189,7 +189,6 @@ if SERVER then if Crushed == 1 then return false end -- no HEAT jet to fire off, it was all converted to HE Bullet.Detonated = true - Bullet.InitTime = ACF.CurTime Bullet.Flight = Bullet.Flight:GetNormalized() * self:CalcSlugMV(Bullet, HEATFillerMass) * 39.37 Bullet.NextPos = HitPos Bullet.DragCoef = Bullet.SlugDragCoef @@ -227,7 +226,7 @@ if SERVER then if HitRes.Ricochet then return "Ricochet" else - if self:Detonate(Bullet, HitPos, HitNormal) then + if self:Detonate(Bullet, HitPos) then return "Penetrated" else return false @@ -245,7 +244,7 @@ if SERVER then function Ammo:WorldImpact(_, Bullet, HitPos, HitNormal) if not Bullet.Detonated then - if self:Detonate(Bullet, HitPos, HitNormal) then + if self:Detonate(Bullet, HitPos) then return "Penetrated" else return false From 464f2be0176a2cc397c7b89b9113d13172c79906 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Mon, 23 Nov 2020 01:47:10 -0300 Subject: [PATCH 161/279] Fixed HEATFS penetration - Fixed HEATFS rounds getting insane penetration values. --- lua/acf/shared/ammo_types/heatfs.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lua/acf/shared/ammo_types/heatfs.lua b/lua/acf/shared/ammo_types/heatfs.lua index 711a9a18d..26aefd16d 100644 --- a/lua/acf/shared/ammo_types/heatfs.lua +++ b/lua/acf/shared/ammo_types/heatfs.lua @@ -17,7 +17,7 @@ function Ammo:UpdateRoundData(ToolData, Data, GUIData) local MaxConeAng = math.deg(math.atan((Data.ProjLength - Data.Caliber * 0.02) / (Data.Caliber * 0.5))) local LinerAngle = math.Clamp(ToolData.LinerAngle, GUIData.MinConeAng, MaxConeAng) - local _, ConeArea, AirVol = self:ConeCalc(LinerAngle, Data.Caliber * 0.05) + local _, ConeArea, AirVol = self:ConeCalc(LinerAngle, Data.Caliber * 0.5) local LinerRad = math.rad(LinerAngle * 0.5) local SlugCaliber = Data.Caliber - Data.Caliber * (math.sin(LinerRad) * 0.5 + math.cos(LinerRad) * 1.5) * 0.5 @@ -38,7 +38,7 @@ function Ammo:UpdateRoundData(ToolData, Data, GUIData) Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass) * 1.25 Data.SlugMass = ConeVol * 0.0079 Data.SlugCaliber = SlugCaliber - Data.SlugPenArea = (SlugFrArea ^ ACF.PenAreaMod) * 0.6666 + Data.SlugPenArea = (SlugFrArea ^ ACF.PenAreaMod) -- * 0.6666 Data.SlugDragCoef = SlugFrArea * 0.0001 / Data.SlugMass local _, HEATFiller, BoomFiller = self:CrushCalc(Data.MuzzleVel, Data.FillerMass) From b72688a5ddcd88a3294a7393f228721ab9286acc Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Mon, 23 Nov 2020 01:48:29 -0300 Subject: [PATCH 162/279] Removed comment from HEATFS ammo - Uncommented a quite important bit on HEATFS ammo. --- lua/acf/shared/ammo_types/heatfs.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/acf/shared/ammo_types/heatfs.lua b/lua/acf/shared/ammo_types/heatfs.lua index 26aefd16d..05651e4e7 100644 --- a/lua/acf/shared/ammo_types/heatfs.lua +++ b/lua/acf/shared/ammo_types/heatfs.lua @@ -38,7 +38,7 @@ function Ammo:UpdateRoundData(ToolData, Data, GUIData) Data.MuzzleVel = ACF_MuzzleVelocity(Data.PropMass, Data.ProjMass) * 1.25 Data.SlugMass = ConeVol * 0.0079 Data.SlugCaliber = SlugCaliber - Data.SlugPenArea = (SlugFrArea ^ ACF.PenAreaMod) -- * 0.6666 + Data.SlugPenArea = (SlugFrArea ^ ACF.PenAreaMod) * 0.6666 Data.SlugDragCoef = SlugFrArea * 0.0001 / Data.SlugMass local _, HEATFiller, BoomFiller = self:CrushCalc(Data.MuzzleVel, Data.FillerMass) From bdc5243727d82df490cbd7f5098ee213b9ab58c1 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Wed, 25 Nov 2020 00:36:51 -0300 Subject: [PATCH 163/279] Fixed crate caliber readout - Fixed crates storing their weapon's ammo caliber in millimeters instead of centimeters. --- lua/entities/acf_ammo/init.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/entities/acf_ammo/init.lua b/lua/entities/acf_ammo/init.lua index 2a6a476e9..df4aa7996 100644 --- a/lua/entities/acf_ammo/init.lua +++ b/lua/entities/acf_ammo/init.lua @@ -266,7 +266,7 @@ do -- Spawning and Updating -------------------- Entity.EntType = "Ammo Crate" Entity.ClassData = Class Entity.WeaponData = Weapon - Entity.Caliber = Weapon.Caliber + Entity.Caliber = Weapon.Caliber * 0.1 Entity.Class = Class.ID Entity:SetNWString("WireName", "ACF " .. (WireName or Weapon.Name .. " Ammo Crate")) From a8e97cb7b89691c50b3fa6e169270596498e70fa Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Thu, 26 Nov 2020 17:42:54 -0300 Subject: [PATCH 164/279] Fixed nil reference on FL ammo - Fixed error related to a nil reference when getting a weapon class spread on Flechette ammo. --- lua/acf/shared/ammo_types/fl.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/acf/shared/ammo_types/fl.lua b/lua/acf/shared/ammo_types/fl.lua index 895e7fe22..d15df3c79 100644 --- a/lua/acf/shared/ammo_types/fl.lua +++ b/lua/acf/shared/ammo_types/fl.lua @@ -172,7 +172,7 @@ if SERVER then local Data = self:GetDisplayData(BulletData) local Destiny = ACF.FindWeaponrySource(BulletData.Id) local Class = ACF.GetClassGroup(Destiny, BulletData.Id) - local Spread = Class.Spread * ACF.GunInaccuracyScale + local Spread = Class and Class.Spread * ACF.GunInaccuracyScale or 0 return Text:format(math.Round(BulletData.MuzzleVel, 2), math.Round(Data.MaxPen, 2), math.Round(BulletData.FlechetteSpread + Spread, 2)) end From da8cbe934ce49195bdd26824da97544805842e42 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Thu, 26 Nov 2020 18:56:23 -0300 Subject: [PATCH 165/279] Fixed weapons being able to link Refills - Fixed weapons being able to be linked to Refill crates while on mid reload. - Crates will be unlinked from all their guns if they happen to have the ENT.Unlinkable flag when updated. - Refill crates will now have a ENT.Unlinkable flag. - Ammo:Create on Refill ammo will now just print a message to console to prevent errors. --- lua/acf/shared/ammo_types/refill.lua | 10 +++++-- lua/entities/acf_ammo/init.lua | 41 ++++++++++++++-------------- 2 files changed, 29 insertions(+), 22 deletions(-) diff --git a/lua/acf/shared/ammo_types/refill.lua b/lua/acf/shared/ammo_types/refill.lua index 608b395c0..a18d217a3 100644 --- a/lua/acf/shared/ammo_types/refill.lua +++ b/lua/acf/shared/ammo_types/refill.lua @@ -112,7 +112,8 @@ if SERVER then Entity.SupplyingTo = {} end - Entity.IsRefill = true + Entity.IsRefill = true + Entity.Unlinkable = true timer.Create("ACF Refill " .. Entity:EntIndex(), 1, 0, function() if not IsValid(Entity) then return end @@ -131,7 +132,8 @@ if SERVER then end Entity.SupplyingTo = nil - Entity.IsRefill = nil + Entity.IsRefill = nil + Entity.Unlinkable = nil Entity:SetNW2Float("FillerMass", 0) @@ -140,6 +142,10 @@ if SERVER then timer.Remove(CallName) end + function Ammo:Create() + print("Someone is trying to fire Refill bullets") + end + function Ammo:Network(Entity, BulletData) Ammo.BaseClass.Network(self, Entity, BulletData) diff --git a/lua/entities/acf_ammo/init.lua b/lua/entities/acf_ammo/init.lua index df4aa7996..b31267879 100644 --- a/lua/entities/acf_ammo/init.lua +++ b/lua/entities/acf_ammo/init.lua @@ -471,13 +471,32 @@ do -- Spawning and Updating -------------------- local Source = Classes[Data.Destiny] local Class = GetClassGroup(Source, Data.Weapon) + local OldClass = self.ClassData local Weapon = Class.Lookup[Data.Weapon] + local OldWeapon = self.Weapon local Ammo = AmmoTypes[Data.AmmoType] local Blacklist = Ammo.Blacklist - local OldClass = self.ClassData local Extra = "" - if Data.Weapon ~= self.Weapon then + if OldClass.OnLast then + OldClass.OnLast(self, OldClass) + end + + HookRun("ACF_OnEntityLast", "acf_ammo", self, OldClass) + + ACF.SaveEntity(self) + + UpdateCrate(self, Data, Class, Weapon, Ammo) + + ACF.RestoreEntity(self) + + if Class.OnUpdate then + Class.OnUpdate(self, Data, Class, Weapon, Ammo) + end + + HookRun("ACF_OnEntityUpdate", "acf_ammo", self, Data, Class, Weapon, Ammo) + + if Data.Weapon ~= OldWeapon or self.Unlinkable then for Entity in pairs(self.Weapons) do self:Unlink(Entity) end @@ -502,24 +521,6 @@ do -- Spawning and Updating -------------------- end end - if OldClass.OnLast then - OldClass.OnLast(self, OldClass) - end - - HookRun("ACF_OnEntityLast", "acf_ammo", self, OldClass) - - ACF.SaveEntity(self) - - UpdateCrate(self, Data, Class, Weapon, Ammo) - - ACF.RestoreEntity(self) - - if Class.OnUpdate then - Class.OnUpdate(self, Data, Class, Weapon, Ammo) - end - - HookRun("ACF_OnEntityUpdate", "acf_ammo", self, Data, Class, Weapon, Ammo) - self:UpdateOverlay(true) net.Start("ACF_UpdateEntity") From d188186851ae135cb84ebbe25a17f6a2181216e2 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Thu, 26 Nov 2020 23:59:56 -0300 Subject: [PATCH 166/279] Fixed fuzed rounds going through armor - Fixed fuzed rounds going through armor due to flawed logic. --- lua/acf/server/ballistics.lua | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/lua/acf/server/ballistics.lua b/lua/acf/server/ballistics.lua index a68ddfe29..7c59448d4 100644 --- a/lua/acf/server/ballistics.lua +++ b/lua/acf/server/ballistics.lua @@ -248,22 +248,24 @@ function ACF.DoBulletsFlight(Index, Bullet) if not util.IsInWorld(Bullet.Pos) then -- Outside world, just delete return ACF.RemoveBullet(Index) else - if Bullet.OnEndFlight then - Bullet.OnEndFlight(Index, Bullet, nil) - end - local DeltaTime = Bullet.DeltaTime local DeltaFuze = ACF.CurTime - Bullet.Fuze local Lerp = DeltaFuze / DeltaTime - --print(DeltaTime, DeltaFuze, Lerp) - if FlightRes.Hit and Lerp < FlightRes.Fraction or true then -- Fuze went off before running into something + + if not FlightRes.Hit or Lerp < FlightRes.Fraction then -- Fuze went off before running into something local Pos = LerpVector(DeltaFuze / DeltaTime, Bullet.Pos, Bullet.NextPos) debugoverlay.Line(Bullet.Pos, Bullet.NextPos, 5, Color( 0, 255, 0 )) + if Bullet.OnEndFlight then + Bullet.OnEndFlight(Index, Bullet, FlightRes) + end + ACF.BulletClient(Index, Bullet, "Update", 1, Pos) RoundData:OnFlightEnd(Index, Bullet, Pos, Bullet.Flight:GetNormalized()) + + return end end end From 85f14a3d58bd56bfc46b5d9a0d8c85e02494150c Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sat, 28 Nov 2020 04:20:25 -0300 Subject: [PATCH 167/279] Fixed error on Torch SWEP - Fixed error on the Torch SWEP when attempting to emit a sound with the wrong argument types. - Removed unused NWVar on ammo networking. --- lua/acf/shared/ammo_types/ap.lua | 1 - lua/weapons/torch/shared.lua | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/lua/acf/shared/ammo_types/ap.lua b/lua/acf/shared/ammo_types/ap.lua index cf390355d..e4a20f237 100644 --- a/lua/acf/shared/ammo_types/ap.lua +++ b/lua/acf/shared/ammo_types/ap.lua @@ -105,7 +105,6 @@ if SERVER then function Ammo:Network(Entity, BulletData) Entity:SetNW2String("AmmoType", "AP") - Entity:SetNW2String("AmmoID", BulletData.Id) Entity:SetNW2Float("Caliber", BulletData.Caliber) Entity:SetNW2Float("ProjMass", BulletData.ProjMass) Entity:SetNW2Float("PropMass", BulletData.PropMass) diff --git a/lua/weapons/torch/shared.lua b/lua/weapons/torch/shared.lua index 1ae977611..12275e3d7 100644 --- a/lua/weapons/torch/shared.lua +++ b/lua/weapons/torch/shared.lua @@ -161,7 +161,7 @@ function SWEP:PrimaryAttack() Entity:ACF_OnRepaired(OldArmor, OldHealth, Armor, Health) end - Entity:EmitSound("ambient/energy/NewSpark0" .. math.random(3, 5) .. ".wav", true, true) + Entity:EmitSound("ambient/energy/NewSpark0" .. math.random(3, 5) .. ".wav") TeslaSpark(Trace.HitPos, 1) end end From 5fa29b747f0bd5f86cf869604d7aa7003553a92c Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sat, 28 Nov 2020 04:24:09 -0300 Subject: [PATCH 168/279] Fixed error when healing players - Fixed the same error when healing a player with the torch. --- lua/weapons/torch/shared.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/weapons/torch/shared.lua b/lua/weapons/torch/shared.lua index 12275e3d7..70fe447bd 100644 --- a/lua/weapons/torch/shared.lua +++ b/lua/weapons/torch/shared.lua @@ -139,7 +139,7 @@ function SWEP:PrimaryAttack() Effect:SetEntity(self) util.Effect("thruster_ring", Effect, true, true) - Entity:EmitSound("items/medshot4.wav", true, true) + Entity:EmitSound("items/medshot4.wav") else if CPPI and not Entity:CPPICanTool(Owner, "torch") then return end From 34a099bab5961ea39b7301ebf43e61cd5c7aae7f Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sat, 28 Nov 2020 23:46:13 -0300 Subject: [PATCH 169/279] Buffed refueling speed - Buffed refueling speed from about 0.4L/s to 20L/s. - Refuel speed will no longer be dependant on the ACF.RefillSpeed variable. Instead, it'll now use its own ACF.RefuelSpeed variable. - Fuel tanks will no longer refuel themselves. --- lua/acf/base/acf_globals.lua | 1 + lua/entities/acf_fueltank/init.lua | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/lua/acf/base/acf_globals.lua b/lua/acf/base/acf_globals.lua index 6ec33febb..af64efce3 100644 --- a/lua/acf/base/acf_globals.lua +++ b/lua/acf/base/acf_globals.lua @@ -94,6 +94,7 @@ do -- ACF global vars ACF.CuIToLiter = 0.0163871 -- cubic inches to liters ACF.RefillDistance = 300 --Distance in which ammo crate starts refilling. ACF.RefillSpeed = 700 -- (ACF.RefillSpeed / RoundMass) / Distance + ACF.RefuelSpeed = 20 -- Liters per second * ACF.FuelRate end do -- ACF Convars/Callbacks ------------------------ diff --git a/lua/entities/acf_fueltank/init.lua b/lua/entities/acf_fueltank/init.lua index 6612150d0..e69519b38 100644 --- a/lua/entities/acf_fueltank/init.lua +++ b/lua/entities/acf_fueltank/init.lua @@ -21,6 +21,7 @@ local HookRun = hook.Run local Wall = 0.03937 --wall thickness in inches (1mm) local function CanRefuel(Refill, Tank, Distance) + if Refill == Tank then return false end if Refill.FuelType ~= Tank.FuelType then return false end if Tank.Disabled then return false end if Tank.SupplyFuel then return false end @@ -513,7 +514,7 @@ function ENT:Think() for Tank in pairs(ACF.FuelTanks) do if CanRefuel(self, Tank, Position:DistToSqr(Tank:GetPos())) then - local Exchange = math.min(DeltaTime * ACF.RefillSpeed * ACF.FuelRate / 1750, self.Fuel, Tank.Capacity - Tank.Fuel) + local Exchange = math.min(DeltaTime * ACF.RefuelSpeed * ACF.FuelRate, self.Fuel, Tank.Capacity - Tank.Fuel) if HookRun("ACF_CanRefuel", self, Tank, Exchange) == false then continue end From a91f574dd09909d6aeff818810b5a40f56b533e6 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sun, 29 Nov 2020 00:03:58 -0300 Subject: [PATCH 170/279] Increased fuel tank limit + improved ammo crate limit convar - Increased the default fuel tank limit from 24 to 32. - The sbox_max_acf_ammo convar will now archive its value along with notifying the players on the server whenever it gets changed. --- lua/acf/base/acf_globals.lua | 3 ++- lua/acf/base/sh_classes.lua | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lua/acf/base/acf_globals.lua b/lua/acf/base/acf_globals.lua index af64efce3..bcf9bec82 100644 --- a/lua/acf/base/acf_globals.lua +++ b/lua/acf/base/acf_globals.lua @@ -98,6 +98,8 @@ do -- ACF global vars end do -- ACF Convars/Callbacks ------------------------ + CreateConVar("sbox_max_acf_ammo", 32, FCVAR_ARCHIVE + FCVAR_NOTIFY, "Maximum amount of ACF ammo crates a player can create.") + function ACF_CVarChangeCallback(CVar, _, New) if CVar == "acf_healthmod" then ACF.Threshold = 264.7 / math.max(New, 0.01) @@ -126,7 +128,6 @@ do -- ACF Convars/Callbacks ------------------------ end end - CreateConVar("sbox_max_acf_ammo", 32) -- New healthmod/armormod/ammomod cvars CreateConVar("acf_healthmod", 1) CreateConVar("acf_armormod", 1) diff --git a/lua/acf/base/sh_classes.lua b/lua/acf/base/sh_classes.lua index 50db1fd7a..ddc0370aa 100644 --- a/lua/acf/base/sh_classes.lua +++ b/lua/acf/base/sh_classes.lua @@ -309,7 +309,7 @@ do -- Fuel tank registration functions if not Group.LimitConVar then Group.LimitConVar = { Name = "_acf_fueltank", - Amount = 24, + Amount = 32, Text = "Maximum amount of ACF fuel tanks a player can create." } end From 47df67dc1e240cdfbd0885f5fad56aa05693a924 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sun, 29 Nov 2020 02:52:30 -0300 Subject: [PATCH 171/279] Fixed client-side hit-box for engines and gearboxes - Engines and gearboxes will now update their client-side hit-box after getting updated. --- lua/entities/acf_engine/cl_init.lua | 4 ++++ lua/entities/acf_gearbox/cl_init.lua | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/lua/entities/acf_engine/cl_init.lua b/lua/entities/acf_engine/cl_init.lua index 0e407ea96..019005685 100644 --- a/lua/entities/acf_engine/cl_init.lua +++ b/lua/entities/acf_engine/cl_init.lua @@ -6,6 +6,10 @@ language.Add("Undone_acf_engine", "Undone ACF Engine") language.Add("SBoxLimit__acf_engine", "You've reached the ACF Engines limit!") function ENT:Initialize() + self:Update() +end + +function ENT:Update() self.HitBoxes = ACF.HitBoxes[self:GetModel()] end diff --git a/lua/entities/acf_gearbox/cl_init.lua b/lua/entities/acf_gearbox/cl_init.lua index ced6f6e7e..14b8990bf 100644 --- a/lua/entities/acf_gearbox/cl_init.lua +++ b/lua/entities/acf_gearbox/cl_init.lua @@ -6,6 +6,10 @@ language.Add("Undone_acf_gearbox", "Undone ACF Gearbox") language.Add("SBoxLimit__acf_gearbox", "You've reached the ACF Gearboxes limit!") function ENT:Initialize() + self:Update() +end + +function ENT:Update() self.HitBoxes = ACF.HitBoxes[self:GetModel()] end From efb7098a90db5f4d6292d7cb6d856a08f7f7aead Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sun, 29 Nov 2020 21:42:38 -0300 Subject: [PATCH 172/279] Added ACF.CreateEntity function - Added shared ACF.CreateEntity function, especifically designed to create entities from classes that have been previously registered with ACF.RegisterEntityClass. - Updated the ACF Menu tool to use this function. --- lua/acf/base/sh_classes.lua | 45 +++++++++++++++++++++ lua/acf/shared/tool_operations/acf_menu.lua | 41 +------------------ 2 files changed, 46 insertions(+), 40 deletions(-) diff --git a/lua/acf/base/sh_classes.lua b/lua/acf/base/sh_classes.lua index ddc0370aa..38fa8b10c 100644 --- a/lua/acf/base/sh_classes.lua +++ b/lua/acf/base/sh_classes.lua @@ -505,6 +505,51 @@ do -- Entity class registration function return List end + + function ACF.CreateEntity(Class, Player, Position, Angles, Data, NoUndo) + if not isstring(Class) then return false end + + local ClassData = ACF.GetEntityClass(Class) + + if not ClassData then + SendMessage(Player, "Error", Class, " is not a registered ACF entity class.") + return false + end + + if not ClassData.Spawn then + SendMessage(Player, "Error", Class, " doesn't have a spawn function assigned to it.") + return false + end + + local Entity = ClassData.Spawn(Player, Position, Angles, Data) + local PhysObj = Entity:GetPhysicsObject() + + if not IsValid(Entity) then + SendMessage(Player, "Error", Class, " entity couldn't be created.") + return false + end + + Entity:Activate() + Entity:DropToFloor() + + if CPPI then + Entity:CPPISetOwner(Player) + end + + if IsValid(PhysObj) then + PhysObj:EnableMotion(false) + PhysObj:Sleep() + end + + if not NoUndo then + undo.Create(Entity.EntType or Class) + undo.AddEntity(Entity) + undo.SetPlayer(Player) + undo.Finish() + end + + return true, Entity + end end do -- Discontinued functions diff --git a/lua/acf/shared/tool_operations/acf_menu.lua b/lua/acf/shared/tool_operations/acf_menu.lua index 54095c984..dc7fbdacf 100644 --- a/lua/acf/shared/tool_operations/acf_menu.lua +++ b/lua/acf/shared/tool_operations/acf_menu.lua @@ -1,5 +1,4 @@ local GetToolData = ACF.GetToolData -local GetEntityClass = ACF.GetEntityClass local SendMessage = ACF.SendMessage local Entities = {} @@ -72,48 +71,10 @@ do -- Spawner operation -- Couldn't update the entity, aborting spawn if IsValid(Entity) then return false end - local Class = GetEntityClass(ClassName) - - if not Class then - SendMessage(Player, "Error", ClassName, " is not a registered ACF entity class.") - return false - end - - if not Class.Spawn then - SendMessage(Player, "Error", ClassName, " doesn't have a spawn function assigned to it.") - return false - end - local Position = Trace.HitPos + Trace.HitNormal * 128 local Angles = Trace.HitNormal:Angle():Up():Angle() - Entity = Class.Spawn(Player, Position, Angles, Data) - - if not IsValid(Entity) then - SendMessage(Player, "Error", ClassName, " entity couldn't be created.") - return false - end - - Entity:Activate() - Entity:DropToFloor() - - if CPPI then - Entity:CPPISetOwner(Player) - end - - undo.Create(ClassName) - undo.AddEntity(Entity) - undo.SetPlayer(Player) - undo.Finish() - - local PhysObj = Entity:GetPhysicsObject() - - if IsValid(PhysObj) then - PhysObj:EnableMotion(false) - PhysObj:Sleep() - end - - return true + return ACF.CreateEntity(ClassName, Player, Position, Angles, Data) end ACF.RegisterOperation("acf_menu", "Main", "Spawner", { From 93b7a7bd930b0a38a2bef78a0bad7f31a33d7ccc Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sun, 29 Nov 2020 23:15:37 -0300 Subject: [PATCH 173/279] Added extra scale information handlers - Scalable entities will now be able to send extra information whenever they're networked by overwriting ENT:GetExtraInfo on the serverside. - Whenever the scale of an entity is changed, it'll now be attempted to call ENT:UpdateExtraInfo. - The clientside scalable base will now be able to process the networked extra information by overwriting ENT:SetExtraInfo. --- lua/entities/base_scalable/cl_init.lua | 6 +++++- lua/entities/base_scalable/init.lua | 5 ++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/lua/entities/base_scalable/cl_init.lua b/lua/entities/base_scalable/cl_init.lua index 9f388572b..127c80abc 100644 --- a/lua/entities/base_scalable/cl_init.lua +++ b/lua/entities/base_scalable/cl_init.lua @@ -103,13 +103,17 @@ net.Receive("RequestSize", function() if Data.Size ~= Ent.Size or Data.Original ~= Ent.OriginalSize then Ent.OriginalSize = Data.Original Ent:SetSize(Data.Size) + + if Ent.SetExtraInfo then + Ent:SetExtraInfo(Data.Extra) + end end if Queued[Ent] then Queued[Ent] = nil end end end) --- Commented out for the moment, something's causing crashes +-- NOTE: Someone reported this could maybe be causing crashes. Please confirm. hook.Add("PhysgunPickup", "Scalable Ent Physgun", function(_, Ent) if Ent.IsScalable then return false end end) diff --git a/lua/entities/base_scalable/init.lua b/lua/entities/base_scalable/init.lua index 5e9069051..bf7e8e1a2 100644 --- a/lua/entities/base_scalable/init.lua +++ b/lua/entities/base_scalable/init.lua @@ -15,7 +15,8 @@ local function GenerateJSON(Table) Data[Entity:EntIndex()] = { Original = Entity:GetOriginalSize(), - Size = Entity:GetSize() + Size = Entity:GetSize(), + Extra = Entity.GetExtraInfo and Entity:GetExtraInfo(), } end @@ -85,6 +86,8 @@ local function ChangeSize(Entity, Size) hook.Run("OnEntityResized", Entity, PhysObj, Size, Scale) end + if Entity.UpdateExtraInfo then Entity:UpdateExtraInfo() end + return true, Size, Scale end From 07bd5351cc1152bfae625a963a56f31054d98016 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sun, 29 Nov 2020 23:31:17 -0300 Subject: [PATCH 174/279] Fixed invalid constraint type restoration - Fixed ACF.RestoreEntity throwing errors whenever an invalid constraint type was attempted to be restored. --- lua/acf/base/util/sv_util.lua | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lua/acf/base/util/sv_util.lua b/lua/acf/base/util/sv_util.lua index 8f54313c6..65c80cf40 100644 --- a/lua/acf/base/util/sv_util.lua +++ b/lua/acf/base/util/sv_util.lua @@ -165,7 +165,10 @@ do -- Entity saving and restoring PhysObj:SetMaterial(EntData.Material) for _, Data in ipairs(EntData.Constraints) do - local Constraint = Constraints[Data.Type] + local Constraint = Data.Type and Constraints[Data.Type] + + if not Constraint then continue end + local Args = {} for Index, Name in ipairs(Constraint.Args) do From 9cbe1a5f28cc2561beacdb6e167e01e5a97d97df Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Mon, 30 Nov 2020 01:17:27 -0300 Subject: [PATCH 175/279] Added ENT:FindOriginalSize to base_scalable - Added ENT:FindOriginalSize to the base_scalable entity. This function will be called every time ENT.OriginalSize couldn't be found on the serverside entity. It'll only receive the Sizes cache table as an argument in case you want to store the value. - Added a vital empty line, required for base_scalable_box to work properly. --- lua/entities/base_scalable/init.lua | 22 +++++++++++++--------- lua/entities/base_scalable_box/init.lua | 1 + 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/lua/entities/base_scalable/init.lua b/lua/entities/base_scalable/init.lua index bf7e8e1a2..dfe2dcab2 100644 --- a/lua/entities/base_scalable/init.lua +++ b/lua/entities/base_scalable/init.lua @@ -97,19 +97,23 @@ function ENT:Initialize() self:GetOriginalSize() -- Instantly saving the original size end -function ENT:GetOriginalSize() - if not self.OriginalSize then - local Size = Sizes[self:GetModel()] +function ENT:FindOriginalSize(SizeTable) + local Key = self:GetModel() + local Stored = SizeTable[Key] - if not Size then - local Min, Max = self:GetPhysicsObject():GetAABB() + if Stored then return Stored end - Size = -Min + Max + local Min, Max = self:GetPhysicsObject():GetAABB() + local Size = -Min + Max - Sizes[self:GetModel()] = Size - end + SizeTable[Key] = Size - self.OriginalSize = Size + return Size +end + +function ENT:GetOriginalSize() + if not self.OriginalSize then + self.OriginalSize = self:FindOriginalSize(Sizes) end return self.OriginalSize diff --git a/lua/entities/base_scalable_box/init.lua b/lua/entities/base_scalable_box/init.lua index f484ee24b..9f8a8d612 100644 --- a/lua/entities/base_scalable_box/init.lua +++ b/lua/entities/base_scalable_box/init.lua @@ -1,5 +1,6 @@ AddCSLuaFile("shared.lua") AddCSLuaFile("cl_init.lua") + include("shared.lua") function CreateScalableBox(Player, Pos, Angle, Size) From 6719fb67bf815da08ffb1d14fce82c3cd72ff1a1 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Mon, 30 Nov 2020 04:10:25 -0300 Subject: [PATCH 176/279] Added scalable multi-convex base entity - Added scalable multi-convex base entity. For the moment it'll only use models. - The scalable base will now process the extra scale data before applying the networked size. --- lua/entities/base_scalable/cl_init.lua | 6 +- .../base_scalable_mconvex/cl_init.lua | 34 +++++++ lua/entities/base_scalable_mconvex/init.lua | 88 +++++++++++++++++++ lua/entities/base_scalable_mconvex/shared.lua | 4 + 4 files changed, 129 insertions(+), 3 deletions(-) create mode 100644 lua/entities/base_scalable_mconvex/cl_init.lua create mode 100644 lua/entities/base_scalable_mconvex/init.lua create mode 100644 lua/entities/base_scalable_mconvex/shared.lua diff --git a/lua/entities/base_scalable/cl_init.lua b/lua/entities/base_scalable/cl_init.lua index 127c80abc..843b407c1 100644 --- a/lua/entities/base_scalable/cl_init.lua +++ b/lua/entities/base_scalable/cl_init.lua @@ -101,12 +101,12 @@ net.Receive("RequestSize", function() if not Ent.Initialized then continue end if Data.Size ~= Ent.Size or Data.Original ~= Ent.OriginalSize then - Ent.OriginalSize = Data.Original - Ent:SetSize(Data.Size) - if Ent.SetExtraInfo then Ent:SetExtraInfo(Data.Extra) end + + Ent.OriginalSize = Data.Original + Ent:SetSize(Data.Size) end if Queued[Ent] then Queued[Ent] = nil end diff --git a/lua/entities/base_scalable_mconvex/cl_init.lua b/lua/entities/base_scalable_mconvex/cl_init.lua new file mode 100644 index 000000000..4accb55dc --- /dev/null +++ b/lua/entities/base_scalable_mconvex/cl_init.lua @@ -0,0 +1,34 @@ +include("shared.lua") + +function ENT:SetExtraInfo(Extra) + self.Mesh = Extra.Mesh +end + +function ENT:ApplyNewSize(NewSize) + local Size = self:GetOriginalSize() + local Scale = Vector(1 / Size.x, 1 / Size.y, 1 / Size.z) * NewSize + local Mesh = self.Mesh + + self.Matrix = Matrix() + self.Matrix:Scale(Scale) + + self:EnableMatrix("RenderMultiply", self.Matrix) + + for I, Hull in ipairs(Mesh) do + for J, Vertex in ipairs(Hull) do + Mesh[I][J] = (Vertex.pos or Vertex) * Scale + end + end + + self:PhysicsInitMultiConvex(Mesh) + self:EnableCustomCollisions(true) + self:SetRenderBounds(self:GetCollisionBounds()) + self:DrawShadow(false) + + local PhysObj = self:GetPhysicsObject() + + if IsValid(PhysObj) then + PhysObj:EnableMotion(false) + PhysObj:Sleep() + end +end diff --git a/lua/entities/base_scalable_mconvex/init.lua b/lua/entities/base_scalable_mconvex/init.lua new file mode 100644 index 000000000..d1852b6b7 --- /dev/null +++ b/lua/entities/base_scalable_mconvex/init.lua @@ -0,0 +1,88 @@ +AddCSLuaFile("shared.lua") +AddCSLuaFile("cl_init.lua") + +include("shared.lua") + +-- TODO: Add support for creation via vertices table instead of model + +local Meshes = {} + +function CreateScalableMultiConvex(Player, Pos, Angle, Size) + local Ent = ents.Create("base_scalable_mconvex") + + if not IsValid(Ent) then return end + + Ent:SetModel("models/props_interiors/pot01a.mdl") + Ent:SetPlayer(Player) + Ent:SetAngles(Angle) + Ent:SetPos(Pos) + Ent:Spawn() + + Ent:SetSize(Size or VectorRand(3, 96)) + + Ent.Owner = Player + + return Ent +end + +duplicator.RegisterEntityClass("base_scalable_mconvex", CreateScalableMultiConvex, "Pos", "Angle", "Size") + +function ENT:FindOriginalSize(SizeTable) + local Key = self:GetModel() + local Stored = SizeTable[Key] + + if Stored then + self.Mesh = table.Copy(Meshes[Key]) + + return Stored + end + + local PhysObj = self:GetPhysicsObject() + + if not IsValid(PhysObj) then + self:PhysicsInit(SOLID_VPHYSICS) + + PhysObj = self:GetPhysicsObject() + end + + local Min, Max = PhysObj:GetAABB() + local Mesh = PhysObj:GetMeshConvexes() + local Size = -Min + Max + + self.Mesh = table.Copy(Mesh) + + SizeTable[Key] = Size + Meshes[Key] = Mesh + + return Size +end + +function ENT:ApplyNewSize(NewSize) + local Size = self:GetSize() or self:GetOriginalSize() + local Factor = Vector(1 / Size.x, 1 / Size.y, 1 / Size.z) * NewSize + local Mesh = self.Mesh + + for I, Hull in ipairs(Mesh) do + for J, Vertex in ipairs(Hull) do + Mesh[I][J] = (Vertex.pos or Vertex) * Factor + end + end + + self:PhysicsInitMultiConvex(Mesh) + self:SetMoveType(MOVETYPE_VPHYSICS) + self:SetSolid(SOLID_VPHYSICS) + self:EnableCustomCollisions(true) + self:DrawShadow(false) + + local PhysObj = self:GetPhysicsObject() + + if IsValid(PhysObj) then + PhysObj:EnableMotion(false) + end +end + +function ENT:GetExtraInfo() + return { + Mesh = Meshes[self:GetModel()] + } +end diff --git a/lua/entities/base_scalable_mconvex/shared.lua b/lua/entities/base_scalable_mconvex/shared.lua new file mode 100644 index 000000000..e83c37d82 --- /dev/null +++ b/lua/entities/base_scalable_mconvex/shared.lua @@ -0,0 +1,4 @@ +DEFINE_BASECLASS("base_scalable") + +ENT.PrintName = "Scalable Multi Convex" +ENT.WireDebugName = "Scalable Multi Convex" From 6eb863c989da18da8fad7350fe3529aae2fadf07 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Tue, 1 Dec 2020 05:22:08 -0300 Subject: [PATCH 177/279] Added custom attachment point functions - Added shared ACF.AddCustomAttachment function. It'll add an attachment to the specified model. - Added shared ACF.AddCustomAttachments function. It'll add a list of attachments to the specified model. - Added shared ACF.SetCustomAttachment function. It'll clear all old attachments and add one to the specified model. - Added shared ACF.SetCustomAttachments function. It'll clear all old attachments and add a list of them to the specified model. - Added shared ACF.RemoveCustomAttachment function. Clears the specified attachment index from the model. - Added shared ACF.RemoveCustomAttachments function. Clears every custom attachment from the model. - Every model used by weapons will now rely on these functions. - ACF.CheckNumber now has a second argument for a default value to return whenever the conversion wasn't possible. - Added ACF.CheckString function. Does exactly the same than ACF.CheckNumber but for strings. --- lua/acf/base/util/sh_util.lua | 203 +++++++++++++++++++- lua/acf/shared/weapons/autocannon.lua | 5 + lua/acf/shared/weapons/autoloader.lua | 5 + lua/acf/shared/weapons/cannon.lua | 9 +- lua/acf/shared/weapons/grenadelauncher.lua | 2 + lua/acf/shared/weapons/heavymachinegun.lua | 15 ++ lua/acf/shared/weapons/howitzer.lua | 6 + lua/acf/shared/weapons/machinegun.lua | 5 + lua/acf/shared/weapons/mortar.lua | 6 + lua/acf/shared/weapons/rotaryautocannon.lua | 6 +- lua/acf/shared/weapons/semiauto.lua | 6 + lua/acf/shared/weapons/shortcannon.lua | 7 + lua/acf/shared/weapons/smokelauncher.lua | 2 + lua/acf/shared/weapons/smoothbore.lua | 4 + 14 files changed, 276 insertions(+), 5 deletions(-) diff --git a/lua/acf/base/util/sh_util.lua b/lua/acf/base/util/sh_util.lua index c15f6894c..b56430dbf 100644 --- a/lua/acf/base/util/sh_util.lua +++ b/lua/acf/base/util/sh_util.lua @@ -354,8 +354,205 @@ do -- Sound aliases end end -function ACF.CheckNumber(Value) - if not Value then return end +do -- Native type verification functions + function ACF.CheckNumber(Value, Default) + if not Value then return Default end - return tonumber(Value) + return tonumber(Value) or Default + end + + function ACF.CheckString(Value) + if not Value then return Default end + + return tostring(Value) or Default + end +end + +do -- Attachment storage + local IsUseless = IsUselessModel + local EntTable = FindMetaTable("Entity") + local Models = {} + + local function GetModelData(Model, NoCreate) + local Table = Models[Model] + + if not (Table or NoCreate) then + Table = {} + + Models[Model] = Table + end + + return Table + end + + local function SaveAttachments(Model, Attachments, Clear) + if IsUseless(Model) then return end + + local Data = GetModelData(Model) + local Count = Clear and 0 or #Data + + if Clear then + for K in pairs(Data) do Data[K] = nil end + end + + for I, Attach in ipairs(Attachments) do + local Index = Count + I + local Name = ACF.CheckString(Attach.Name, "Unnamed" .. Index) + + Data[Index] = { + Index = Index, + Name = Name, + Pos = Attach.Pos or Vector(), + Ang = Attach.Ang or Angle(), + Bone = Attach.Bone, + } + end + + if not next(Data) then + Models[Model] = nil + end + end + + local function GetAttachData(Entity) + if not Entity.AttachData then + Entity.AttachData = GetModelData(Entity:GetModel(), true) + end + + return Entity.AttachData + end + + ------------------------------------------------------------------- + + function ACF.AddCustomAttachment(Model, Name, Pos, Ang, Bone) + if not ACF.CheckString(Model) then return end + + SaveAttachments(Model, {{ + Name = Name, + Pos = Pos, + Ang = Ang, + Bone = Bone, + }}) + end + + function ACF.AddCustomAttachments(Model, Attachments) + if not ACF.CheckString(Model) then return end + if not istable(Attachments) then return end + + SaveAttachments(Model, Attachments) + end + + function ACF.SetCustomAttachment(Model, Name, Pos, Ang, Bone) + if not ACF.CheckString(Model) then return end + + SaveAttachments(Model, {{ + Name = Name, + Pos = Pos, + Ang = Ang, + Bone = Bone, + }}, true) + end + + function ACF.SetCustomAttachments(Model, Attachments) + if not ACF.CheckString(Model) then return end + if not istable(Attachments) then return end + + SaveAttachments(Model, Attachments, true) + end + + function ACF.RemoveCustomAttachment(Model, Index) + if not ACF.CheckString(Model) then return end + + local Data = GetModelData(Model, true) + + if not Data then return end + + table.remove(Data, Index) + + if not next(Data) then + Models[Model] = nil + end + end + + function ACF.RemoveCustomAttachments(Model) + if not ACF.CheckString(Model) then return end + + local Data = GetModelData(Model, true) + + if not Data then return end + + for K in pairs(Data) do + Data[K] = nil + end + + Models[Model] = nil + end + + EntTable.LegacySetModel = EntTable.LegacySetModel or EntTable.SetModel + EntTable.LegacyGetAttachment = EntTable.LegacyGetAttachment or EntTable.GetAttachment + EntTable.LegacyGetAttachments = EntTable.LegacyGetAttachments or EntTable.GetAttachments + EntTable.LegacyLookupAttachment = EntTable.LegacyLookupAttachment or EntTable.LookupAttachment + + function EntTable:SetModel(Path, ...) + self:LegacySetModel(Path, ...) + + self.AttachData = GetModelData(Path, true) + end + + function EntTable:GetAttachment(Index, ...) + local Data = GetAttachData(self) + + if not Data then + return self:LegacyGetAttachment(Index, ...) + end + + local Attachment = Data[Index] + + if not Attachment then return end + + local Pos = Attachment.Pos + + if self.Scale then + Pos = Pos * self.Scale + end + + return { + Pos = self:LocalToWorld(Pos), + Ang = self:LocalToWorldAngles(Attachment.Ang), + } + end + + function EntTable:GetAttachments(...) + local Data = GetAttachData(self) + + if not Data then + return self:LegacyGetAttachments(...) + end + + local Result = {} + + for Index, Info in ipairs(Data) do + Result[Index] = { + id = Index, + name = Info.Name, + } + end + + return Result + end + + function EntTable:LookupAttachment(Name, ...) + local Data = GetAttachData(self) + + if not Data then + return self:LegacyLookupAttachment(Name, ...) + end + + for Index, Info in ipairs(Data) do + if Info.Name == Name then + return Index + end + end + + return 0 + end end diff --git a/lua/acf/shared/weapons/autocannon.lua b/lua/acf/shared/weapons/autocannon.lua index 4422b8e11..34d6c888f 100644 --- a/lua/acf/shared/weapons/autocannon.lua +++ b/lua/acf/shared/weapons/autocannon.lua @@ -73,3 +73,8 @@ ACF.RegisterWeapon("50mmAC", "AC", { PropMass = 1.2, } }) + +ACF.SetCustomAttachment("models/autocannon/autocannon_20mm.mdl", "muzzle", Vector(66), Angle(0, 0, 180)) +ACF.SetCustomAttachment("models/autocannon/autocannon_30mm.mdl", "muzzle", Vector(84), Angle(0, 0, 180)) +ACF.SetCustomAttachment("models/autocannon/autocannon_40mm.mdl", "muzzle", Vector(96), Angle(0, 0, 180)) +ACF.SetCustomAttachment("models/autocannon/autocannon_50mm.mdl", "muzzle", Vector(120), Angle(0, 0, 180)) diff --git a/lua/acf/shared/weapons/autoloader.lua b/lua/acf/shared/weapons/autoloader.lua index 3181411c2..e799e4f2d 100644 --- a/lua/acf/shared/weapons/autoloader.lua +++ b/lua/acf/shared/weapons/autoloader.lua @@ -73,3 +73,8 @@ ACF.RegisterWeapon("140mmAL", "AL", { PropMass = 28, } }) + +ACF.SetCustomAttachment("models/tankgun/tankgun_al_75mm.mdl", "muzzle", Vector(109.65), Angle(0, 0, 90)) +ACF.SetCustomAttachment("models/tankgun/tankgun_al_100mm.mdl", "muzzle", Vector(146.2), Angle(0, 0, 90)) +ACF.SetCustomAttachment("models/tankgun/tankgun_al_120mm.mdl", "muzzle", Vector(175.44), Angle(0, 0, 90)) +ACF.SetCustomAttachment("models/tankgun/tankgun_al_140mm.mdl", "muzzle", Vector(204.68), Angle(0, 0, 90)) diff --git a/lua/acf/shared/weapons/cannon.lua b/lua/acf/shared/weapons/cannon.lua index 4cb3e4aa7..59268269b 100644 --- a/lua/acf/shared/weapons/cannon.lua +++ b/lua/acf/shared/weapons/cannon.lua @@ -88,4 +88,11 @@ ACF.RegisterWeapon("140mmC", "C", { MaxLength = 127, PropMass = 28, } -}) \ No newline at end of file +}) + +ACF.SetCustomAttachment("models/tankgun/tankgun_37mm.mdl", "muzzle", Vector(55.77), Angle(0, 0, 90)) +ACF.SetCustomAttachment("models/tankgun/tankgun_50mm.mdl", "muzzle", Vector(75.36, -0.01, 0), Angle(0, 0, 90)) +ACF.SetCustomAttachment("models/tankgun/tankgun_75mm.mdl", "muzzle", Vector(113.04, -0.01, 0), Angle(0, 0, 90)) +ACF.SetCustomAttachment("models/tankgun/tankgun_100mm.mdl", "muzzle", Vector(150.72, -0.01, 0), Angle(0, 0, 90)) +ACF.SetCustomAttachment("models/tankgun/tankgun_120mm.mdl", "muzzle", Vector(180.85, -0.02, 0), Angle(0, 0, 90)) +ACF.SetCustomAttachment("models/tankgun/tankgun_140mm.mdl", "muzzle", Vector(210.99, -0.02, 0), Angle(0, 0, 90)) diff --git a/lua/acf/shared/weapons/grenadelauncher.lua b/lua/acf/shared/weapons/grenadelauncher.lua index 7e98d1ca0..e31487ba1 100644 --- a/lua/acf/shared/weapons/grenadelauncher.lua +++ b/lua/acf/shared/weapons/grenadelauncher.lua @@ -26,3 +26,5 @@ ACF.RegisterWeapon("40mmGL", "GL", { PropMass = 0.01, } }) + +ACF.SetCustomAttachment("models/launcher/40mmgl.mdl", "muzzle", Vector(19), Angle(0, 0, -180)) diff --git a/lua/acf/shared/weapons/heavymachinegun.lua b/lua/acf/shared/weapons/heavymachinegun.lua index ce7fa3646..2b205c5fa 100644 --- a/lua/acf/shared/weapons/heavymachinegun.lua +++ b/lua/acf/shared/weapons/heavymachinegun.lua @@ -78,3 +78,18 @@ ACF.RegisterWeapon("40mmHMG", "HMG", { PropMass = 0.9, } }) + +ACF.SetCustomAttachments("models/machinegun/machinegun_20mm_compact.mdl", { + { Name = "muzzle", Pos = Vector(30.93, -0.02, 0), Ang = Angle(0, 0, 90) }, + { Name = "muzzle2", Pos = Vector(69.93, -0.15, 0), Ang = Angle(0, 0, 90) }, +}) + +ACF.SetCustomAttachments("models/machinegun/machinegun_30mm_compact.mdl", { + { Name = "muzzle", Pos = Vector(41.76, -0.03, 0), Ang = Angle(0, 0, 90) }, + { Name = "muzzle2", Pos = Vector(94.41, -0.2, 0), Ang = Angle(0, 0, 90) }, +}) + +ACF.SetCustomAttachments("models/machinegun/machinegun_40mm_compact.mdl", { + { Name = "muzzle", Pos = Vector(51.04, -0.03, 0), Ang = Angle(0, 0, 90) }, + { Name = "muzzle2", Pos = Vector(115.39, -0.25, 0), Ang = Angle(0, 0, 90) }, +}) diff --git a/lua/acf/shared/weapons/howitzer.lua b/lua/acf/shared/weapons/howitzer.lua index 66332c841..cd02eeefb 100644 --- a/lua/acf/shared/weapons/howitzer.lua +++ b/lua/acf/shared/weapons/howitzer.lua @@ -74,3 +74,9 @@ ACF.RegisterWeapon("203mmHW", "HW", { PropMass = 28.5, } }) + +ACF.SetCustomAttachment("models/howitzer/howitzer_75mm.mdl", "muzzle", Vector(71.67, 0, -0.77)) +ACF.SetCustomAttachment("models/howitzer/howitzer_105mm.mdl", "muzzle", Vector(101.08, 0, -1.08)) +ACF.SetCustomAttachment("models/howitzer/howitzer_122mm.mdl", "muzzle", Vector(117.51, 0, -1.26)) +ACF.SetCustomAttachment("models/howitzer/howitzer_155mm.mdl", "muzzle", Vector(149.31, 0, -1.6)) +ACF.SetCustomAttachment("models/howitzer/howitzer_203mm.mdl", "muzzle", Vector(195.59, 0, -2.1)) diff --git a/lua/acf/shared/weapons/machinegun.lua b/lua/acf/shared/weapons/machinegun.lua index c584d1e1a..3497c75f1 100644 --- a/lua/acf/shared/weapons/machinegun.lua +++ b/lua/acf/shared/weapons/machinegun.lua @@ -74,3 +74,8 @@ ACF.RegisterWeapon("20mmMG", "MG", { PropMass = 0.09, } }) + +ACF.SetCustomAttachment("models/machinegun/machinegun_762mm.mdl", "muzzle", Vector(26.53, 0, -0.05), Angle(0, 0, 90)) +ACF.SetCustomAttachment("models/machinegun/machinegun_127mm.mdl", "muzzle", Vector(37.14, 0, -0.07), Angle(0, 0, 90)) +ACF.SetCustomAttachment("models/machinegun/machinegun_145mm.mdl", "muzzle", Vector(39.79, 0, -0.08), Angle(0, 0, 90)) +ACF.SetCustomAttachment("models/machinegun/machinegun_20mm.mdl", "muzzle", Vector(53.05, 0, -0.11), Angle(0, 0, 90)) diff --git a/lua/acf/shared/weapons/mortar.lua b/lua/acf/shared/weapons/mortar.lua index 742145daa..31247f238 100644 --- a/lua/acf/shared/weapons/mortar.lua +++ b/lua/acf/shared/weapons/mortar.lua @@ -74,3 +74,9 @@ ACF.RegisterWeapon("200mmM", "MO", { PropMass = 0.330, } }) + +ACF.SetCustomAttachment("models/mortar/mortar_60mm.mdl", "muzzle", Vector(12.01), Angle(0, 0, 90)) +ACF.SetCustomAttachment("models/mortar/mortar_80mm.mdl", "muzzle", Vector(16.02), Angle(0, 0, 90)) +ACF.SetCustomAttachment("models/mortar/mortar_120mm.mdl", "muzzle", Vector(24.02), Angle(0, 0, 90)) +ACF.SetCustomAttachment("models/mortar/mortar_150mm.mdl", "muzzle", Vector(30.03), Angle(0, 0, 90)) +ACF.SetCustomAttachment("models/mortar/mortar_200mm.mdl", "muzzle", Vector(40.04), Angle(0, 0, 90)) diff --git a/lua/acf/shared/weapons/rotaryautocannon.lua b/lua/acf/shared/weapons/rotaryautocannon.lua index d826a042d..209401a69 100644 --- a/lua/acf/shared/weapons/rotaryautocannon.lua +++ b/lua/acf/shared/weapons/rotaryautocannon.lua @@ -56,4 +56,8 @@ ACF.RegisterWeapon("30mmRAC", "RAC", { MaxLength = 40, PropMass = 0.350, } -}) \ No newline at end of file +}) + +ACF.SetCustomAttachment("models/rotarycannon/kw/14_5mmrac.mdl", "muzzle", Vector(43.21, 0, 1.26)) +ACF.SetCustomAttachment("models/rotarycannon/kw/20mmrac.mdl", "muzzle", Vector(59.6, 0, 1.74)) +ACF.SetCustomAttachment("models/rotarycannon/kw/30mmrac.mdl", "muzzle", Vector(89.4, 0, 2.61)) diff --git a/lua/acf/shared/weapons/semiauto.lua b/lua/acf/shared/weapons/semiauto.lua index 2b1e6a8ce..5211aa7e5 100644 --- a/lua/acf/shared/weapons/semiauto.lua +++ b/lua/acf/shared/weapons/semiauto.lua @@ -90,3 +90,9 @@ ACF.RegisterWeapon("76mmSA", "SA", { PropMass = 4.75, } }) + +ACF.SetCustomAttachment("models/autocannon/semiautocannon_25mm.mdl", "muzzle", Vector(44), Angle(0, 0, 180)) +ACF.SetCustomAttachment("models/autocannon/semiautocannon_37mm.mdl", "muzzle", Vector(65.12), Angle(0, 0, 180)) +ACF.SetCustomAttachment("models/autocannon/semiautocannon_45mm.mdl", "muzzle", Vector(79.2), Angle(0, 0, 180)) +ACF.SetCustomAttachment("models/autocannon/semiautocannon_57mm.mdl", "muzzle", Vector(109.12), Angle(0, 0, 180)) +ACF.SetCustomAttachment("models/autocannon/semiautocannon_76mm.mdl", "muzzle", Vector(167.2), Angle(0, 0, 180)) diff --git a/lua/acf/shared/weapons/shortcannon.lua b/lua/acf/shared/weapons/shortcannon.lua index 9c2bae987..3f567e160 100644 --- a/lua/acf/shared/weapons/shortcannon.lua +++ b/lua/acf/shared/weapons/shortcannon.lua @@ -89,3 +89,10 @@ ACF.RegisterWeapon("140mmSC", "SC", { PropMass = 12.8, } }) + +ACF.SetCustomAttachment("models/tankgun/tankgun_short_37mm.mdl", "muzzle", Vector(30.66), Angle(0, 0, 90)) +ACF.SetCustomAttachment("models/tankgun/tankgun_short_50mm.mdl", "muzzle", Vector(41.43, -0.01), Angle(0, 0, 90)) +ACF.SetCustomAttachment("models/tankgun/tankgun_short_75mm.mdl", "muzzle", Vector(62.15, -0.01), Angle(0, 0, 90)) +ACF.SetCustomAttachment("models/tankgun/tankgun_short_100mm.mdl", "muzzle", Vector(82.86, -0.01), Angle(0, 0, 90)) +ACF.SetCustomAttachment("models/tankgun/tankgun_short_120mm.mdl", "muzzle", Vector(99.42, -0.02), Angle(0, 0, 90)) +ACF.SetCustomAttachment("models/tankgun/tankgun_short_140mm.mdl", "muzzle", Vector(115.99, -0.02), Angle(0, 0, 90)) diff --git a/lua/acf/shared/weapons/smokelauncher.lua b/lua/acf/shared/weapons/smokelauncher.lua index 8e92439fd..abc82db60 100644 --- a/lua/acf/shared/weapons/smokelauncher.lua +++ b/lua/acf/shared/weapons/smokelauncher.lua @@ -31,3 +31,5 @@ ACF.RegisterWeapon("40mmSL", "SL", { PropMass = 0.000075, } }) + +ACF.SetCustomAttachment("models/launcher/40mmsl.mdl", "muzzle", Vector(5), Angle(0, 0, 180)) diff --git a/lua/acf/shared/weapons/smoothbore.lua b/lua/acf/shared/weapons/smoothbore.lua index 8cd33cf78..d6dc380e8 100644 --- a/lua/acf/shared/weapons/smoothbore.lua +++ b/lua/acf/shared/weapons/smoothbore.lua @@ -48,3 +48,7 @@ ACF.RegisterWeapon("140mmSB", "SB", { PropMass = 28, } }) + +ACF.SetCustomAttachment("models/tankgun_old/tankgun_100mm.mdl", "muzzle", Vector(135), Angle(0, 0, 90)) +ACF.SetCustomAttachment("models/tankgun_old/tankgun_120mm.mdl", "muzzle", Vector(162), Angle(0, 0, 90)) +ACF.SetCustomAttachment("models/tankgun_old/tankgun_140mm.mdl", "muzzle", Vector(189), Angle(0, 0, 90)) From 585f09f4851ef5ff907733bf4e4927720e40ae03 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Tue, 1 Dec 2020 18:27:13 -0300 Subject: [PATCH 178/279] Fixed flechette ammo - Fixed flechette ammo not being fired due to their bulletdata missing the crate ID. - Replaced a few instances of ACF_CreateBullet with ACF.CreateBullet. --- lua/acf/shared/ammo_types/ap.lua | 2 +- lua/acf/shared/ammo_types/fl.lua | 37 ++++++++++++++++---------------- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/lua/acf/shared/ammo_types/ap.lua b/lua/acf/shared/ammo_types/ap.lua index e4a20f237..2a0b34341 100644 --- a/lua/acf/shared/ammo_types/ap.lua +++ b/lua/acf/shared/ammo_types/ap.lua @@ -89,7 +89,7 @@ if SERVER then end function Ammo:Create(_, BulletData) - ACF_CreateBullet(BulletData) + ACF.CreateBullet(BulletData) end function Ammo:ServerConvert(ToolData) diff --git a/lua/acf/shared/ammo_types/fl.lua b/lua/acf/shared/ammo_types/fl.lua index d15df3c79..e64f1867b 100644 --- a/lua/acf/shared/ammo_types/fl.lua +++ b/lua/acf/shared/ammo_types/fl.lua @@ -109,22 +109,23 @@ if SERVER then function Ammo:Create(Gun, BulletData) local FlechetteData = { - Caliber = math.Round(BulletData.FlechetteRadius * 0.2, 2), - Id = BulletData.Id, - Type = "AP", - Owner = BulletData.Owner, - Entity = BulletData.Entity, - Gun = BulletData.Gun, - Pos = BulletData.Pos, - FrArea = BulletData.FlechetteArea, - ProjMass = BulletData.FlechetteMass, - DragCoef = BulletData.FlechetteDragCoef, - Tracer = BulletData.Tracer, - LimitVel = BulletData.LimitVel, - Ricochet = BulletData.Ricochet, - PenArea = BulletData.FlechettePenArea, - ShovePower = BulletData.ShovePower, - KETransfert = BulletData.KETransfert, + Caliber = math.Round(BulletData.FlechetteRadius * 0.2, 2), + Id = BulletData.Id, + Type = "AP", + Owner = BulletData.Owner, + Entity = BulletData.Entity, + Crate = BulletData.Crate, + Gun = BulletData.Gun, + Pos = BulletData.Pos, + FrArea = BulletData.FlechetteArea, + ProjMass = BulletData.FlechetteMass, + DragCoef = BulletData.FlechetteDragCoef, + Tracer = BulletData.Tracer, + LimitVel = BulletData.LimitVel, + Ricochet = BulletData.Ricochet, + PenArea = BulletData.FlechettePenArea, + ShovePower = BulletData.ShovePower, + KETransfert = BulletData.KETransfert, } --if ammo is cooking off, shoot in random direction @@ -136,7 +137,7 @@ if SERVER then FlechetteData.Flight = (MuzzleVec + Inaccuracy):GetNormalized() * BulletData.MuzzleVel * 39.37 + Gun:GetVelocity() - ACF_CreateBullet(FlechetteData) + ACF.CreateBullet(FlechetteData) end else local BaseInaccuracy = math.tan(math.rad(Gun:GetSpread())) @@ -153,7 +154,7 @@ if SERVER then FlechetteData.Flight = (MuzzleVec + BaseSpread + AddSpread):GetNormalized() * BulletData.MuzzleVel * 39.37 + Gun:GetVelocity() - ACF_CreateBullet(FlechetteData) + ACF.CreateBullet(FlechetteData) end end end From 92b53e194c09eb1d0b6244191d68ba07c8e938c3 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Tue, 1 Dec 2020 19:16:26 -0300 Subject: [PATCH 179/279] Ammo crates will now use multi convex base - Switched ammo crates to the multi convex base. Deals with a bug on the box base, along with other problems such as being unable to walk on top of them without "freezing". - ACF.CreateEntity will now longer force the physics object to sleep. --- lua/acf/base/sh_classes.lua | 1 - lua/entities/acf_ammo/shared.lua | 2 +- lua/entities/base_scalable/init.lua | 2 +- lua/entities/base_scalable_box/cl_init.lua | 6 ++---- lua/entities/base_scalable_box/shared.lua | 4 +++- lua/entities/base_scalable_mconvex/cl_init.lua | 10 ++++------ 6 files changed, 11 insertions(+), 14 deletions(-) diff --git a/lua/acf/base/sh_classes.lua b/lua/acf/base/sh_classes.lua index 38fa8b10c..bf2e5bcef 100644 --- a/lua/acf/base/sh_classes.lua +++ b/lua/acf/base/sh_classes.lua @@ -538,7 +538,6 @@ do -- Entity class registration function if IsValid(PhysObj) then PhysObj:EnableMotion(false) - PhysObj:Sleep() end if not NoUndo then diff --git a/lua/entities/acf_ammo/shared.lua b/lua/entities/acf_ammo/shared.lua index c4d867fef..1b4c8291a 100644 --- a/lua/entities/acf_ammo/shared.lua +++ b/lua/entities/acf_ammo/shared.lua @@ -1,4 +1,4 @@ -DEFINE_BASECLASS("base_scalable_box") +DEFINE_BASECLASS("base_scalable_mconvex") ENT.PrintName = "ACF Ammo Crate" ENT.WireDebugName = "ACF Ammo Crate" diff --git a/lua/entities/base_scalable/init.lua b/lua/entities/base_scalable/init.lua index dfe2dcab2..4d600fdee 100644 --- a/lua/entities/base_scalable/init.lua +++ b/lua/entities/base_scalable/init.lua @@ -67,7 +67,7 @@ local function ChangeSize(Entity, Size) if Entity.Size == Size then return false end local Original = Entity:GetOriginalSize() - local Scale = Vector(Size.x / Original.x, Size.y / Original.y, Size.z / Original.z) + local Scale = Vector(1 / Original.x, 1 / Original.y, 1 / Original.z) * Size if Entity.ApplyNewSize then Entity:ApplyNewSize(Size, Scale) end diff --git a/lua/entities/base_scalable_box/cl_init.lua b/lua/entities/base_scalable_box/cl_init.lua index d0ed0f5a3..0f41ff4f1 100644 --- a/lua/entities/base_scalable_box/cl_init.lua +++ b/lua/entities/base_scalable_box/cl_init.lua @@ -1,12 +1,10 @@ include("shared.lua") -function ENT:ApplyNewSize(NewSize) - local Size = self:GetOriginalSize() - local Scale = Vector(1 / Size.x, 1 / Size.y, 1 / Size.z) * NewSize +function ENT:ApplyNewSize(NewSize, NewScale) local Bounds = NewSize * 0.5 self.Matrix = Matrix() - self.Matrix:Scale(Scale) + self.Matrix:Scale(NewScale) self:EnableMatrix("RenderMultiply", self.Matrix) diff --git a/lua/entities/base_scalable_box/shared.lua b/lua/entities/base_scalable_box/shared.lua index b1891a64e..2c2fc2b5b 100644 --- a/lua/entities/base_scalable_box/shared.lua +++ b/lua/entities/base_scalable_box/shared.lua @@ -1,4 +1,6 @@ DEFINE_BASECLASS("base_scalable") ENT.PrintName = "Scalable Box" -ENT.WireDebugName = "Scalable Box" \ No newline at end of file +ENT.WireDebugName = "Scalable Box" + +-- TODO: Either client or serverside are remaining static, fix this before using this base again. diff --git a/lua/entities/base_scalable_mconvex/cl_init.lua b/lua/entities/base_scalable_mconvex/cl_init.lua index 4accb55dc..cd7a82fa6 100644 --- a/lua/entities/base_scalable_mconvex/cl_init.lua +++ b/lua/entities/base_scalable_mconvex/cl_init.lua @@ -4,19 +4,17 @@ function ENT:SetExtraInfo(Extra) self.Mesh = Extra.Mesh end -function ENT:ApplyNewSize(NewSize) - local Size = self:GetOriginalSize() - local Scale = Vector(1 / Size.x, 1 / Size.y, 1 / Size.z) * NewSize - local Mesh = self.Mesh +function ENT:ApplyNewSize(_, NewScale) + local Mesh = self.Mesh self.Matrix = Matrix() - self.Matrix:Scale(Scale) + self.Matrix:Scale(NewScale) self:EnableMatrix("RenderMultiply", self.Matrix) for I, Hull in ipairs(Mesh) do for J, Vertex in ipairs(Hull) do - Mesh[I][J] = (Vertex.pos or Vertex) * Scale + Mesh[I][J] = (Vertex.pos or Vertex) * NewScale end end From 83415f7699311bdd7dabd5aa0337dddc5f38c999 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Thu, 3 Dec 2020 11:09:18 -0300 Subject: [PATCH 180/279] Removed repeated argument from ENT:ACF_OnDamage - ENT:ACF_OnDamage will no longer receive the same entity it's being called on as the first argument. - Updated all entities that used ENT:ACF_OnDamage --- lua/acf/server/damage.lua | 2 +- lua/entities/acf_ammo/init.lua | 4 ++-- lua/entities/acf_engine/init.lua | 4 ++-- lua/entities/acf_fueltank/init.lua | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lua/acf/server/damage.lua b/lua/acf/server/damage.lua index 0c3d50f12..3c9512410 100644 --- a/lua/acf/server/damage.lua +++ b/lua/acf/server/damage.lua @@ -494,7 +494,7 @@ do end if Entity.ACF_OnDamage then -- Use special damage function if target entity has one - return Entity:ACF_OnDamage(Entity, Energy, FrArea, Angle, Inflictor, Bone, Type) + return Entity:ACF_OnDamage(Energy, FrArea, Angle, Inflictor, Bone, Type) elseif Activated == "Prop" then return PropDamage(Entity, Energy, FrArea, Angle, Inflictor, Bone) elseif Activated == "Vehicle" then diff --git a/lua/entities/acf_ammo/init.lua b/lua/entities/acf_ammo/init.lua index b31267879..16a2e613d 100644 --- a/lua/entities/acf_ammo/init.lua +++ b/lua/entities/acf_ammo/init.lua @@ -583,9 +583,9 @@ do -- ACF Activation and Damage ----------------- self.ACF.Type = "Prop" end - function ENT:ACF_OnDamage(Entity, Energy, FrArea, Ang, Inflictor, _, Type) + function ENT:ACF_OnDamage(Energy, FrArea, Ang, Inflictor, _, Type) local Mul = (Type == "HEAT" and ACF.HEATMulAmmo) or 1 --Heat penetrators deal bonus damage to ammo - local HitRes = ACF.PropDamage(Entity, Energy, FrArea * Mul, Ang, Inflictor) --Calling the standard damage prop function + local HitRes = ACF.PropDamage(self, Energy, FrArea * Mul, Ang, Inflictor) --Calling the standard damage prop function if self.Exploding or not self.IsExplosive then return HitRes end diff --git a/lua/entities/acf_engine/init.lua b/lua/entities/acf_engine/init.lua index 5f652854d..9877d7ab8 100644 --- a/lua/entities/acf_engine/init.lua +++ b/lua/entities/acf_engine/init.lua @@ -602,9 +602,9 @@ function ENT:ACF_Activate() end --This function needs to return HitRes -function ENT:ACF_OnDamage(Entity, Energy, FrArea, Angle, Inflictor, _, Type) +function ENT:ACF_OnDamage(Energy, FrArea, Angle, Inflictor, _, Type) local Mul = Type == "HEAT" and ACF.HEATMulEngine or 1 --Heat penetrators deal bonus damage to engines - local Res = ACF.PropDamage(Entity, Energy, FrArea * Mul, Angle, Inflictor) + local Res = ACF.PropDamage(self, Energy, FrArea * Mul, Angle, Inflictor) --adjusting performance based on damage local TorqueMult = math.Clamp(((1 - self.TorqueScale) / 0.5) * ((self.ACF.Health / self.ACF.MaxHealth) - 1) + 1, self.TorqueScale, 1) diff --git a/lua/entities/acf_fueltank/init.lua b/lua/entities/acf_fueltank/init.lua index e69519b38..060017cba 100644 --- a/lua/entities/acf_fueltank/init.lua +++ b/lua/entities/acf_fueltank/init.lua @@ -274,9 +274,9 @@ function ENT:ACF_Activate(Recalc) self.ACF.Type = "Prop" end -function ENT:ACF_OnDamage(Entity, Energy, FrArea, Angle, Inflictor, _, Type) +function ENT:ACF_OnDamage(Energy, FrArea, Angle, Inflictor, _, Type) local Mul = Type == "HEAT" and ACF.HEATMulFuel or 1 --Heat penetrators deal bonus damage to fuel - local HitRes = ACF.PropDamage(Entity, Energy, FrArea * Mul, Angle, Inflictor) --Calling the standard damage prop function + local HitRes = ACF.PropDamage(self, Energy, FrArea * Mul, Angle, Inflictor) --Calling the standard damage prop function local NoExplode = self.FuelType == "Diesel" and not (Type == "HE" or Type == "HEAT") if self.Exploding or NoExplode or not self.IsExplosive then return HitRes end From d4f56c42ec9923c7d3ad0b65bbde10b3b8bc343d Mon Sep 17 00:00:00 2001 From: Stoob Date: Thu, 3 Dec 2020 14:56:50 -0600 Subject: [PATCH 181/279] World penetration overhaul WIP --- lua/acf/server/ballistics.lua | 151 ++++++++++------------- lua/acf/server/damage.lua | 198 ++++++++++++++++++++++++++++++- lua/acf/shared/ammo_types/ap.lua | 22 ++-- 3 files changed, 268 insertions(+), 103 deletions(-) diff --git a/lua/acf/server/ballistics.lua b/lua/acf/server/ballistics.lua index 7c59448d4..0b26b411f 100644 --- a/lua/acf/server/ballistics.lua +++ b/lua/acf/server/ballistics.lua @@ -14,6 +14,8 @@ local BackTrace = { start = true, endpos = true, filter = true, mask = true, ou local GlobalFilter = ACF.GlobalFilter local AmmoTypes = ACF.Classes.AmmoTypes local Gravity = Vector(0, 0, -GetConVar("sv_gravity"):GetInt()) +local WORLD = game.GetWorld() +local HookRun = hook.Run cvars.AddChangeCallback("sv_gravity", function(_, _, Value) Gravity.z = -Value @@ -61,11 +63,11 @@ function ACF_CheckHitbox(Ent,RayStart,Ray) end -- This will create, or update, the tracer effect on the clientside -function ACF.BulletClient(Index, Bullet, Type, Hit, HitPos) +function ACF.BulletClient(Bullet, Type, Hit, HitPos) if Bullet.NoEffect then return end -- No clientside effect will be created for this bullet local Effect = EffectData() - Effect:SetHitBox(Index) + Effect:SetHitBox(Bullet.Index) Effect:SetStart(Bullet.Flight * 0.1) if Type == "Update" then @@ -85,8 +87,8 @@ function ACF.BulletClient(Index, Bullet, Type, Hit, HitPos) util.Effect("ACF_Bullet_Effect", Effect, true, true) end -function ACF.RemoveBullet(Index) - local Bullet = Bullets[Index] +function ACF.RemoveBullet(Bullet) + local Index = Bullet.Index Bullets[Index] = nil Unused[Index] = true @@ -100,8 +102,8 @@ function ACF.RemoveBullet(Index) end end -function ACF.CalcBulletFlight(Index, Bullet) - if not Bullet.LastThink then return ACF.RemoveBullet(Index) end +function ACF.CalcBulletFlight(Bullet) + if not Bullet.LastThink then return ACF.RemoveBullet(Bullet) end if Bullet.PreCalcFlight then Bullet:PreCalcFlight() @@ -116,7 +118,7 @@ function ACF.CalcBulletFlight(Index, Bullet) Bullet.LastThink = ACF.CurTime Bullet.DeltaTime = DeltaTime - ACF.DoBulletsFlight(Index, Bullet) + ACF.DoBulletsFlight(Bullet) if Bullet.PostCalcFlight then Bullet:PostCalcFlight() @@ -144,10 +146,11 @@ local function GetBulletIndex() return Index end +local CalcFlight = ACF.CalcBulletFlight local function IterateBullets() - for Index, Bullet in pairs(Bullets) do + for _, Bullet in pairs(Bullets) do if not Bullet.HandlesOwnIteration then - ACF.CalcBulletFlight(Index, Bullet) + CalcFlight(Bullet) end end end @@ -177,32 +180,60 @@ function ACF.CreateBullet(BulletData) Bullets[Index] = Bullet - ACF.BulletClient(Index, Bullet, "Init", 0) - ACF.CalcBulletFlight(Index, Bullet) + ACF.BulletClient(Bullet, "Init", 0) + ACF.CalcBulletFlight(Bullet) return Bullet end -function ACF.DoBulletsFlight(Index, Bullet) - if hook.Run("ACF_BulletsFlight", Index, Bullet) == false then return end +local function OnImpact(Bullet, Trace, Type) + local Data = AmmoTypes[Bullet.Type] + local Func = Type == "World" and Data.WorldImpact or Data.PropImpact + local Retry = Func(Data, Bullet, Trace) + + if Retry == "Penetrated" then + if Bullet.OnPenetrated then + Bullet.OnPenetrated(Bullet, Trace) + end + + ACF.BulletClient(Bullet, "Update", 2, Trace.HitPos) + ACF.DoBulletsFlight(Bullet) + elseif Retry == "Ricochet" then + if Bullet.OnRicocheted then + Bullet.OnRicocheted(Bullet, Trace) + end + + ACF.BulletClient(Bullet, "Update", 3, Trace.HitPos) + else + if Bullet.OnEndFlight then + Bullet.OnEndFlight(Bullet, Trace) + end + + ACF.BulletClient(Bullet, "Update", 1, Trace.HitPos) + + Data:OnFlightEnd(Bullet, Trace) + end +end + +function ACF.DoBulletsFlight(Bullet) + if HookRun("ACF Bullet Flight", Bullet) == false then return end if Bullet.SkyLvL then if ACF.CurTime - Bullet.LifeTime > 30 then - return ACF.RemoveBullet(Index) + return ACF.RemoveBullet(Bullet) end if Bullet.NextPos.z + ACF.SkyboxGraceZone > Bullet.SkyLvL then if Bullet.Fuze and Bullet.Fuze <= ACF.CurTime then -- Fuze detonated outside map - ACF.RemoveBullet(Index) + ACF.RemoveBullet(Bullet) end return elseif not util.IsInWorld(Bullet.NextPos) then - return ACF.RemoveBullet(Index) + return ACF.RemoveBullet(Bullet) else Bullet.SkyLvL = nil Bullet.LifeTime = nil - Bullet.SkipNextHit = true return end @@ -242,96 +273,42 @@ function ACF.DoBulletsFlight(Index, Bullet) Bullet.Filter = Filter end - local RoundData = AmmoTypes[Bullet.Type] - if Bullet.Fuze and Bullet.Fuze <= ACF.CurTime then if not util.IsInWorld(Bullet.Pos) then -- Outside world, just delete - return ACF.RemoveBullet(Index) + return ACF.RemoveBullet(Bullet.Index) else + if Bullet.OnEndFlight then + Bullet.OnEndFlight(Bullet, nil) + end + local DeltaTime = Bullet.DeltaTime local DeltaFuze = ACF.CurTime - Bullet.Fuze local Lerp = DeltaFuze / DeltaTime - - if not FlightRes.Hit or Lerp < FlightRes.Fraction then -- Fuze went off before running into something + --print(DeltaTime, DeltaFuze, Lerp) + if FlightRes.Hit and Lerp < FlightRes.Fraction or true then -- Fuze went off before running into something local Pos = LerpVector(DeltaFuze / DeltaTime, Bullet.Pos, Bullet.NextPos) debugoverlay.Line(Bullet.Pos, Bullet.NextPos, 5, Color( 0, 255, 0 )) - if Bullet.OnEndFlight then - Bullet.OnEndFlight(Index, Bullet, FlightRes) - end - - ACF.BulletClient(Index, Bullet, "Update", 1, Pos) - - RoundData:OnFlightEnd(Index, Bullet, Pos, Bullet.Flight:GetNormalized()) + ACF.BulletClient(Bullet, "Update", 1, Pos) - return + AmmoTypes[Bullet.Type]:OnFlightEnd(Bullet, Pos, Bullet.Flight:GetNormalized()) end end end - if Bullet.SkipNextHit then - if not FlightRes.StartSolid and not FlightRes.HitNoDraw then - Bullet.SkipNextHit = nil - end - elseif FlightRes.HitNonWorld and not GlobalFilter[FlightRes.Entity:GetClass()] then - local Retry = RoundData:PropImpact(Index, Bullet, FlightRes.Entity, FlightRes.HitNormal, FlightRes.HitPos, FlightRes.HitGroup) - - if Retry == "Penetrated" then - if Bullet.OnPenetrated then - Bullet.OnPenetrated(Index, Bullet, FlightRes) - end - - ACF.BulletClient(Index, Bullet, "Update", 2, FlightRes.HitPos) - ACF.DoBulletsFlight(Index, Bullet) - elseif Retry == "Ricochet" then - if Bullet.OnRicocheted then - Bullet.OnRicocheted(Index, Bullet, FlightRes) - end - - ACF.BulletClient(Index, Bullet, "Update", 3, FlightRes.HitPos) - else - if Bullet.OnEndFlight then - Bullet.OnEndFlight(Index, Bullet, FlightRes) - end - - ACF.BulletClient(Index, Bullet, "Update", 1, FlightRes.HitPos) - - RoundData:OnFlightEnd(Index, Bullet, FlightRes.HitPos, FlightRes.HitNormal) - end - elseif FlightRes.HitWorld then - if not FlightRes.HitSky then - local Retry = RoundData:WorldImpact(Index, Bullet, FlightRes.HitPos, FlightRes.HitNormal) - - if Retry == "Penetrated" then - if Bullet.OnPenetrated then - Bullet.OnPenetrated(Index, Bullet, FlightRes) - end - - ACF.BulletClient(Index, Bullet, "Update", 2, FlightRes.HitPos) - ACF.CalcBulletFlight(Index, Bullet) - elseif Retry == "Ricochet" then - if Bullet.OnRicocheted then - Bullet.OnRicocheted(Index, Bullet, FlightRes) - end - - ACF.BulletClient(Index, Bullet, "Update", 3, FlightRes.HitPos) - else - if Bullet.OnEndFlight then - Bullet.OnEndFlight(Index, Bullet, FlightRes) - end - - ACF.BulletClient(Index, Bullet, "Update", 1, FlightRes.HitPos) - - RoundData:OnFlightEnd(Index, Bullet, FlightRes.HitPos, FlightRes.HitNormal) - end - else + if FlightRes.Hit then + if FlightRes.HitSky then if FlightRes.HitNormal == Vector(0, 0, -1) then Bullet.SkyLvL = FlightRes.HitPos.z Bullet.LifeTime = ACF.CurTime else - ACF.RemoveBullet(Index) + ACF.RemoveBullet(Bullet) end + else + local Type = (FlightRes.HitWorld or FlightRes.Entity:CPPIGetOwner() == WORLD) and "World" or "Prop" + + OnImpact(Bullet, FlightRes, Type) end end end diff --git a/lua/acf/server/damage.lua b/lua/acf/server/damage.lua index 3c9512410..51acb9baf 100644 --- a/lua/acf/server/damage.lua +++ b/lua/acf/server/damage.lua @@ -494,7 +494,7 @@ do end if Entity.ACF_OnDamage then -- Use special damage function if target entity has one - return Entity:ACF_OnDamage(Energy, FrArea, Angle, Inflictor, Bone, Type) + return Entity:ACF_OnDamage(Entity, Energy, FrArea, Angle, Inflictor, Bone, Type) elseif Activated == "Prop" then return PropDamage(Entity, Energy, FrArea, Angle, Inflictor, Bone) elseif Activated == "Vehicle" then @@ -693,6 +693,7 @@ do return HitRes end + --[[ function ACF_PenetrateGround( Bullet, Energy, HitPos, HitNormal ) local MaxDig = ((Energy.Penetration / Bullet.PenArea) * ACF.KEtoRHA / ACF.GroundtoRHA) / 25.4 local HitRes = {Penetrated = false, Ricochet = false} @@ -729,6 +730,201 @@ do end return HitRes + end]]-- + + function ACF_Ricochet(Bullet, Trace) + local Ricochet = 0 + local Speed = Bullet.Flight:Length() / ACF.Scale + local Angle = ACF_GetHitAngle( Trace.HitNormal, Bullet.Flight ) + local MinAngle = math.min(Bullet.Ricochet - Speed / 39.37 / 30 + 20,89.9) --Making the chance of a ricochet get higher as the speeds increase + + if Angle > math.random(MinAngle,90) and Angle < 89.9 then --Checking for ricochet + Ricochet = Angle / 90 * 0.75 + end + + if Ricochet > 0 and Bullet.GroundRicos < 2 then + Bullet.GroundRicos = Bullet.GroundRicos + 1 + Bullet.NextPos = Trace.HitPos + Bullet.Flight = (RicochetVector(Bullet.Flight, Trace.HitNormal) + VectorRand() * 0.05):GetNormalized() * Speed * Ricochet + + print("Ricochet") + return "Ricochet" + end + + print("Splat") + return false + end + + local function DigTrace(From, To, Filter) + local Dig = util.TraceHull({ + start = From, + endpos = To, + mask = MASK_NPCSOLID_BRUSHONLY, -- Map and brushes only + mins = Vector(), + maxs = Vector() + }) + + debugoverlay.Line(From, Dig.HitPos, 30, ColorRand(100, 255), true) + + if Dig.StartSolid then -- Started inside solid map volume + if Dig.FractionLeftSolid == 0 then -- Trace could not move inside + local Displacement = To - From + local Normal = Displacement:GetNormalized() + local Length = Displacement:Length() + + local C = math.Round(Length / 12) + local N = Length / C + + for I = 1, C do + local P = From + Normal * I * N + + debugoverlay.Cross(P, 1, 15, Color(255, 255, 0), true) + + local Back = util.TraceHull({ -- Send a trace backwards to hit the other side + start = P, + endpos = From, -- Countering the initial offset position of the dig trace to handle things <1 inch thick + mask = MASK_NPCSOLID_BRUSHONLY, -- Map and brushes only + mins = Vector(), + maxs = Vector() + }) + + if Back.StartSolid or Back.HitNoDraw then continue end + + debugoverlay.Line(P, Back.HitPos, 30, Color(255, 0, 255), true) + return true, Back.HitPos + end + + return false + elseif Dig.FractionLeftSolid == 1 then -- Non-penetration: too thick + return false + else -- Penetrated + if Dig.HitNoDraw then -- Hit a layer inside + return DigTrace(Dig.HitPos + (To - From):GetNormalized() * 0.1, To, Filter) -- Try again + else -- Complete penetration + local Back = util.TraceHull({ + start = Dig.StartPos, + endpos = From, + mask = MASK_NPCSOLID_BRUSHONLY, -- Map and brushes only + mins = Vector(), + maxs = Vector() + }) + + -- False positive, still inside the world + -- Typically occurs when two brushes meet + if Back.StartSolid or Back.HitNoDraw then + return DigTrace(Dig.StartPos + (To - From):GetNormalized() * 0.1, To, Filter) + end + + debugoverlay.Cross(Dig.StartPos, 5, 30, Color(255, 0, 0), true) -- Red cross: Exit point + + return true, Dig.StartPos + end + end + else -- Started inside a brush + local Back = util.TraceHull({ -- Send a trace backwards to hit the other side + start = Dig.HitPos, + endpos = From + (From - Dig.HitPos):GetNormalized(), -- Countering the initial offset position of the dig trace to handle things <1 inch thick + mask = MASK_NPCSOLID_BRUSHONLY, -- Map and brushes only + mins = Vector(), + maxs = Vector() + }) + + local Up = (Dig.HitPos - Back.HitPos):Angle():Up() + debugoverlay.Line(Dig.HitPos + Up, Back.HitPos + Up, 30, Color(255, 0, 160), true) + + if Back.StartSolid then -- object is too thick + return false + elseif not Back.Hit or Back.HitNoDraw then + -- Hit nothing on the way back + -- Map edge, going into the ground, whatever... + -- Effectively infinitely thick + + return false + else -- Penetration + debugoverlay.Cross(Back.HitPos, 5, Color(255, 0, 0), true) -- Red cross: Exit point + + return true, Back.HitPos + end + end + end + + function ACF_PenetrateGround(Bullet, Trace) + print("ACF_PenetrateGroundx") + local Energy = ACF_Kinetic(Bullet.Flight:Length() / ACF.Scale, Bullet.ProjMass, Bullet.LimitVel) + local Density = util.GetSurfaceData(Trace.SurfaceProps).density / 10000 + local Pen = Energy.Penetration / Bullet.PenArea * ACF.KEtoRHA -- Base RHA penetration of the projectile + local RHAe = Pen / Density -- RHA equivalent thickness of the target material + + local Enter = Trace.HitPos -- Impact point + local Fwd = Bullet.Flight:GetNormalized() + + debugoverlay.Cross(Enter, 5, 30, Color(0, 255, 0), true) -- Green cross: entrance point + + local Penetrated, Exit = DigTrace(Enter + Fwd, Enter + Fwd * RHAe / 25.4) + + if Penetrated then + print("Penetrated") + local Thicc = (Exit - Enter):Length() * Density * 25.4 -- RHAe of the material passed through + + print("Pass-through RHAe: " .. math.Round(Thicc)) + debugoverlay.Cross(Exit, 5, 30, Color(255, 0, 0), true) -- Red cross: exit point + + Bullet.Flight = Bullet.Flight * (1 - Thicc / Pen) + Bullet.Pos = Exit + Fwd * 0.25 + --Bullet.NextPos = Exit + Fwd * 0.25 + + return "Penetrated" --, Exit, Thicc + else -- Ricochet + return ACF_Ricochet(Bullet, Trace) + end + + function ACF_PenetrateMapEntity(Bullet, Trace) + print("PenetrateMapEntity") + local Energy = ACF_Kinetic(Bullet.Flight:Length() / ACF.Scale, Bullet.ProjMass, Bullet.LimitVel) + local Density = util.GetSurfaceData(Trace.SurfaceProps).density / 10000 + local Pen = Energy.Penetration / Bullet.PenArea * ACF.KEtoRHA -- Base RHA penetration of the projectile + local RHAe = Pen / Density -- RHA equivalent thickness of the target material + + local Enter = Trace.HitPos -- Impact point + local Fwd = Bullet.Flight:GetNormalized() + + local PassThrough = util.TraceHull({ + start = Enter, + endpos = Enter + Fwd * RHAe / 25.4, + filter = {Trace.Entity}, + mask = MASK_SOLID_BRUSHONLY + }) + + debugoverlay.Line(PassThrough.StartPos, PassThrough.HitPos, 30, Color(255, 0, 160), true) + + local Filt = {} + local Back + + repeat + Back = util.TraceHull({ + start = PassThrough.HitPos, + endpos = Origin, + filter = Filt + }) + + if Back.Entity ~= Trace.Entity then + Filt[#Filt + 1] = Back.Entity + continue + end + + if Back.StartSolid then return ACF_Ricochet(Bullet, Trace) end + until Back.Entity == Trace.Entity + + local Thicc = (Back.HitPos - Entrance):Length() * Density * 25.4 -- Obstacle thickness in RHA + + Bullet.Flight = Bullet.Flight * (1 - Thicc / Pen) + Bullet.Pos = Exit + Fwd * 0.25 + + debugoverlay.Cross(Back.HitPos, 5, 30, Color(255, 0, 0), true) + + return "Penetrated" + --return true, Back.HitPos, Thickness + end end end end diff --git a/lua/acf/shared/ammo_types/ap.lua b/lua/acf/shared/ammo_types/ap.lua index 2a0b34341..e7d6d637e 100644 --- a/lua/acf/shared/ammo_types/ap.lua +++ b/lua/acf/shared/ammo_types/ap.lua @@ -89,7 +89,7 @@ if SERVER then end function Ammo:Create(_, BulletData) - ACF.CreateBullet(BulletData) + ACF_CreateBullet(BulletData) end function Ammo:ServerConvert(ToolData) @@ -105,6 +105,7 @@ if SERVER then function Ammo:Network(Entity, BulletData) Entity:SetNW2String("AmmoType", "AP") + Entity:SetNW2String("AmmoID", BulletData.Id) Entity:SetNW2Float("Caliber", BulletData.Caliber) Entity:SetNW2Float("ProjMass", BulletData.ProjMass) Entity:SetNW2Float("PropMass", BulletData.PropMass) @@ -122,7 +123,7 @@ if SERVER then return Text:format(math.Round(BulletData.MuzzleVel, 2), math.Round(Data.MaxPen, 2)) end - function Ammo:PropImpact(_, Bullet, Target, HitNormal, HitPos, Bone) + function Ammo:PropImpact(Bullet, Target, HitNormal, HitPos, Bone) if ACF_Check(Target) then local Speed = Bullet.Flight:Length() / ACF.Scale local Energy = ACF_Kinetic(Speed, Bullet.ProjMass, Bullet.LimitVel) @@ -146,21 +147,12 @@ if SERVER then end end - function Ammo:WorldImpact(_, Bullet, HitPos, HitNormal) - local Energy = ACF_Kinetic(Bullet.Flight:Length() / ACF.Scale, Bullet.ProjMass, Bullet.LimitVel) - local HitRes = ACF_PenetrateGround(Bullet, Energy, HitPos, HitNormal) - - if HitRes.Penetrated then - return "Penetrated" - elseif HitRes.Ricochet then - return "Ricochet" - else - return false - end + function Ammo:WorldImpact(Bullet, Trace) + return Trace.Entity and ACF_PenetrateMapEntity(Bullet, Trace) or ACF_PenetrateGround(Bullet, Trace) end - function Ammo:OnFlightEnd(Index) - ACF_RemoveBullet(Index) + function Ammo:OnFlightEnd(Bullet) + ACF_RemoveBullet(Bullet) end else ACF.RegisterAmmoDecal("AP", "damage/ap_pen", "damage/ap_rico") From d7e4913dd9aab526191f765ec3e63c875f6df841 Mon Sep 17 00:00:00 2001 From: Stoob Date: Fri, 4 Dec 2020 16:02:28 -0600 Subject: [PATCH 182/279] Fixed getting world entity Apparently, the world entity is not defined at runtime --- lua/acf/server/ballistics.lua | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lua/acf/server/ballistics.lua b/lua/acf/server/ballistics.lua index 0b26b411f..16fd5e43f 100644 --- a/lua/acf/server/ballistics.lua +++ b/lua/acf/server/ballistics.lua @@ -14,7 +14,6 @@ local BackTrace = { start = true, endpos = true, filter = true, mask = true, ou local GlobalFilter = ACF.GlobalFilter local AmmoTypes = ACF.Classes.AmmoTypes local Gravity = Vector(0, 0, -GetConVar("sv_gravity"):GetInt()) -local WORLD = game.GetWorld() local HookRun = hook.Run cvars.AddChangeCallback("sv_gravity", function(_, _, Value) @@ -306,7 +305,7 @@ function ACF.DoBulletsFlight(Bullet) ACF.RemoveBullet(Bullet) end else - local Type = (FlightRes.HitWorld or FlightRes.Entity:CPPIGetOwner() == WORLD) and "World" or "Prop" + local Type = (FlightRes.HitWorld or FlightRes.Entity:CPPIGetOwner() == game.GetWorld()) and "World" or "Prop" OnImpact(Bullet, FlightRes, Type) end From 2e173da634497d8f65b27f6f2d02f526ca327dd8 Mon Sep 17 00:00:00 2001 From: Stoob Date: Fri, 4 Dec 2020 16:02:53 -0600 Subject: [PATCH 183/279] Fixed PenetrateWorldEntity defined in wrong place Woops! --- lua/acf/server/damage.lua | 96 +++++++++++++++++++-------------------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/lua/acf/server/damage.lua b/lua/acf/server/damage.lua index 51acb9baf..5d7131c35 100644 --- a/lua/acf/server/damage.lua +++ b/lua/acf/server/damage.lua @@ -848,6 +848,54 @@ do end end + function ACF_PenetrateMapEntity(Bullet, Trace) + print("PenetrateMapEntity") + local Energy = ACF_Kinetic(Bullet.Flight:Length() / ACF.Scale, Bullet.ProjMass, Bullet.LimitVel) + local Density = util.GetSurfaceData(Trace.SurfaceProps).density / 10000 + local Pen = Energy.Penetration / Bullet.PenArea * ACF.KEtoRHA -- Base RHA penetration of the projectile + local RHAe = Pen / Density -- RHA equivalent thickness of the target material + + local Enter = Trace.HitPos -- Impact point + local Fwd = Bullet.Flight:GetNormalized() + + local PassThrough = util.TraceHull({ + start = Enter, + endpos = Enter + Fwd * RHAe / 25.4, + filter = {Trace.Entity}, + mask = MASK_SOLID_BRUSHONLY + }) + + debugoverlay.Line(PassThrough.StartPos, PassThrough.HitPos, 30, Color(255, 0, 160), true) + + local Filt = {} + local Back + + repeat + Back = util.TraceHull({ + start = PassThrough.HitPos, + endpos = Origin, + filter = Filt + }) + + if Back.Entity ~= Trace.Entity then + Filt[#Filt + 1] = Back.Entity + continue + end + + if Back.StartSolid then return ACF_Ricochet(Bullet, Trace) end + until Back.Entity == Trace.Entity + + local Thicc = (Back.HitPos - Entrance):Length() * Density * 25.4 -- Obstacle thickness in RHA + + Bullet.Flight = Bullet.Flight * (1 - Thicc / Pen) + Bullet.Pos = Exit + Fwd * 0.25 + + debugoverlay.Cross(Back.HitPos, 5, 30, Color(255, 0, 0), true) + + return "Penetrated" + --return true, Back.HitPos, Thickness + end + function ACF_PenetrateGround(Bullet, Trace) print("ACF_PenetrateGroundx") local Energy = ACF_Kinetic(Bullet.Flight:Length() / ACF.Scale, Bullet.ProjMass, Bullet.LimitVel) @@ -877,54 +925,6 @@ do else -- Ricochet return ACF_Ricochet(Bullet, Trace) end - - function ACF_PenetrateMapEntity(Bullet, Trace) - print("PenetrateMapEntity") - local Energy = ACF_Kinetic(Bullet.Flight:Length() / ACF.Scale, Bullet.ProjMass, Bullet.LimitVel) - local Density = util.GetSurfaceData(Trace.SurfaceProps).density / 10000 - local Pen = Energy.Penetration / Bullet.PenArea * ACF.KEtoRHA -- Base RHA penetration of the projectile - local RHAe = Pen / Density -- RHA equivalent thickness of the target material - - local Enter = Trace.HitPos -- Impact point - local Fwd = Bullet.Flight:GetNormalized() - - local PassThrough = util.TraceHull({ - start = Enter, - endpos = Enter + Fwd * RHAe / 25.4, - filter = {Trace.Entity}, - mask = MASK_SOLID_BRUSHONLY - }) - - debugoverlay.Line(PassThrough.StartPos, PassThrough.HitPos, 30, Color(255, 0, 160), true) - - local Filt = {} - local Back - - repeat - Back = util.TraceHull({ - start = PassThrough.HitPos, - endpos = Origin, - filter = Filt - }) - - if Back.Entity ~= Trace.Entity then - Filt[#Filt + 1] = Back.Entity - continue - end - - if Back.StartSolid then return ACF_Ricochet(Bullet, Trace) end - until Back.Entity == Trace.Entity - - local Thicc = (Back.HitPos - Entrance):Length() * Density * 25.4 -- Obstacle thickness in RHA - - Bullet.Flight = Bullet.Flight * (1 - Thicc / Pen) - Bullet.Pos = Exit + Fwd * 0.25 - - debugoverlay.Cross(Back.HitPos, 5, 30, Color(255, 0, 0), true) - - return "Penetrated" - --return true, Back.HitPos, Thickness - end end end end From 6c2d1b6ba5f9209dc79d2e026af6e6171df9d487 Mon Sep 17 00:00:00 2001 From: Stoob Date: Fri, 4 Dec 2020 16:36:42 -0600 Subject: [PATCH 184/279] Fixed bad ternary operation Fixed evaluation in AP running both functions instead of the intended one --- lua/acf/shared/ammo_types/ap.lua | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lua/acf/shared/ammo_types/ap.lua b/lua/acf/shared/ammo_types/ap.lua index e7d6d637e..fcaeefda9 100644 --- a/lua/acf/shared/ammo_types/ap.lua +++ b/lua/acf/shared/ammo_types/ap.lua @@ -148,7 +148,11 @@ if SERVER then end function Ammo:WorldImpact(Bullet, Trace) - return Trace.Entity and ACF_PenetrateMapEntity(Bullet, Trace) or ACF_PenetrateGround(Bullet, Trace) + if Trace.Entity then + return ACF_PenetrateMapEntity(Bullet, Trace) + else + return ACF_PenetrateGround(Bullet, Trace) + end end function Ammo:OnFlightEnd(Bullet) From c04f46a39b0f44dab3d5094f109c6056f3d21203 Mon Sep 17 00:00:00 2001 From: Stoob Date: Fri, 4 Dec 2020 19:18:17 -0600 Subject: [PATCH 185/279] Fixed infinite loop on map entity hit --- lua/acf/server/damage.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lua/acf/server/damage.lua b/lua/acf/server/damage.lua index 5d7131c35..0c8650ab4 100644 --- a/lua/acf/server/damage.lua +++ b/lua/acf/server/damage.lua @@ -873,11 +873,11 @@ do repeat Back = util.TraceHull({ start = PassThrough.HitPos, - endpos = Origin, + endpos = Enter, filter = Filt }) - if Back.Entity ~= Trace.Entity then + if Back.HitNonWorld and Back.Entity ~= Trace.Entity then Filt[#Filt + 1] = Back.Entity continue end From a68617a7a32b6fbb179d47eeafe512275088fbca Mon Sep 17 00:00:00 2001 From: Stoob Date: Fri, 4 Dec 2020 19:18:41 -0600 Subject: [PATCH 186/279] Removed old ACF_PenetrateGround --- lua/acf/server/damage.lua | 39 --------------------------------------- 1 file changed, 39 deletions(-) diff --git a/lua/acf/server/damage.lua b/lua/acf/server/damage.lua index 0c8650ab4..5b74e2afb 100644 --- a/lua/acf/server/damage.lua +++ b/lua/acf/server/damage.lua @@ -693,45 +693,6 @@ do return HitRes end - --[[ - function ACF_PenetrateGround( Bullet, Energy, HitPos, HitNormal ) - local MaxDig = ((Energy.Penetration / Bullet.PenArea) * ACF.KEtoRHA / ACF.GroundtoRHA) / 25.4 - local HitRes = {Penetrated = false, Ricochet = false} - - local DigTr = { } - DigTr.start = HitPos + Bullet.Flight:GetNormalized() * 0.1 - DigTr.endpos = HitPos + Bullet.Flight:GetNormalized() * (MaxDig + 0.1) - DigTr.filter = Bullet.Filter - DigTr.mask = MASK_SOLID_BRUSHONLY - local DigRes = util.TraceLine(DigTr) - --print(util.GetSurfacePropName(DigRes.SurfaceProps)) - - local loss = DigRes.FractionLeftSolid - - if loss == 1 or loss == 0 then --couldn't penetrate - local Ricochet = 0 - local Speed = Bullet.Flight:Length() / ACF.Scale - local Angle = ACF_GetHitAngle( HitNormal, Bullet.Flight ) - local MinAngle = math.min(Bullet.Ricochet - Speed / 39.37 / 30 + 20,89.9) --Making the chance of a ricochet get higher as the speeds increase - if Angle > math.random(MinAngle,90) and Angle < 89.9 then --Checking for ricochet - Ricochet = Angle / 90 * 0.75 - end - - if Ricochet > 0 and Bullet.GroundRicos < 2 then - Bullet.GroundRicos = Bullet.GroundRicos + 1 - Bullet.NextPos = HitPos - Bullet.Flight = (RicochetVector(Bullet.Flight, HitNormal) + VectorRand() * 0.05):GetNormalized() * Speed * Ricochet - HitRes.Ricochet = true - end - else --penetrated - Bullet.Flight = Bullet.Flight * (1 - loss) - Bullet.NextPos = DigRes.StartPos + Bullet.Flight:GetNormalized() * 0.25 --this is actually where trace left brush - HitRes.Penetrated = true - end - - return HitRes - end]]-- - function ACF_Ricochet(Bullet, Trace) local Ricochet = 0 local Speed = Bullet.Flight:Length() / ACF.Scale From 9b0c5ace4507453913dd872b9bbf63f88b6e74c5 Mon Sep 17 00:00:00 2001 From: Stoob Date: Fri, 4 Dec 2020 19:19:37 -0600 Subject: [PATCH 187/279] Minor stuff --- lua/acf/server/ballistics.lua | 4 ++-- lua/acf/server/damage.lua | 11 ++++++----- lua/acf/shared/ammo_types/ap.lua | 2 +- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/lua/acf/server/ballistics.lua b/lua/acf/server/ballistics.lua index 16fd5e43f..62dc9cd7d 100644 --- a/lua/acf/server/ballistics.lua +++ b/lua/acf/server/ballistics.lua @@ -87,10 +87,10 @@ function ACF.BulletClient(Bullet, Type, Hit, HitPos) end function ACF.RemoveBullet(Bullet) - local Index = Bullet.Index + local Index = Bullet.Index Bullets[Index] = nil - Unused[Index] = true + Unused[Index] = true if Bullet and Bullet.OnRemoved then Bullet:OnRemoved() diff --git a/lua/acf/server/damage.lua b/lua/acf/server/damage.lua index 5b74e2afb..8a4c498a1 100644 --- a/lua/acf/server/damage.lua +++ b/lua/acf/server/damage.lua @@ -268,7 +268,7 @@ do end local function CanSee(Target, Data) - local R = ACF.Trace(Data) + local R = Trace(Data) return R.Entity == Target or not R.Hit or (Target:InVehicle() and R.Entity == Target:GetVehicle()) end @@ -712,7 +712,6 @@ do return "Ricochet" end - print("Splat") return false end @@ -811,6 +810,7 @@ do function ACF_PenetrateMapEntity(Bullet, Trace) print("PenetrateMapEntity") + local Energy = ACF_Kinetic(Bullet.Flight:Length() / ACF.Scale, Bullet.ProjMass, Bullet.LimitVel) local Density = util.GetSurfaceData(Trace.SurfaceProps).density / 10000 local Pen = Energy.Penetration / Bullet.PenArea * ACF.KEtoRHA -- Base RHA penetration of the projectile @@ -846,10 +846,10 @@ do if Back.StartSolid then return ACF_Ricochet(Bullet, Trace) end until Back.Entity == Trace.Entity - local Thicc = (Back.HitPos - Entrance):Length() * Density * 25.4 -- Obstacle thickness in RHA + local Thicc = (Back.HitPos - Enter):Length() * Density * 25.4 -- Obstacle thickness in RHA Bullet.Flight = Bullet.Flight * (1 - Thicc / Pen) - Bullet.Pos = Exit + Fwd * 0.25 + Bullet.Pos = Back.HitPos + Fwd * 0.25 debugoverlay.Cross(Back.HitPos, 5, 30, Color(255, 0, 0), true) @@ -858,7 +858,8 @@ do end function ACF_PenetrateGround(Bullet, Trace) - print("ACF_PenetrateGroundx") + print("ACF_PenetrateGround") + local Energy = ACF_Kinetic(Bullet.Flight:Length() / ACF.Scale, Bullet.ProjMass, Bullet.LimitVel) local Density = util.GetSurfaceData(Trace.SurfaceProps).density / 10000 local Pen = Energy.Penetration / Bullet.PenArea * ACF.KEtoRHA -- Base RHA penetration of the projectile diff --git a/lua/acf/shared/ammo_types/ap.lua b/lua/acf/shared/ammo_types/ap.lua index fcaeefda9..c79d194ab 100644 --- a/lua/acf/shared/ammo_types/ap.lua +++ b/lua/acf/shared/ammo_types/ap.lua @@ -148,7 +148,7 @@ if SERVER then end function Ammo:WorldImpact(Bullet, Trace) - if Trace.Entity then + if IsValid(Trace.Entity) then return ACF_PenetrateMapEntity(Bullet, Trace) else return ACF_PenetrateGround(Bullet, Trace) From f3033026395efefadd85c283a8c94d3cdde45a71 Mon Sep 17 00:00:00 2001 From: Stoob Date: Fri, 4 Dec 2020 19:40:49 -0600 Subject: [PATCH 188/279] Updated APHE --- lua/acf/shared/ammo_types/aphe.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lua/acf/shared/ammo_types/aphe.lua b/lua/acf/shared/ammo_types/aphe.lua index a123c1fdf..721885b9a 100644 --- a/lua/acf/shared/ammo_types/aphe.lua +++ b/lua/acf/shared/ammo_types/aphe.lua @@ -110,10 +110,10 @@ if SERVER then return Text:format(math.Round(Data.BlastRadius, 2), math.Round(BulletData.FillerMass * ACF.HEPower, 2)) end - function Ammo:OnFlightEnd(Index, Bullet, HitPos) - ACF_HE(HitPos, Bullet.FillerMass, Bullet.ProjMass - Bullet.FillerMass, Bullet.Owner, nil, Bullet.Gun) + function Ammo:OnFlightEnd( Bullet, Trace) + ACF_HE(Trace.HitPos, Bullet.FillerMass, Bullet.ProjMass - Bullet.FillerMass, Bullet.Owner, nil, Bullet.Gun) - Ammo.BaseClass.OnFlightEnd(self, Index, Bullet, Hitpos) + Ammo.BaseClass.OnFlightEnd(self, Bullet, Trace) end else ACF.RegisterAmmoDecal("APHE", "damage/ap_pen", "damage/ap_rico") From a125412b689f8629a64737019e2cbdee1246df8b Mon Sep 17 00:00:00 2001 From: Stoob Date: Fri, 4 Dec 2020 19:41:29 -0600 Subject: [PATCH 189/279] Moved terminal ballistics functions from damage.lua to ballistics.lua --- lua/acf/server/ballistics.lua | 261 ++++++++++++++++++++++++++++++++++ lua/acf/server/damage.lua | 261 ---------------------------------- 2 files changed, 261 insertions(+), 261 deletions(-) diff --git a/lua/acf/server/ballistics.lua b/lua/acf/server/ballistics.lua index 62dc9cd7d..a0a28728e 100644 --- a/lua/acf/server/ballistics.lua +++ b/lua/acf/server/ballistics.lua @@ -312,6 +312,267 @@ function ACF.DoBulletsFlight(Bullet) end end +do -- Terminal ballistics -------------------------- + local function RicochetVector(Flight, HitNormal) + local Vec = Flight:GetNormalized() + + return Vec - ( 2 * Vec:Dot(HitNormal) ) * HitNormal + end + + function ACF_RoundImpact( Bullet, Speed, Energy, Target, HitPos, HitNormal , Bone ) + local Angle = ACF_GetHitAngle( HitNormal , Bullet.Flight ) + + local HitRes = ACF_Damage ( --DAMAGE !! + Target, + Energy, + Bullet.PenArea, + Angle, + Bullet.Owner, + Bone, + Bullet.Gun, + Bullet.Type + ) + + local Ricochet = 0 + if HitRes.Loss == 1 then + -- Ricochet distribution center + local sigmoidCenter = Bullet.DetonatorAngle or ( Bullet.Ricochet - math.abs(Speed / 39.37 - Bullet.LimitVel) / 100 ) + + -- Ricochet probability (sigmoid distribution); up to 5% minimal ricochet probability for projectiles with caliber < 20 mm + local ricoProb = math.Clamp( 1 / (1 + math.exp( (Angle - sigmoidCenter) / -4) ), math.max(-0.05 * (Bullet.Caliber - 2) / 2, 0), 1 ) + + -- Checking for ricochet + if ricoProb > math.random() and Angle < 90 then + Ricochet = math.Clamp(Angle / 90, 0.05, 1) -- atleast 5% of energy is kept + HitRes.Loss = 0.25 - Ricochet + Energy.Kinetic = Energy.Kinetic * HitRes.Loss + end + end + + if ACF_KEPUSH:GetBool() then + Shove( + Target, + HitPos, + Bullet.Flight:GetNormalized(), + Energy.Kinetic * HitRes.Loss * 1000 * Bullet.ShovePower + ) + end + + if HitRes.Kill then + local Debris = ACF_APKill( Target , (Bullet.Flight):GetNormalized() , Energy.Kinetic ) + table.insert( Bullet.Filter , Debris ) + end + + HitRes.Ricochet = false + + if Ricochet > 0 and Bullet.Ricochets < 3 then + Bullet.Ricochets = Bullet.Ricochets + 1 + Bullet.NextPos = HitPos + Bullet.Flight = (RicochetVector(Bullet.Flight, HitNormal) + VectorRand() * 0.025):GetNormalized() * Speed * Ricochet + + HitRes.Ricochet = true + end + + return HitRes + end + + function ACF_Ricochet(Bullet, Trace) + local Ricochet = 0 + local Speed = Bullet.Flight:Length() / ACF.Scale + local Angle = ACF_GetHitAngle( Trace.HitNormal, Bullet.Flight ) + local MinAngle = math.min(Bullet.Ricochet - Speed / 39.37 / 30 + 20,89.9) --Making the chance of a ricochet get higher as the speeds increase + + if Angle > math.random(MinAngle,90) and Angle < 89.9 then --Checking for ricochet + Ricochet = Angle / 90 * 0.75 + end + + if Ricochet > 0 and Bullet.GroundRicos < 2 then + Bullet.GroundRicos = Bullet.GroundRicos + 1 + Bullet.NextPos = Trace.HitPos + Bullet.Flight = (RicochetVector(Bullet.Flight, Trace.HitNormal) + VectorRand() * 0.05):GetNormalized() * Speed * Ricochet + + print("Ricochet") + return "Ricochet" + end + + return false + end + + local function DigTrace(From, To, Filter) + local Dig = util.TraceHull({ + start = From, + endpos = To, + mask = MASK_NPCSOLID_BRUSHONLY, -- Map and brushes only + mins = Vector(), + maxs = Vector() + }) + + debugoverlay.Line(From, Dig.HitPos, 30, ColorRand(100, 255), true) + + if Dig.StartSolid then -- Started inside solid map volume + if Dig.FractionLeftSolid == 0 then -- Trace could not move inside + local Displacement = To - From + local Normal = Displacement:GetNormalized() + local Length = Displacement:Length() + + local C = math.Round(Length / 12) + local N = Length / C + + for I = 1, C do + local P = From + Normal * I * N + + debugoverlay.Cross(P, 1, 15, Color(255, 255, 0), true) + + local Back = util.TraceHull({ -- Send a trace backwards to hit the other side + start = P, + endpos = From, -- Countering the initial offset position of the dig trace to handle things <1 inch thick + mask = MASK_NPCSOLID_BRUSHONLY, -- Map and brushes only + mins = Vector(), + maxs = Vector() + }) + + if Back.StartSolid or Back.HitNoDraw then continue end + + debugoverlay.Line(P, Back.HitPos, 30, Color(255, 0, 255), true) + return true, Back.HitPos + end + + return false + elseif Dig.FractionLeftSolid == 1 then -- Non-penetration: too thick + return false + else -- Penetrated + if Dig.HitNoDraw then -- Hit a layer inside + return DigTrace(Dig.HitPos + (To - From):GetNormalized() * 0.1, To, Filter) -- Try again + else -- Complete penetration + local Back = util.TraceHull({ + start = Dig.StartPos, + endpos = From, + mask = MASK_NPCSOLID_BRUSHONLY, -- Map and brushes only + mins = Vector(), + maxs = Vector() + }) + + -- False positive, still inside the world + -- Typically occurs when two brushes meet + if Back.StartSolid or Back.HitNoDraw then + return DigTrace(Dig.StartPos + (To - From):GetNormalized() * 0.1, To, Filter) + end + + debugoverlay.Cross(Dig.StartPos, 5, 30, Color(255, 0, 0), true) -- Red cross: Exit point + + return true, Dig.StartPos + end + end + else -- Started inside a brush + local Back = util.TraceHull({ -- Send a trace backwards to hit the other side + start = Dig.HitPos, + endpos = From + (From - Dig.HitPos):GetNormalized(), -- Countering the initial offset position of the dig trace to handle things <1 inch thick + mask = MASK_NPCSOLID_BRUSHONLY, -- Map and brushes only + mins = Vector(), + maxs = Vector() + }) + + local Up = (Dig.HitPos - Back.HitPos):Angle():Up() + debugoverlay.Line(Dig.HitPos + Up, Back.HitPos + Up, 30, Color(255, 0, 160), true) + + if Back.StartSolid then -- object is too thick + return false + elseif not Back.Hit or Back.HitNoDraw then + -- Hit nothing on the way back + -- Map edge, going into the ground, whatever... + -- Effectively infinitely thick + + return false + else -- Penetration + debugoverlay.Cross(Back.HitPos, 5, Color(255, 0, 0), true) -- Red cross: Exit point + + return true, Back.HitPos + end + end + end + + function ACF_PenetrateMapEntity(Bullet, Trace) + print("PenetrateMapEntity") + + local Energy = ACF_Kinetic(Bullet.Flight:Length() / ACF.Scale, Bullet.ProjMass, Bullet.LimitVel) + local Density = util.GetSurfaceData(Trace.SurfaceProps).density / 10000 + local Pen = Energy.Penetration / Bullet.PenArea * ACF.KEtoRHA -- Base RHA penetration of the projectile + local RHAe = Pen / Density -- RHA equivalent thickness of the target material + + local Enter = Trace.HitPos -- Impact point + local Fwd = Bullet.Flight:GetNormalized() + + local PassThrough = util.TraceHull({ + start = Enter, + endpos = Enter + Fwd * RHAe / 25.4, + filter = {Trace.Entity}, + mask = MASK_SOLID_BRUSHONLY + }) + + debugoverlay.Line(PassThrough.StartPos, PassThrough.HitPos, 30, Color(255, 0, 160), true) + + local Filt = {} + local Back + + repeat + Back = util.TraceHull({ + start = PassThrough.HitPos, + endpos = Enter, + filter = Filt + }) + + if Back.HitNonWorld and Back.Entity ~= Trace.Entity then + Filt[#Filt + 1] = Back.Entity + continue + end + + if Back.StartSolid then return ACF_Ricochet(Bullet, Trace) end + until Back.Entity == Trace.Entity + + local Thicc = (Back.HitPos - Enter):Length() * Density * 25.4 -- Obstacle thickness in RHA + + Bullet.Flight = Bullet.Flight * (1 - Thicc / Pen) + Bullet.Pos = Back.HitPos + Fwd * 0.25 + + debugoverlay.Cross(Back.HitPos, 5, 30, Color(255, 0, 0), true) + + return "Penetrated" + --return true, Back.HitPos, Thickness + end + + function ACF_PenetrateGround(Bullet, Trace) + print("ACF_PenetrateGround") + + local Energy = ACF_Kinetic(Bullet.Flight:Length() / ACF.Scale, Bullet.ProjMass, Bullet.LimitVel) + local Density = util.GetSurfaceData(Trace.SurfaceProps).density / 10000 + local Pen = Energy.Penetration / Bullet.PenArea * ACF.KEtoRHA -- Base RHA penetration of the projectile + local RHAe = Pen / Density -- RHA equivalent thickness of the target material + + local Enter = Trace.HitPos -- Impact point + local Fwd = Bullet.Flight:GetNormalized() + + debugoverlay.Cross(Enter, 5, 30, Color(0, 255, 0), true) -- Green cross: entrance point + + local Penetrated, Exit = DigTrace(Enter + Fwd, Enter + Fwd * RHAe / 25.4) + + if Penetrated then + print("Penetrated") + local Thicc = (Exit - Enter):Length() * Density * 25.4 -- RHAe of the material passed through + + print("Pass-through RHAe: " .. math.Round(Thicc)) + debugoverlay.Cross(Exit, 5, 30, Color(255, 0, 0), true) -- Red cross: exit point + + Bullet.Flight = Bullet.Flight * (1 - Thicc / Pen) + Bullet.Pos = Exit + Fwd * 0.25 + --Bullet.NextPos = Exit + Fwd * 0.25 + + return "Penetrated" --, Exit, Thicc + else -- Ricochet + return ACF_Ricochet(Bullet, Trace) + end + end +end + -- Backwards compatibility ACF_BulletClient = ACF.BulletClient ACF_CalcBulletFlight = ACF.CalcBulletFlight diff --git a/lua/acf/server/damage.lua b/lua/acf/server/damage.lua index 8a4c498a1..389d74d8f 100644 --- a/lua/acf/server/damage.lua +++ b/lua/acf/server/damage.lua @@ -628,265 +628,4 @@ do return Debris end end - - do -- Round Impact -------------------------- - local function RicochetVector(Flight, HitNormal) - local Vec = Flight:GetNormalized() - - return Vec - ( 2 * Vec:Dot(HitNormal) ) * HitNormal - end - - function ACF_RoundImpact( Bullet, Speed, Energy, Target, HitPos, HitNormal , Bone ) - local Angle = ACF_GetHitAngle( HitNormal , Bullet.Flight ) - - local HitRes = ACF_Damage ( --DAMAGE !! - Target, - Energy, - Bullet.PenArea, - Angle, - Bullet.Owner, - Bone, - Bullet.Gun, - Bullet.Type - ) - - local Ricochet = 0 - if HitRes.Loss == 1 then - -- Ricochet distribution center - local sigmoidCenter = Bullet.DetonatorAngle or ( Bullet.Ricochet - math.abs(Speed / 39.37 - Bullet.LimitVel) / 100 ) - - -- Ricochet probability (sigmoid distribution); up to 5% minimal ricochet probability for projectiles with caliber < 20 mm - local ricoProb = math.Clamp( 1 / (1 + math.exp( (Angle - sigmoidCenter) / -4) ), math.max(-0.05 * (Bullet.Caliber - 2) / 2, 0), 1 ) - - -- Checking for ricochet - if ricoProb > math.random() and Angle < 90 then - Ricochet = math.Clamp(Angle / 90, 0.05, 1) -- atleast 5% of energy is kept - HitRes.Loss = 0.25 - Ricochet - Energy.Kinetic = Energy.Kinetic * HitRes.Loss - end - end - - if ACF_KEPUSH:GetBool() then - Shove( - Target, - HitPos, - Bullet.Flight:GetNormalized(), - Energy.Kinetic * HitRes.Loss * 1000 * Bullet.ShovePower - ) - end - - if HitRes.Kill then - local Debris = ACF_APKill( Target , (Bullet.Flight):GetNormalized() , Energy.Kinetic ) - table.insert( Bullet.Filter , Debris ) - end - - HitRes.Ricochet = false - - if Ricochet > 0 and Bullet.Ricochets < 3 then - Bullet.Ricochets = Bullet.Ricochets + 1 - Bullet.NextPos = HitPos - Bullet.Flight = (RicochetVector(Bullet.Flight, HitNormal) + VectorRand() * 0.025):GetNormalized() * Speed * Ricochet - - HitRes.Ricochet = true - end - - return HitRes - end - - function ACF_Ricochet(Bullet, Trace) - local Ricochet = 0 - local Speed = Bullet.Flight:Length() / ACF.Scale - local Angle = ACF_GetHitAngle( Trace.HitNormal, Bullet.Flight ) - local MinAngle = math.min(Bullet.Ricochet - Speed / 39.37 / 30 + 20,89.9) --Making the chance of a ricochet get higher as the speeds increase - - if Angle > math.random(MinAngle,90) and Angle < 89.9 then --Checking for ricochet - Ricochet = Angle / 90 * 0.75 - end - - if Ricochet > 0 and Bullet.GroundRicos < 2 then - Bullet.GroundRicos = Bullet.GroundRicos + 1 - Bullet.NextPos = Trace.HitPos - Bullet.Flight = (RicochetVector(Bullet.Flight, Trace.HitNormal) + VectorRand() * 0.05):GetNormalized() * Speed * Ricochet - - print("Ricochet") - return "Ricochet" - end - - return false - end - - local function DigTrace(From, To, Filter) - local Dig = util.TraceHull({ - start = From, - endpos = To, - mask = MASK_NPCSOLID_BRUSHONLY, -- Map and brushes only - mins = Vector(), - maxs = Vector() - }) - - debugoverlay.Line(From, Dig.HitPos, 30, ColorRand(100, 255), true) - - if Dig.StartSolid then -- Started inside solid map volume - if Dig.FractionLeftSolid == 0 then -- Trace could not move inside - local Displacement = To - From - local Normal = Displacement:GetNormalized() - local Length = Displacement:Length() - - local C = math.Round(Length / 12) - local N = Length / C - - for I = 1, C do - local P = From + Normal * I * N - - debugoverlay.Cross(P, 1, 15, Color(255, 255, 0), true) - - local Back = util.TraceHull({ -- Send a trace backwards to hit the other side - start = P, - endpos = From, -- Countering the initial offset position of the dig trace to handle things <1 inch thick - mask = MASK_NPCSOLID_BRUSHONLY, -- Map and brushes only - mins = Vector(), - maxs = Vector() - }) - - if Back.StartSolid or Back.HitNoDraw then continue end - - debugoverlay.Line(P, Back.HitPos, 30, Color(255, 0, 255), true) - return true, Back.HitPos - end - - return false - elseif Dig.FractionLeftSolid == 1 then -- Non-penetration: too thick - return false - else -- Penetrated - if Dig.HitNoDraw then -- Hit a layer inside - return DigTrace(Dig.HitPos + (To - From):GetNormalized() * 0.1, To, Filter) -- Try again - else -- Complete penetration - local Back = util.TraceHull({ - start = Dig.StartPos, - endpos = From, - mask = MASK_NPCSOLID_BRUSHONLY, -- Map and brushes only - mins = Vector(), - maxs = Vector() - }) - - -- False positive, still inside the world - -- Typically occurs when two brushes meet - if Back.StartSolid or Back.HitNoDraw then - return DigTrace(Dig.StartPos + (To - From):GetNormalized() * 0.1, To, Filter) - end - - debugoverlay.Cross(Dig.StartPos, 5, 30, Color(255, 0, 0), true) -- Red cross: Exit point - - return true, Dig.StartPos - end - end - else -- Started inside a brush - local Back = util.TraceHull({ -- Send a trace backwards to hit the other side - start = Dig.HitPos, - endpos = From + (From - Dig.HitPos):GetNormalized(), -- Countering the initial offset position of the dig trace to handle things <1 inch thick - mask = MASK_NPCSOLID_BRUSHONLY, -- Map and brushes only - mins = Vector(), - maxs = Vector() - }) - - local Up = (Dig.HitPos - Back.HitPos):Angle():Up() - debugoverlay.Line(Dig.HitPos + Up, Back.HitPos + Up, 30, Color(255, 0, 160), true) - - if Back.StartSolid then -- object is too thick - return false - elseif not Back.Hit or Back.HitNoDraw then - -- Hit nothing on the way back - -- Map edge, going into the ground, whatever... - -- Effectively infinitely thick - - return false - else -- Penetration - debugoverlay.Cross(Back.HitPos, 5, Color(255, 0, 0), true) -- Red cross: Exit point - - return true, Back.HitPos - end - end - end - - function ACF_PenetrateMapEntity(Bullet, Trace) - print("PenetrateMapEntity") - - local Energy = ACF_Kinetic(Bullet.Flight:Length() / ACF.Scale, Bullet.ProjMass, Bullet.LimitVel) - local Density = util.GetSurfaceData(Trace.SurfaceProps).density / 10000 - local Pen = Energy.Penetration / Bullet.PenArea * ACF.KEtoRHA -- Base RHA penetration of the projectile - local RHAe = Pen / Density -- RHA equivalent thickness of the target material - - local Enter = Trace.HitPos -- Impact point - local Fwd = Bullet.Flight:GetNormalized() - - local PassThrough = util.TraceHull({ - start = Enter, - endpos = Enter + Fwd * RHAe / 25.4, - filter = {Trace.Entity}, - mask = MASK_SOLID_BRUSHONLY - }) - - debugoverlay.Line(PassThrough.StartPos, PassThrough.HitPos, 30, Color(255, 0, 160), true) - - local Filt = {} - local Back - - repeat - Back = util.TraceHull({ - start = PassThrough.HitPos, - endpos = Enter, - filter = Filt - }) - - if Back.HitNonWorld and Back.Entity ~= Trace.Entity then - Filt[#Filt + 1] = Back.Entity - continue - end - - if Back.StartSolid then return ACF_Ricochet(Bullet, Trace) end - until Back.Entity == Trace.Entity - - local Thicc = (Back.HitPos - Enter):Length() * Density * 25.4 -- Obstacle thickness in RHA - - Bullet.Flight = Bullet.Flight * (1 - Thicc / Pen) - Bullet.Pos = Back.HitPos + Fwd * 0.25 - - debugoverlay.Cross(Back.HitPos, 5, 30, Color(255, 0, 0), true) - - return "Penetrated" - --return true, Back.HitPos, Thickness - end - - function ACF_PenetrateGround(Bullet, Trace) - print("ACF_PenetrateGround") - - local Energy = ACF_Kinetic(Bullet.Flight:Length() / ACF.Scale, Bullet.ProjMass, Bullet.LimitVel) - local Density = util.GetSurfaceData(Trace.SurfaceProps).density / 10000 - local Pen = Energy.Penetration / Bullet.PenArea * ACF.KEtoRHA -- Base RHA penetration of the projectile - local RHAe = Pen / Density -- RHA equivalent thickness of the target material - - local Enter = Trace.HitPos -- Impact point - local Fwd = Bullet.Flight:GetNormalized() - - debugoverlay.Cross(Enter, 5, 30, Color(0, 255, 0), true) -- Green cross: entrance point - - local Penetrated, Exit = DigTrace(Enter + Fwd, Enter + Fwd * RHAe / 25.4) - - if Penetrated then - print("Penetrated") - local Thicc = (Exit - Enter):Length() * Density * 25.4 -- RHAe of the material passed through - - print("Pass-through RHAe: " .. math.Round(Thicc)) - debugoverlay.Cross(Exit, 5, 30, Color(255, 0, 0), true) -- Red cross: exit point - - Bullet.Flight = Bullet.Flight * (1 - Thicc / Pen) - Bullet.Pos = Exit + Fwd * 0.25 - --Bullet.NextPos = Exit + Fwd * 0.25 - - return "Penetrated" --, Exit, Thicc - else -- Ricochet - return ACF_Ricochet(Bullet, Trace) - end - end - end end From 191c019ea4d83804023c40068024f11012673781 Mon Sep 17 00:00:00 2001 From: Stoob Date: Fri, 4 Dec 2020 20:46:25 -0600 Subject: [PATCH 190/279] Tweak RHAe scaling and added variability Reduced world RHAe by a little over half and added 20% density RNG --- lua/acf/server/ballistics.lua | 9 +++++---- lua/acf/server/damage.lua | 1 - 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lua/acf/server/ballistics.lua b/lua/acf/server/ballistics.lua index a0a28728e..10b466d59 100644 --- a/lua/acf/server/ballistics.lua +++ b/lua/acf/server/ballistics.lua @@ -15,6 +15,7 @@ local GlobalFilter = ACF.GlobalFilter local AmmoTypes = ACF.Classes.AmmoTypes local Gravity = Vector(0, 0, -GetConVar("sv_gravity"):GetInt()) local HookRun = hook.Run +local ACF_KEPUSH = GetConVar("acf_kepush") cvars.AddChangeCallback("sv_gravity", function(_, _, Value) Gravity.z = -Value @@ -495,9 +496,9 @@ do -- Terminal ballistics -------------------------- print("PenetrateMapEntity") local Energy = ACF_Kinetic(Bullet.Flight:Length() / ACF.Scale, Bullet.ProjMass, Bullet.LimitVel) - local Density = util.GetSurfaceData(Trace.SurfaceProps).density / 10000 + local Density = (util.GetSurfaceData(Trace.SurfaceProps).density * 0.5 * math.Rand(0.9, 1.1)) ^ 0.9 / 10000 local Pen = Energy.Penetration / Bullet.PenArea * ACF.KEtoRHA -- Base RHA penetration of the projectile - local RHAe = Pen / Density -- RHA equivalent thickness of the target material + local RHAe = math.max(Pen / Density, 1) -- RHA equivalent thickness of the target material local Enter = Trace.HitPos -- Impact point local Fwd = Bullet.Flight:GetNormalized() @@ -544,9 +545,9 @@ do -- Terminal ballistics -------------------------- print("ACF_PenetrateGround") local Energy = ACF_Kinetic(Bullet.Flight:Length() / ACF.Scale, Bullet.ProjMass, Bullet.LimitVel) - local Density = util.GetSurfaceData(Trace.SurfaceProps).density / 10000 + local Density = (util.GetSurfaceData(Trace.SurfaceProps).density * 0.5 * math.Rand(0.9, 1.1)) ^ 0.9 / 10000 local Pen = Energy.Penetration / Bullet.PenArea * ACF.KEtoRHA -- Base RHA penetration of the projectile - local RHAe = Pen / Density -- RHA equivalent thickness of the target material + local RHAe = math.max(Pen / Density, 1) -- RHA equivalent thickness of the target material local Enter = Trace.HitPos -- Impact point local Fwd = Bullet.Flight:GetNormalized() diff --git a/lua/acf/server/damage.lua b/lua/acf/server/damage.lua index 389d74d8f..304b24bb0 100644 --- a/lua/acf/server/damage.lua +++ b/lua/acf/server/damage.lua @@ -1,7 +1,6 @@ -- Local Vars ----------------------------------- local ACF = ACF local ACF_HEPUSH = GetConVar("acf_hepush") -local ACF_KEPUSH = GetConVar("acf_kepush") local TimerCreate = timer.Create local TraceRes = {} local TraceData = { output = TraceRes, mask = MASK_SOLID, filter = false } From 9d1b3f1ec6dd5c13a76b681c8ed517b5bfa98af6 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Mon, 7 Dec 2020 13:45:41 -0300 Subject: [PATCH 191/279] Readded APCR to HMGs - HMGs will be able to load APCR ammo again. --- lua/acf/shared/ammo_types/apcr.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/lua/acf/shared/ammo_types/apcr.lua b/lua/acf/shared/ammo_types/apcr.lua index 1e330cf36..4d5d91af0 100644 --- a/lua/acf/shared/ammo_types/apcr.lua +++ b/lua/acf/shared/ammo_types/apcr.lua @@ -11,6 +11,7 @@ function Ammo:OnLoaded() AC = true, SA = true, SC = true, + HMG = true, RAC = true, }) end From 4139746b08bb16fe7cc6f6c464eec11981d0394f Mon Sep 17 00:00:00 2001 From: Stoob Date: Tue, 8 Dec 2020 20:44:41 -0600 Subject: [PATCH 192/279] Fixed projectiles retaining velocity for one tick after penetration --- lua/acf/server/ballistics.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lua/acf/server/ballistics.lua b/lua/acf/server/ballistics.lua index 10b466d59..f007dd78b 100644 --- a/lua/acf/server/ballistics.lua +++ b/lua/acf/server/ballistics.lua @@ -557,15 +557,15 @@ do -- Terminal ballistics -------------------------- local Penetrated, Exit = DigTrace(Enter + Fwd, Enter + Fwd * RHAe / 25.4) if Penetrated then - print("Penetrated") - local Thicc = (Exit - Enter):Length() * Density * 25.4 -- RHAe of the material passed through + local Thicc = (Exit - Enter):Length() * Density * 25.4 -- RHAe of the material passed through + local DeltaTime = engine.TickInterval() print("Pass-through RHAe: " .. math.Round(Thicc)) debugoverlay.Cross(Exit, 5, 30, Color(255, 0, 0), true) -- Red cross: exit point Bullet.Flight = Bullet.Flight * (1 - Thicc / Pen) Bullet.Pos = Exit + Fwd * 0.25 - --Bullet.NextPos = Exit + Fwd * 0.25 + Bullet.NextPos = Exit + Bullet.Flight * ACF.Scale * DeltaTime return "Penetrated" --, Exit, Thicc else -- Ricochet From af2a83d34e25a4b6b6cbbae92c32e9a737b1428b Mon Sep 17 00:00:00 2001 From: Stoob Date: Tue, 8 Dec 2020 20:44:54 -0600 Subject: [PATCH 193/279] Removed debugging elements --- lua/acf/server/ballistics.lua | 31 ++----------------------------- 1 file changed, 2 insertions(+), 29 deletions(-) diff --git a/lua/acf/server/ballistics.lua b/lua/acf/server/ballistics.lua index f007dd78b..3790d8246 100644 --- a/lua/acf/server/ballistics.lua +++ b/lua/acf/server/ballistics.lua @@ -288,8 +288,6 @@ function ACF.DoBulletsFlight(Bullet) if FlightRes.Hit and Lerp < FlightRes.Fraction or true then -- Fuze went off before running into something local Pos = LerpVector(DeltaFuze / DeltaTime, Bullet.Pos, Bullet.NextPos) - debugoverlay.Line(Bullet.Pos, Bullet.NextPos, 5, Color( 0, 255, 0 )) - ACF.BulletClient(Bullet, "Update", 1, Pos) AmmoTypes[Bullet.Type]:OnFlightEnd(Bullet, Pos, Bullet.Flight:GetNormalized()) @@ -392,7 +390,6 @@ do -- Terminal ballistics -------------------------- Bullet.NextPos = Trace.HitPos Bullet.Flight = (RicochetVector(Bullet.Flight, Trace.HitNormal) + VectorRand() * 0.05):GetNormalized() * Speed * Ricochet - print("Ricochet") return "Ricochet" end @@ -408,7 +405,7 @@ do -- Terminal ballistics -------------------------- maxs = Vector() }) - debugoverlay.Line(From, Dig.HitPos, 30, ColorRand(100, 255), true) + debugoverlay.Line(From, Dig.StartPos, 30, ColorRand(100, 255), true) if Dig.StartSolid then -- Started inside solid map volume if Dig.FractionLeftSolid == 0 then -- Trace could not move inside @@ -422,8 +419,6 @@ do -- Terminal ballistics -------------------------- for I = 1, C do local P = From + Normal * I * N - debugoverlay.Cross(P, 1, 15, Color(255, 255, 0), true) - local Back = util.TraceHull({ -- Send a trace backwards to hit the other side start = P, endpos = From, -- Countering the initial offset position of the dig trace to handle things <1 inch thick @@ -434,7 +429,6 @@ do -- Terminal ballistics -------------------------- if Back.StartSolid or Back.HitNoDraw then continue end - debugoverlay.Line(P, Back.HitPos, 30, Color(255, 0, 255), true) return true, Back.HitPos end @@ -459,8 +453,6 @@ do -- Terminal ballistics -------------------------- return DigTrace(Dig.StartPos + (To - From):GetNormalized() * 0.1, To, Filter) end - debugoverlay.Cross(Dig.StartPos, 5, 30, Color(255, 0, 0), true) -- Red cross: Exit point - return true, Dig.StartPos end end @@ -473,9 +465,6 @@ do -- Terminal ballistics -------------------------- maxs = Vector() }) - local Up = (Dig.HitPos - Back.HitPos):Angle():Up() - debugoverlay.Line(Dig.HitPos + Up, Back.HitPos + Up, 30, Color(255, 0, 160), true) - if Back.StartSolid then -- object is too thick return false elseif not Back.Hit or Back.HitNoDraw then @@ -485,16 +474,12 @@ do -- Terminal ballistics -------------------------- return false else -- Penetration - debugoverlay.Cross(Back.HitPos, 5, Color(255, 0, 0), true) -- Red cross: Exit point - return true, Back.HitPos end end end function ACF_PenetrateMapEntity(Bullet, Trace) - print("PenetrateMapEntity") - local Energy = ACF_Kinetic(Bullet.Flight:Length() / ACF.Scale, Bullet.ProjMass, Bullet.LimitVel) local Density = (util.GetSurfaceData(Trace.SurfaceProps).density * 0.5 * math.Rand(0.9, 1.1)) ^ 0.9 / 10000 local Pen = Energy.Penetration / Bullet.PenArea * ACF.KEtoRHA -- Base RHA penetration of the projectile @@ -510,8 +495,6 @@ do -- Terminal ballistics -------------------------- mask = MASK_SOLID_BRUSHONLY }) - debugoverlay.Line(PassThrough.StartPos, PassThrough.HitPos, 30, Color(255, 0, 160), true) - local Filt = {} local Back @@ -535,15 +518,10 @@ do -- Terminal ballistics -------------------------- Bullet.Flight = Bullet.Flight * (1 - Thicc / Pen) Bullet.Pos = Back.HitPos + Fwd * 0.25 - debugoverlay.Cross(Back.HitPos, 5, 30, Color(255, 0, 0), true) - return "Penetrated" - --return true, Back.HitPos, Thickness end function ACF_PenetrateGround(Bullet, Trace) - print("ACF_PenetrateGround") - local Energy = ACF_Kinetic(Bullet.Flight:Length() / ACF.Scale, Bullet.ProjMass, Bullet.LimitVel) local Density = (util.GetSurfaceData(Trace.SurfaceProps).density * 0.5 * math.Rand(0.9, 1.1)) ^ 0.9 / 10000 local Pen = Energy.Penetration / Bullet.PenArea * ACF.KEtoRHA -- Base RHA penetration of the projectile @@ -552,22 +530,17 @@ do -- Terminal ballistics -------------------------- local Enter = Trace.HitPos -- Impact point local Fwd = Bullet.Flight:GetNormalized() - debugoverlay.Cross(Enter, 5, 30, Color(0, 255, 0), true) -- Green cross: entrance point - local Penetrated, Exit = DigTrace(Enter + Fwd, Enter + Fwd * RHAe / 25.4) if Penetrated then local Thicc = (Exit - Enter):Length() * Density * 25.4 -- RHAe of the material passed through local DeltaTime = engine.TickInterval() - print("Pass-through RHAe: " .. math.Round(Thicc)) - debugoverlay.Cross(Exit, 5, 30, Color(255, 0, 0), true) -- Red cross: exit point - Bullet.Flight = Bullet.Flight * (1 - Thicc / Pen) Bullet.Pos = Exit + Fwd * 0.25 Bullet.NextPos = Exit + Bullet.Flight * ACF.Scale * DeltaTime - return "Penetrated" --, Exit, Thicc + return "Penetrated" else -- Ricochet return ACF_Ricochet(Bullet, Trace) end From 38bf70c832877fa535b856f14eb14f85aa2dc1f8 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Wed, 9 Dec 2020 05:10:20 -0300 Subject: [PATCH 194/279] Fixed some conflicts from the worldpen branch merge - ACF.RemoveBullet will now mark the bullets with the Bullet.Removed flag. - Reapplied fixes to the timed fuze detonation. - Replaced the names on some variables to make the linter happy again. - Reapplied changes to ENT:ACF_OnDamage. - Reapplied some changes on AP ammo creation and networking. - Fixed Ammo:PropImpact using the wrong arguments on AP, HE, HEAT and SM ammo. - Fixed Ammo:WorldImpact using the wrong arguments on HEAT ammo. --- lua/acf/server/ballistics.lua | 62 ++++++++++++++++------------- lua/acf/server/damage.lua | 2 +- lua/acf/shared/ammo_types/ap.lua | 11 ++--- lua/acf/shared/ammo_types/aphe.lua | 2 +- lua/acf/shared/ammo_types/he.lua | 6 ++- lua/acf/shared/ammo_types/heat.lua | 16 +++++--- lua/acf/shared/ammo_types/smoke.lua | 6 ++- 7 files changed, 62 insertions(+), 43 deletions(-) diff --git a/lua/acf/server/ballistics.lua b/lua/acf/server/ballistics.lua index 3790d8246..ce6a9f43c 100644 --- a/lua/acf/server/ballistics.lua +++ b/lua/acf/server/ballistics.lua @@ -88,15 +88,19 @@ function ACF.BulletClient(Bullet, Type, Hit, HitPos) end function ACF.RemoveBullet(Bullet) + if Bullet.Removed then return end + local Index = Bullet.Index Bullets[Index] = nil Unused[Index] = true - if Bullet and Bullet.OnRemoved then + if Bullet.OnRemoved then Bullet:OnRemoved() end + Bullet.Removed = true + if not next(Bullets) then hook.Remove("Tick", "IterateBullets") end @@ -186,10 +190,9 @@ function ACF.CreateBullet(BulletData) return Bullet end -local function OnImpact(Bullet, Trace, Type) - local Data = AmmoTypes[Bullet.Type] - local Func = Type == "World" and Data.WorldImpact or Data.PropImpact - local Retry = Func(Data, Bullet, Trace) +local function OnImpact(Bullet, Trace, Ammo, Type) + local Func = Type == "World" and Ammo.WorldImpact or Ammo.PropImpact + local Retry = Func(Ammo, Bullet, Trace) if Retry == "Penetrated" then if Bullet.OnPenetrated then @@ -211,7 +214,7 @@ local function OnImpact(Bullet, Trace, Type) ACF.BulletClient(Bullet, "Update", 1, Trace.HitPos) - Data:OnFlightEnd(Bullet, Trace) + Ammo:OnFlightEnd(Bullet, Trace) end end @@ -273,24 +276,28 @@ function ACF.DoBulletsFlight(Bullet) Bullet.Filter = Filter end + local Ammo = AmmoTypes[Bullet.Type] + if Bullet.Fuze and Bullet.Fuze <= ACF.CurTime then if not util.IsInWorld(Bullet.Pos) then -- Outside world, just delete - return ACF.RemoveBullet(Bullet.Index) + return ACF.RemoveBullet(Bullet) else - if Bullet.OnEndFlight then - Bullet.OnEndFlight(Bullet, nil) - end - local DeltaTime = Bullet.DeltaTime local DeltaFuze = ACF.CurTime - Bullet.Fuze local Lerp = DeltaFuze / DeltaTime - --print(DeltaTime, DeltaFuze, Lerp) - if FlightRes.Hit and Lerp < FlightRes.Fraction or true then -- Fuze went off before running into something - local Pos = LerpVector(DeltaFuze / DeltaTime, Bullet.Pos, Bullet.NextPos) + + if not FlightRes.Hit or Lerp < FlightRes.Fraction then -- Fuze went off before running into something + local Pos = LerpVector(Lerp, Bullet.Pos, Bullet.NextPos) + + if Bullet.OnEndFlight then + Bullet.OnEndFlight(Bullet, FlightRes) + end ACF.BulletClient(Bullet, "Update", 1, Pos) - AmmoTypes[Bullet.Type]:OnFlightEnd(Bullet, Pos, Bullet.Flight:GetNormalized()) + Ammo:OnFlightEnd(Bullet, FlightRes) + + return end end end @@ -306,7 +313,7 @@ function ACF.DoBulletsFlight(Bullet) else local Type = (FlightRes.HitWorld or FlightRes.Entity:CPPIGetOwner() == game.GetWorld()) and "World" or "Prop" - OnImpact(Bullet, FlightRes, Type) + OnImpact(Bullet, FlightRes, Ammo, Type) end end end @@ -315,17 +322,17 @@ do -- Terminal ballistics -------------------------- local function RicochetVector(Flight, HitNormal) local Vec = Flight:GetNormalized() - return Vec - ( 2 * Vec:Dot(HitNormal) ) * HitNormal + return Vec - (2 * Vec:Dot(HitNormal)) * HitNormal end - function ACF_RoundImpact( Bullet, Speed, Energy, Target, HitPos, HitNormal , Bone ) - local Angle = ACF_GetHitAngle( HitNormal , Bullet.Flight ) + function ACF_RoundImpact(Bullet, Speed, Energy, Target, HitPos, HitNormal, Bone) + local HitAngle = ACF_GetHitAngle(HitNormal , Bullet.Flight) local HitRes = ACF_Damage ( --DAMAGE !! Target, Energy, Bullet.PenArea, - Angle, + HitAngle, Bullet.Owner, Bone, Bullet.Gun, @@ -335,10 +342,10 @@ do -- Terminal ballistics -------------------------- local Ricochet = 0 if HitRes.Loss == 1 then -- Ricochet distribution center - local sigmoidCenter = Bullet.DetonatorAngle or ( Bullet.Ricochet - math.abs(Speed / 39.37 - Bullet.LimitVel) / 100 ) + local sigmoidCenter = Bullet.DetonatorAngle or (Bullet.Ricochet - math.abs(Speed / 39.37 - Bullet.LimitVel) / 100) -- Ricochet probability (sigmoid distribution); up to 5% minimal ricochet probability for projectiles with caliber < 20 mm - local ricoProb = math.Clamp( 1 / (1 + math.exp( (Angle - sigmoidCenter) / -4) ), math.max(-0.05 * (Bullet.Caliber - 2) / 2, 0), 1 ) + local ricoProb = math.Clamp(1 / (1 + math.exp((Angle - sigmoidCenter) / -4)), math.max(-0.05 * (Bullet.Caliber - 2) / 2, 0), 1) -- Checking for ricochet if ricoProb > math.random() and Angle < 90 then @@ -358,8 +365,9 @@ do -- Terminal ballistics -------------------------- end if HitRes.Kill then - local Debris = ACF_APKill( Target , (Bullet.Flight):GetNormalized() , Energy.Kinetic ) - table.insert( Bullet.Filter , Debris ) + local Debris = ACF_APKill(Target, Bullet.Flight:GetNormalized() , Energy.Kinetic) + + table.insert(Bullet.Filter , Debris) end HitRes.Ricochet = false @@ -378,11 +386,11 @@ do -- Terminal ballistics -------------------------- function ACF_Ricochet(Bullet, Trace) local Ricochet = 0 local Speed = Bullet.Flight:Length() / ACF.Scale - local Angle = ACF_GetHitAngle( Trace.HitNormal, Bullet.Flight ) + local HitAngle = ACF_GetHitAngle(Trace.HitNormal, Bullet.Flight) local MinAngle = math.min(Bullet.Ricochet - Speed / 39.37 / 30 + 20,89.9) --Making the chance of a ricochet get higher as the speeds increase - if Angle > math.random(MinAngle,90) and Angle < 89.9 then --Checking for ricochet - Ricochet = Angle / 90 * 0.75 + if HitAngle > math.random(MinAngle,90) and Angle < 89.9 then --Checking for ricochet + Ricochet = HitAngle / 90 * 0.75 end if Ricochet > 0 and Bullet.GroundRicos < 2 then diff --git a/lua/acf/server/damage.lua b/lua/acf/server/damage.lua index 304b24bb0..edaa41654 100644 --- a/lua/acf/server/damage.lua +++ b/lua/acf/server/damage.lua @@ -493,7 +493,7 @@ do end if Entity.ACF_OnDamage then -- Use special damage function if target entity has one - return Entity:ACF_OnDamage(Entity, Energy, FrArea, Angle, Inflictor, Bone, Type) + return Entity:ACF_OnDamage(Energy, FrArea, Angle, Inflictor, Bone, Type) elseif Activated == "Prop" then return PropDamage(Entity, Energy, FrArea, Angle, Inflictor, Bone) elseif Activated == "Vehicle" then diff --git a/lua/acf/shared/ammo_types/ap.lua b/lua/acf/shared/ammo_types/ap.lua index c79d194ab..481413757 100644 --- a/lua/acf/shared/ammo_types/ap.lua +++ b/lua/acf/shared/ammo_types/ap.lua @@ -89,7 +89,7 @@ if SERVER then end function Ammo:Create(_, BulletData) - ACF_CreateBullet(BulletData) + ACF.CreateBullet(BulletData) end function Ammo:ServerConvert(ToolData) @@ -105,7 +105,6 @@ if SERVER then function Ammo:Network(Entity, BulletData) Entity:SetNW2String("AmmoType", "AP") - Entity:SetNW2String("AmmoID", BulletData.Id) Entity:SetNW2Float("Caliber", BulletData.Caliber) Entity:SetNW2Float("ProjMass", BulletData.ProjMass) Entity:SetNW2Float("PropMass", BulletData.PropMass) @@ -123,11 +122,13 @@ if SERVER then return Text:format(math.Round(BulletData.MuzzleVel, 2), math.Round(Data.MaxPen, 2)) end - function Ammo:PropImpact(Bullet, Target, HitNormal, HitPos, Bone) + function Ammo:PropImpact(Bullet, Trace) + local Target = Trace.Entity + if ACF_Check(Target) then local Speed = Bullet.Flight:Length() / ACF.Scale local Energy = ACF_Kinetic(Speed, Bullet.ProjMass, Bullet.LimitVel) - local HitRes = ACF_RoundImpact(Bullet, Speed, Energy, Target, HitPos, HitNormal, Bone) + local HitRes = ACF_RoundImpact(Bullet, Speed, Energy, Target, Trace.HitPos, Trace.HitNormal, Trace.HitGroup) if HitRes.Overkill > 0 then table.insert(Bullet.Filter, Target) --"Penetrate" (Ingoring the prop for the retry trace) @@ -147,7 +148,7 @@ if SERVER then end end - function Ammo:WorldImpact(Bullet, Trace) + function Ammo:WorldImpact(Bullet, Trace) if IsValid(Trace.Entity) then return ACF_PenetrateMapEntity(Bullet, Trace) else diff --git a/lua/acf/shared/ammo_types/aphe.lua b/lua/acf/shared/ammo_types/aphe.lua index 721885b9a..cbeb3d771 100644 --- a/lua/acf/shared/ammo_types/aphe.lua +++ b/lua/acf/shared/ammo_types/aphe.lua @@ -110,7 +110,7 @@ if SERVER then return Text:format(math.Round(Data.BlastRadius, 2), math.Round(BulletData.FillerMass * ACF.HEPower, 2)) end - function Ammo:OnFlightEnd( Bullet, Trace) + function Ammo:OnFlightEnd(Bullet, Trace) ACF_HE(Trace.HitPos, Bullet.FillerMass, Bullet.ProjMass - Bullet.FillerMass, Bullet.Owner, nil, Bullet.Gun) Ammo.BaseClass.OnFlightEnd(self, Bullet, Trace) diff --git a/lua/acf/shared/ammo_types/he.lua b/lua/acf/shared/ammo_types/he.lua index 452493cf1..34c6e4e51 100644 --- a/lua/acf/shared/ammo_types/he.lua +++ b/lua/acf/shared/ammo_types/he.lua @@ -88,11 +88,13 @@ if SERVER then return Text:format(math.Round(BulletData.MuzzleVel, 2), math.Round(Data.BlastRadius, 2), math.Round(BulletData.FillerMass * ACF.HEPower, 2)) end - function Ammo:PropImpact(_, Bullet, Target, HitNormal, HitPos, Bone) + function Ammo:PropImpact(Bullet, Trace) + local Target = Trace.Entity + if ACF_Check(Target) then local Speed = Bullet.Flight:Length() / ACF.Scale local Energy = ACF_Kinetic(Speed, Bullet.ProjMass - Bullet.FillerMass, Bullet.LimitVel) - local HitRes = ACF_RoundImpact(Bullet, Speed, Energy, Target, HitPos, HitNormal, Bone) + local HitRes = ACF_RoundImpact(Bullet, Speed, Energy, Target, Trace.HitPos, Trace.HitNormal, Trace.HitGroup) if HitRes.Ricochet then return "Ricochet" end end diff --git a/lua/acf/shared/ammo_types/heat.lua b/lua/acf/shared/ammo_types/heat.lua index 7c325f517..ef3bef48d 100644 --- a/lua/acf/shared/ammo_types/heat.lua +++ b/lua/acf/shared/ammo_types/heat.lua @@ -200,9 +200,14 @@ if SERVER then return true end - function Ammo:PropImpact(_, Bullet, Target, HitNormal, HitPos, Bone) + function Ammo:PropImpact(Bullet, Trace) + local Target = Trace.Target + if ACF_Check(Target) then local Speed = Bullet.Flight:Length() / ACF.Scale + local HitPos = Trace.HitPos + local HitNormal = Trace.HitNormal + local Bone = Trace.HitGroup if Bullet.Detonated then Bullet.NotFirstPen = true @@ -242,17 +247,17 @@ if SERVER then return false end - function Ammo:WorldImpact(_, Bullet, HitPos, HitNormal) + function Ammo:WorldImpact(Bullet, Trace) if not Bullet.Detonated then - if self:Detonate(Bullet, HitPos) then + if self:Detonate(Bullet, Trace.HitPos) then return "Penetrated" else return false end end - local Energy = ACF_Kinetic(Bullet.Flight:Length() / ACF.Scale, Bullet.ProjMass, 999999) - local HitRes = ACF_PenetrateGround(Bullet, Energy, HitPos, HitNormal) + local Function = IsValid(Trace.Entity) and ACF_PenetrateMapEntity or ACF_PenetrateGround + local HitRes = Function(Bullet, Trace) if HitRes.Penetrated then return "Penetrated" @@ -286,6 +291,7 @@ else util.Effect("ACF_HEAT_Explosion", Data) Bullet.Detonated = true + Bullet.LimitVel = 999999 Effect:SetModel("models/Gibs/wood_gib01e.mdl") end diff --git a/lua/acf/shared/ammo_types/smoke.lua b/lua/acf/shared/ammo_types/smoke.lua index 21d2e342f..660cc1b83 100644 --- a/lua/acf/shared/ammo_types/smoke.lua +++ b/lua/acf/shared/ammo_types/smoke.lua @@ -153,11 +153,13 @@ if SERVER then return Text:format(math.Round(BulletData.MuzzleVel, 2), WPText, SMText) end - function Ammo:PropImpact(_, Bullet, Target, HitNormal, HitPos, Bone) + function Ammo:PropImpact(Bullet, Trace) + local Target = Trace.Entity + if ACF_Check(Target) then local Speed = Bullet.Flight:Length() / ACF.Scale local Energy = ACF_Kinetic(Speed, Bullet.ProjMass - (Bullet.FillerMass + Bullet.WPMass), Bullet.LimitVel) - local HitRes = ACF_RoundImpact(Bullet, Speed, Energy, Target, HitPos, HitNormal, Bone) + local HitRes = ACF_RoundImpact(Bullet, Speed, Energy, Target, Trace.HitPos, Trace.HitNormal, Trace.HitGroup) if HitRes.Ricochet then return "Ricochet" end end From d6ebb45239439cf31512aedecfdfbf6e381b4dec Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Wed, 9 Dec 2020 05:37:36 -0300 Subject: [PATCH 195/279] Fixed typo and HEAT world penetration - Fixed typo inside ACF_Ricochet - Fixed Ammo:WorldImpact not working as intended inside HEAT ammunition. --- lua/acf/server/ballistics.lua | 2 +- lua/acf/shared/ammo_types/heat.lua | 7 +------ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/lua/acf/server/ballistics.lua b/lua/acf/server/ballistics.lua index ce6a9f43c..26f5f8fc9 100644 --- a/lua/acf/server/ballistics.lua +++ b/lua/acf/server/ballistics.lua @@ -389,7 +389,7 @@ do -- Terminal ballistics -------------------------- local HitAngle = ACF_GetHitAngle(Trace.HitNormal, Bullet.Flight) local MinAngle = math.min(Bullet.Ricochet - Speed / 39.37 / 30 + 20,89.9) --Making the chance of a ricochet get higher as the speeds increase - if HitAngle > math.random(MinAngle,90) and Angle < 89.9 then --Checking for ricochet + if HitAngle > math.random(MinAngle,90) and HitAngle < 89.9 then --Checking for ricochet Ricochet = HitAngle / 90 * 0.75 end diff --git a/lua/acf/shared/ammo_types/heat.lua b/lua/acf/shared/ammo_types/heat.lua index ef3bef48d..34a010731 100644 --- a/lua/acf/shared/ammo_types/heat.lua +++ b/lua/acf/shared/ammo_types/heat.lua @@ -257,13 +257,8 @@ if SERVER then end local Function = IsValid(Trace.Entity) and ACF_PenetrateMapEntity or ACF_PenetrateGround - local HitRes = Function(Bullet, Trace) - if HitRes.Penetrated then - return "Penetrated" - else - return false - end + return Function(Bullet, Trace) end else ACF.RegisterAmmoDecal("HEAT", "damage/heat_pen", "damage/heat_rico", function(Caliber) return Caliber * 0.1667 end) From 1be132fab036b85de851e6999f0d1a353e5ca7d6 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Wed, 9 Dec 2020 05:40:10 -0300 Subject: [PATCH 196/279] Improved ACF.CreateEntity - ACF.CreateEntity will no longer try to drop the entity to the floor if successfully created. That behavior was moved to the ACF Menu spawn action. - ACF.CreateEntity will now use ENT.Name for the undo registration. --- lua/acf/base/sh_classes.lua | 8 ++++---- lua/acf/shared/tool_operations/acf_menu.lua | 9 +++++++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/lua/acf/base/sh_classes.lua b/lua/acf/base/sh_classes.lua index bf2e5bcef..7a3d9751e 100644 --- a/lua/acf/base/sh_classes.lua +++ b/lua/acf/base/sh_classes.lua @@ -521,16 +521,16 @@ do -- Entity class registration function return false end - local Entity = ClassData.Spawn(Player, Position, Angles, Data) - local PhysObj = Entity:GetPhysicsObject() + local Entity = ClassData.Spawn(Player, Position, Angles, Data) if not IsValid(Entity) then SendMessage(Player, "Error", Class, " entity couldn't be created.") return false end + local PhysObj = Entity:GetPhysicsObject() + Entity:Activate() - Entity:DropToFloor() if CPPI then Entity:CPPISetOwner(Player) @@ -541,7 +541,7 @@ do -- Entity class registration function end if not NoUndo then - undo.Create(Entity.EntType or Class) + undo.Create(Entity.Name or Class) undo.AddEntity(Entity) undo.SetPlayer(Player) undo.Finish() diff --git a/lua/acf/shared/tool_operations/acf_menu.lua b/lua/acf/shared/tool_operations/acf_menu.lua index dc7fbdacf..4abce7b7a 100644 --- a/lua/acf/shared/tool_operations/acf_menu.lua +++ b/lua/acf/shared/tool_operations/acf_menu.lua @@ -72,9 +72,14 @@ do -- Spawner operation if IsValid(Entity) then return false end local Position = Trace.HitPos + Trace.HitNormal * 128 - local Angles = Trace.HitNormal:Angle():Up():Angle() + local Angles = Trace.HitNormal:Angle():Up():Angle() + local Success, NewEntity = ACF.CreateEntity(ClassName, Player, Position, Angles, Data) - return ACF.CreateEntity(ClassName, Player, Position, Angles, Data) + if Success then + NewEntity:DropToFloor() + end + + return Success end ACF.RegisterOperation("acf_menu", "Main", "Spawner", { From 0a79ebe133c55f103ac522142fc4af89b39f71f5 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Wed, 9 Dec 2020 08:31:06 -0300 Subject: [PATCH 197/279] Added ACF entities to cleanup - ACF entities will now be properly registered for cleanup. --- lua/entities/acf_ammo/cl_init.lua | 2 ++ lua/entities/acf_ammo/shared.lua | 4 +++- lua/entities/acf_engine/cl_init.lua | 2 ++ lua/entities/acf_engine/shared.lua | 4 +++- lua/entities/acf_fueltank/cl_init.lua | 2 ++ lua/entities/acf_fueltank/shared.lua | 4 +++- lua/entities/acf_gearbox/cl_init.lua | 2 ++ lua/entities/acf_gearbox/shared.lua | 4 +++- lua/entities/acf_gun/cl_init.lua | 2 ++ lua/entities/acf_gun/shared.lua | 4 +++- 10 files changed, 25 insertions(+), 5 deletions(-) diff --git a/lua/entities/acf_ammo/cl_init.lua b/lua/entities/acf_ammo/cl_init.lua index a4ba054ee..19603adb5 100644 --- a/lua/entities/acf_ammo/cl_init.lua +++ b/lua/entities/acf_ammo/cl_init.lua @@ -1,6 +1,8 @@ include("shared.lua") +language.Add("Cleanup_acf_ammo", "ACF Ammo Crates") language.Add("Undone_acf_ammo", "Undone ACF Ammo Crate") +language.Add("Cleaned_acf_ammo", "Cleaned up all ACF Ammo Crates") language.Add("SBoxLimit__acf_ammo", "You've reached the ACF Ammo Crates limit!") local MaxRounds = GetConVar("acf_maxroundsdisplay") diff --git a/lua/entities/acf_ammo/shared.lua b/lua/entities/acf_ammo/shared.lua index 1b4c8291a..2f162e321 100644 --- a/lua/entities/acf_ammo/shared.lua +++ b/lua/entities/acf_ammo/shared.lua @@ -2,4 +2,6 @@ DEFINE_BASECLASS("base_scalable_mconvex") ENT.PrintName = "ACF Ammo Crate" ENT.WireDebugName = "ACF Ammo Crate" -ENT.IsAmmoCrate = true \ No newline at end of file +ENT.IsAmmoCrate = true + +cleanup.Register("acf_ammo") diff --git a/lua/entities/acf_engine/cl_init.lua b/lua/entities/acf_engine/cl_init.lua index 019005685..79be12aba 100644 --- a/lua/entities/acf_engine/cl_init.lua +++ b/lua/entities/acf_engine/cl_init.lua @@ -2,7 +2,9 @@ include("shared.lua") local HideInfo = ACF.HideInfoBubble +language.Add("Cleanup_acf_engine", "ACF Engines") language.Add("Undone_acf_engine", "Undone ACF Engine") +language.Add("Cleaned_acf_engine", "Cleaned up all ACF Engines") language.Add("SBoxLimit__acf_engine", "You've reached the ACF Engines limit!") function ENT:Initialize() diff --git a/lua/entities/acf_engine/shared.lua b/lua/entities/acf_engine/shared.lua index 7f646f254..a10c8db9c 100644 --- a/lua/entities/acf_engine/shared.lua +++ b/lua/entities/acf_engine/shared.lua @@ -1,4 +1,6 @@ DEFINE_BASECLASS("base_wire_entity") ENT.PrintName = "ACF Engine" -ENT.WireDebugName = "ACF Engine" \ No newline at end of file +ENT.WireDebugName = "ACF Engine" + +cleanup.Register("acf_engine") diff --git a/lua/entities/acf_fueltank/cl_init.lua b/lua/entities/acf_fueltank/cl_init.lua index e8929ba31..0ff8038d2 100644 --- a/lua/entities/acf_fueltank/cl_init.lua +++ b/lua/entities/acf_fueltank/cl_init.lua @@ -2,7 +2,9 @@ include("shared.lua") local HideInfo = ACF.HideInfoBubble +language.Add("Cleanup_acf_fueltank", "ACF Fuel Tanks") language.Add("Undone_acf_fueltank", "Undone ACF Fuel Tank") +language.Add("Cleaned_acf_fueltank", "Cleaned up all ACF Fuel Tanks") language.Add("SBoxLimit__acf_fueltank", "You've reached the ACF Fuel Tanks limit!") function ENT:Initialize() diff --git a/lua/entities/acf_fueltank/shared.lua b/lua/entities/acf_fueltank/shared.lua index ae6896b58..375c2e4f4 100644 --- a/lua/entities/acf_fueltank/shared.lua +++ b/lua/entities/acf_fueltank/shared.lua @@ -1,4 +1,6 @@ DEFINE_BASECLASS("base_wire_entity") ENT.PrintName = "ACF Fuel Tank" -ENT.WireDebugName = "ACF Fuel Tank" \ No newline at end of file +ENT.WireDebugName = "ACF Fuel Tank" + +cleanup.Register("acf_fueltank") diff --git a/lua/entities/acf_gearbox/cl_init.lua b/lua/entities/acf_gearbox/cl_init.lua index 14b8990bf..5366849fb 100644 --- a/lua/entities/acf_gearbox/cl_init.lua +++ b/lua/entities/acf_gearbox/cl_init.lua @@ -2,7 +2,9 @@ include("shared.lua") local HideInfo = ACF.HideInfoBubble +language.Add("Cleanup_acf_gearbox", "ACF Gearboxes") language.Add("Undone_acf_gearbox", "Undone ACF Gearbox") +language.Add("Cleaned_acf_gearbox", "Cleaned up all ACF Gearboxes") language.Add("SBoxLimit__acf_gearbox", "You've reached the ACF Gearboxes limit!") function ENT:Initialize() diff --git a/lua/entities/acf_gearbox/shared.lua b/lua/entities/acf_gearbox/shared.lua index 8d0a23bf3..e30fbbd9f 100644 --- a/lua/entities/acf_gearbox/shared.lua +++ b/lua/entities/acf_gearbox/shared.lua @@ -1,4 +1,6 @@ DEFINE_BASECLASS("base_wire_entity") ENT.PrintName = "ACF Gearbox" -ENT.WireDebugName = "ACF Gearbox" \ No newline at end of file +ENT.WireDebugName = "ACF Gearbox" + +cleanup.Register("acf_gearbox") diff --git a/lua/entities/acf_gun/cl_init.lua b/lua/entities/acf_gun/cl_init.lua index c2cf87913..e15d46768 100644 --- a/lua/entities/acf_gun/cl_init.lua +++ b/lua/entities/acf_gun/cl_init.lua @@ -2,7 +2,9 @@ include("shared.lua") local HideInfo = ACF.HideInfoBubble +language.Add("Cleanup_acf_gun", "ACF Weapons") language.Add("Undone_acf_gun", "Undone ACF Weapon") +language.Add("Cleaned_acf_gun", "Cleaned up all ACF Weapons") language.Add("SBoxLimit__acf_gun", "You've reached the ACF Weapons limit!") language.Add("SBoxLimit__acf_smokelauncher", "You've reached the ACF Smoke Launcher limit!") diff --git a/lua/entities/acf_gun/shared.lua b/lua/entities/acf_gun/shared.lua index 29b5b272a..aed110513 100644 --- a/lua/entities/acf_gun/shared.lua +++ b/lua/entities/acf_gun/shared.lua @@ -1,4 +1,6 @@ DEFINE_BASECLASS("base_wire_entity") ENT.PrintName = "ACF Gun" -ENT.WireDebugName = "ACF Gun" \ No newline at end of file +ENT.WireDebugName = "ACF Gun" + +cleanup.Register("acf_gun") From 51a8091c355b8ee03a7b6efa7b2fe039aac01efe Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Wed, 9 Dec 2020 12:43:53 -0300 Subject: [PATCH 198/279] Fixed nil reference on 5-Auto and 7-Auto gearboxes - Fixed nil reference inside 5-Auto and 7-Auto gearboxes related to a no longer localized function attempting to be used. - We'll now use the second argument on ACF.CheckNumber instead on relying on ternaries. --- lua/acf/shared/gearboxes/3-auto.lua | 6 +++--- lua/acf/shared/gearboxes/5-auto.lua | 6 +++--- lua/acf/shared/gearboxes/7-auto.lua | 6 +++--- lua/acf/shared/gearboxes/cvt.lua | 4 ++-- lua/entities/acf_gearbox/init.lua | 4 ++-- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/lua/acf/shared/gearboxes/3-auto.lua b/lua/acf/shared/gearboxes/3-auto.lua index f3871adea..42b56a259 100644 --- a/lua/acf/shared/gearboxes/3-auto.lua +++ b/lua/acf/shared/gearboxes/3-auto.lua @@ -60,7 +60,7 @@ ACF.RegisterGearboxClass("3-Auto", { if Count > Max then break end - Points[Count] = ACF.CheckNumber(Point) or Count * 100 + Points[Count] = ACF.CheckNumber(Point, Count * 100) end end @@ -73,7 +73,7 @@ ACF.RegisterGearboxClass("3-Auto", { local Point = ACF.CheckNumber(Points[I]) if not Point then - Point = (ACF.CheckNumber(Data["Shift" .. I]) or I * 100) * Mult + Point = ACF.CheckNumber(Data["Shift" .. I], I * 100) * Mult Data["Shift" .. I] = nil end @@ -86,7 +86,7 @@ ACF.RegisterGearboxClass("3-Auto", { local Reverse = ACF.CheckNumber(Data.Reverse) if not Reverse then - Reverse = ACF.CheckNumber(Data.Gear8) or -1 + Reverse = ACF.CheckNumber(Data.Gear8, -1) Data.Gear8 = nil end diff --git a/lua/acf/shared/gearboxes/5-auto.lua b/lua/acf/shared/gearboxes/5-auto.lua index 4ce3d6c32..b4128a20e 100644 --- a/lua/acf/shared/gearboxes/5-auto.lua +++ b/lua/acf/shared/gearboxes/5-auto.lua @@ -59,7 +59,7 @@ ACF.RegisterGearboxClass("5-Auto", { if Count > Max then break end - Points[Count] = ACF.CheckNumber(Point) or Count * 100 + Points[Count] = ACF.CheckNumber(Point, Count * 100) end end @@ -72,7 +72,7 @@ ACF.RegisterGearboxClass("5-Auto", { local Point = ACF.CheckNumber(Points[I]) if not Point then - Point = (CheckNumber(Data["Shift" .. I]) or I * 100) * Mult + Point = ACF.CheckNumber(Data["Shift" .. I], I * 100) * Mult Data["Shift" .. I] = nil end @@ -85,7 +85,7 @@ ACF.RegisterGearboxClass("5-Auto", { local Reverse = ACF.CheckNumber(Data.Reverse) if not Reverse then - Reverse = ACF.CheckNumber(Data.Gear8) or -1 + Reverse = ACF.CheckNumber(Data.Gear8, -1) Data.Gear8 = nil end diff --git a/lua/acf/shared/gearboxes/7-auto.lua b/lua/acf/shared/gearboxes/7-auto.lua index 90828c756..32639f693 100644 --- a/lua/acf/shared/gearboxes/7-auto.lua +++ b/lua/acf/shared/gearboxes/7-auto.lua @@ -59,7 +59,7 @@ ACF.RegisterGearboxClass("7-Auto", { if Count > Max then break end - Points[Count] = ACF.CheckNumber(Point) or Count * 100 + Points[Count] = ACF.CheckNumber(Point, Count * 100) end end @@ -72,7 +72,7 @@ ACF.RegisterGearboxClass("7-Auto", { local Point = ACF.CheckNumber(Points[I]) if not Point then - Point = (CheckNumber(Data["Shift" .. I]) or I * 100) * Mult + Point = ACF.CheckNumber(Data["Shift" .. I], I * 100) * Mult Data["Shift" .. I] = nil end @@ -85,7 +85,7 @@ ACF.RegisterGearboxClass("7-Auto", { local Reverse = ACF.CheckNumber(Data.Reverse) if not Reverse then - Reverse = ACF.CheckNumber(Data.Gear8) or -1 + Reverse = ACF.CheckNumber(Data.Gear8, -1) Data.Gear8 = nil end diff --git a/lua/acf/shared/gearboxes/cvt.lua b/lua/acf/shared/gearboxes/cvt.lua index 1675954ab..4cf92b1cd 100644 --- a/lua/acf/shared/gearboxes/cvt.lua +++ b/lua/acf/shared/gearboxes/cvt.lua @@ -35,13 +35,13 @@ ACF.RegisterGearboxClass("CVT", { Data.Gears[1] = 0.01 if not Min then - Min = ACF.CheckNumber(Data.Gear3) or 3000 + Min = ACF.CheckNumber(Data.Gear3, 3000) Data.Gear3 = nil end if not Max then - Max = ACF.CheckNumber(Data.Gear4) or 5000 + Max = ACF.CheckNumber(Data.Gear4, 5000) Data.Gear4 = nil end diff --git a/lua/entities/acf_gearbox/init.lua b/lua/entities/acf_gearbox/init.lua index 4375855b6..a5a321ee6 100644 --- a/lua/entities/acf_gearbox/init.lua +++ b/lua/entities/acf_gearbox/init.lua @@ -261,7 +261,7 @@ do -- Spawn and Update functions local Gear = ACF.CheckNumber(Gears[I]) if not Gear then - Gear = ACF.CheckNumber(Data["Gear" .. I]) or I * 0.1 + Gear = ACF.CheckNumber(Data["Gear" .. I], I * 0.1) Data["Gear" .. I] = nil end @@ -274,7 +274,7 @@ do -- Spawn and Update functions local Final = ACF.CheckNumber(Data.FinalDrive) if not Final then - Final = ACF.CheckNumber(Data.Gear0) or 1 + Final = ACF.CheckNumber(Data.Gear0, 1) Data.Gear0 = nil end From ada93e95a4f3fc91dcc759fe6f4144caa88ef227 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Wed, 9 Dec 2020 13:15:36 -0300 Subject: [PATCH 199/279] Properly used the cleanup library - Each entity will now use their own cleanup entry depending on their class. Weapons are an exception, since they can also define their own cleanup entry. --- lua/acf/base/sh_classes.lua | 4 ++++ lua/acf/shared/weapons/smokelauncher.lua | 1 + lua/entities/acf_ammo/init.lua | 2 +- lua/entities/acf_engine/init.lua | 2 +- lua/entities/acf_fueltank/init.lua | 2 +- lua/entities/acf_gearbox/init.lua | 2 +- lua/entities/acf_gun/cl_init.lua | 2 ++ lua/entities/acf_gun/init.lua | 2 +- 8 files changed, 12 insertions(+), 5 deletions(-) diff --git a/lua/acf/base/sh_classes.lua b/lua/acf/base/sh_classes.lua index 7a3d9751e..859aa30ba 100644 --- a/lua/acf/base/sh_classes.lua +++ b/lua/acf/base/sh_classes.lua @@ -219,6 +219,10 @@ do -- Weapon registration functions } end + if not Group.Cleanup then + Group.Cleanup = "acf_gun" + end + AddSboxLimit(Group.LimitConVar) if Group.MuzzleFlash then diff --git a/lua/acf/shared/weapons/smokelauncher.lua b/lua/acf/shared/weapons/smokelauncher.lua index abc82db60..dac8a8f50 100644 --- a/lua/acf/shared/weapons/smokelauncher.lua +++ b/lua/acf/shared/weapons/smokelauncher.lua @@ -5,6 +5,7 @@ ACF.RegisterWeaponClass("SL", { Spread = 0.32, Sound = "acf_base/weapons/smoke_launch.mp3", IsBoxed = true, + Cleanup = "acf_smokelauncher", LimitConVar = { Name = "_acf_smokelauncher", Amount = 10, diff --git a/lua/entities/acf_ammo/init.lua b/lua/entities/acf_ammo/init.lua index 16a2e613d..77a1ea647 100644 --- a/lua/entities/acf_ammo/init.lua +++ b/lua/entities/acf_ammo/init.lua @@ -402,7 +402,7 @@ do -- Spawning and Updating -------------------- if not IsValid(Crate) then return end Player:AddCount("_acf_ammo", Crate) - Player:AddCleanup("acfmenu", Crate) + Player:AddCleanup("acf_ammo", Crate) Crate:SetModel("models/holograms/rcube_thin.mdl") Crate:SetMaterial("phoenix_storms/Future_vents") diff --git a/lua/entities/acf_engine/init.lua b/lua/entities/acf_engine/init.lua index 9877d7ab8..2f323d0c3 100644 --- a/lua/entities/acf_engine/init.lua +++ b/lua/entities/acf_engine/init.lua @@ -339,7 +339,7 @@ do -- Spawn and Update functions Engine:SetPos(Pos) Engine:Spawn() - Player:AddCleanup("acfmenu", Engine) + Player:AddCleanup("acf_engine", Engine) Player:AddCount(Limit, Engine) Engine.Owner = Player -- MUST be stored on ent for PP diff --git a/lua/entities/acf_fueltank/init.lua b/lua/entities/acf_fueltank/init.lua index 060017cba..e15b35a20 100644 --- a/lua/entities/acf_fueltank/init.lua +++ b/lua/entities/acf_fueltank/init.lua @@ -138,7 +138,7 @@ do -- Spawn and Update functions Tank:SetPos(Pos) Tank:Spawn() - Player:AddCleanup("acfmenu", Tank) + Player:AddCleanup("acf_fueltank", Tank) Player:AddCount(Limit, Tank) Tank.Owner = Player -- MUST be stored on ent for PP diff --git a/lua/entities/acf_gearbox/init.lua b/lua/entities/acf_gearbox/init.lua index a5a321ee6..d29c0a737 100644 --- a/lua/entities/acf_gearbox/init.lua +++ b/lua/entities/acf_gearbox/init.lua @@ -427,7 +427,7 @@ do -- Spawn and Update functions Gearbox:SetPos(Pos) Gearbox:Spawn() - Player:AddCleanup("acfmenu", Gearbox) + Player:AddCleanup("acf_gearbox", Gearbox) Player:AddCount(Limit, Gearbox) Gearbox.Owner = Player -- MUST be stored on ent for PP diff --git a/lua/entities/acf_gun/cl_init.lua b/lua/entities/acf_gun/cl_init.lua index e15d46768..dc4a7485b 100644 --- a/lua/entities/acf_gun/cl_init.lua +++ b/lua/entities/acf_gun/cl_init.lua @@ -5,7 +5,9 @@ local HideInfo = ACF.HideInfoBubble language.Add("Cleanup_acf_gun", "ACF Weapons") language.Add("Undone_acf_gun", "Undone ACF Weapon") language.Add("Cleaned_acf_gun", "Cleaned up all ACF Weapons") +language.Add("Cleanup_acf_smokelauncher", "ACF Smoke Launchers") language.Add("SBoxLimit__acf_gun", "You've reached the ACF Weapons limit!") +language.Add("Cleaned_acf_smokelauncher", "Cleaned up all ACF Smoke Launchers") language.Add("SBoxLimit__acf_smokelauncher", "You've reached the ACF Smoke Launcher limit!") function ENT:Initialize() diff --git a/lua/entities/acf_gun/init.lua b/lua/entities/acf_gun/init.lua index 8800caa12..685c5d0bd 100644 --- a/lua/entities/acf_gun/init.lua +++ b/lua/entities/acf_gun/init.lua @@ -177,7 +177,7 @@ do -- Spawn and Update functions -------------------------------- if not IsValid(Gun) then return end - Player:AddCleanup("acfmenu", Gun) + Player:AddCleanup(Class.Cleanup, Gun) Player:AddCount(Limit, Gun) Gun:SetPlayer(Player) From b498badb963f16d6f6fe430acec4a25d1bfaded3 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Wed, 9 Dec 2020 23:20:00 -0300 Subject: [PATCH 200/279] Fixed errors on round impact - Fixed an error related to a wrong reference. - Fixed a nil reference related to a function that doesn't exist within the file. --- lua/acf/server/ballistics.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lua/acf/server/ballistics.lua b/lua/acf/server/ballistics.lua index 26f5f8fc9..a3367e676 100644 --- a/lua/acf/server/ballistics.lua +++ b/lua/acf/server/ballistics.lua @@ -345,18 +345,18 @@ do -- Terminal ballistics -------------------------- local sigmoidCenter = Bullet.DetonatorAngle or (Bullet.Ricochet - math.abs(Speed / 39.37 - Bullet.LimitVel) / 100) -- Ricochet probability (sigmoid distribution); up to 5% minimal ricochet probability for projectiles with caliber < 20 mm - local ricoProb = math.Clamp(1 / (1 + math.exp((Angle - sigmoidCenter) / -4)), math.max(-0.05 * (Bullet.Caliber - 2) / 2, 0), 1) + local ricoProb = math.Clamp(1 / (1 + math.exp((HitAngle - sigmoidCenter) / -4)), math.max(-0.05 * (Bullet.Caliber - 2) / 2, 0), 1) -- Checking for ricochet - if ricoProb > math.random() and Angle < 90 then - Ricochet = math.Clamp(Angle / 90, 0.05, 1) -- atleast 5% of energy is kept + if ricoProb > math.random() and HitAngle < 90 then + Ricochet = math.Clamp(HitAngle / 90, 0.05, 1) -- atleast 5% of energy is kept HitRes.Loss = 0.25 - Ricochet Energy.Kinetic = Energy.Kinetic * HitRes.Loss end end if ACF_KEPUSH:GetBool() then - Shove( + ACF.KEShove( Target, HitPos, Bullet.Flight:GetNormalized(), From 77cf8fac77f8d498d155accc9935ce00a37512b5 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Thu, 10 Dec 2020 01:24:42 -0300 Subject: [PATCH 201/279] Fixed typo on HEAT ammo - Fixed typo inside HEAT ammo prop impact function that led to an infinite loop. --- lua/acf/shared/ammo_types/heat.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/acf/shared/ammo_types/heat.lua b/lua/acf/shared/ammo_types/heat.lua index 34a010731..b45d4ede1 100644 --- a/lua/acf/shared/ammo_types/heat.lua +++ b/lua/acf/shared/ammo_types/heat.lua @@ -201,7 +201,7 @@ if SERVER then end function Ammo:PropImpact(Bullet, Trace) - local Target = Trace.Target + local Target = Trace.Entity if ACF_Check(Target) then local Speed = Bullet.Flight:Length() / ACF.Scale From 7d9085c009abe5edd0c0705e8d347ba42af01526 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Fri, 11 Dec 2020 14:23:21 -0300 Subject: [PATCH 202/279] Fixed engine default sound - Fixed engine default sound being mistakenly saved on the engine class definition. --- lua/acf/base/sh_classes.lua | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lua/acf/base/sh_classes.lua b/lua/acf/base/sh_classes.lua index 859aa30ba..cb03a7ed4 100644 --- a/lua/acf/base/sh_classes.lua +++ b/lua/acf/base/sh_classes.lua @@ -288,7 +288,13 @@ do -- Engine registration functions end function ACF.RegisterEngine(ID, ClassID, Data) - return AddGroupedClass(ID, ClassID, Engines, Data) + local Class = AddGroupedClass(ID, ClassID, Engines, Data) + + if not Class.Sound then + Class.Sound = "vehicles/junker/jnk_fourth_cruise_loop2.wav" + end + + return Class end end @@ -366,13 +372,7 @@ do -- Gearbox registration functions end function ACF.RegisterGearbox(ID, ClassID, Data) - local Class = AddGroupedClass(ID, ClassID, Gearboxes, Data) - - if not Class.Sound then - Class.Sound = "vehicles/junker/jnk_fourth_cruise_loop2.wav" - end - - return Class + return AddGroupedClass(ID, ClassID, Gearboxes, Data) end end From 085eb420c92f55f3b24242a71d8f67cf56a788d7 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Fri, 11 Dec 2020 14:26:10 -0300 Subject: [PATCH 203/279] Moved ACF_Check and ACF_Activate into ACF namespace - ACF_Check and ACF_Activate will now be ACF.Check and ACF.Activate respectively. The old variant will be kept for backwards compatibility. --- lua/acf/base/sv_validation.lua | 15 +++++++++------ lua/acf/server/damage.lua | 2 +- lua/acf/shared/ammo_types/ap.lua | 2 +- lua/acf/shared/ammo_types/he.lua | 2 +- lua/acf/shared/ammo_types/heat.lua | 2 +- lua/acf/shared/ammo_types/smoke.lua | 2 +- lua/entities/acf_ammo/init.lua | 2 +- lua/entities/acf_engine/init.lua | 2 +- lua/entities/acf_fueltank/init.lua | 2 +- lua/entities/acf_gearbox/init.lua | 2 +- lua/entities/acf_gun/init.lua | 2 +- .../core/custom/acffunctions.lua | 12 ++++++------ lua/weapons/gmod_tool/stools/acfarmorprop.lua | 18 +++++++++--------- lua/weapons/torch/shared.lua | 6 +++--- 14 files changed, 37 insertions(+), 34 deletions(-) diff --git a/lua/acf/base/sv_validation.lua b/lua/acf/base/sv_validation.lua index 30132f112..df9f6bbba 100644 --- a/lua/acf/base/sv_validation.lua +++ b/lua/acf/base/sv_validation.lua @@ -1,6 +1,7 @@ -- Entity validation for ACF -- Local Vars ----------------------------------- +local ACF = ACF local Gamemode = GetConVar("acf_gamemode") local StringFind = string.find local TimerSimple = timer.Simple @@ -109,7 +110,7 @@ local function CheckLegal(Entity) return true end -- Global Funcs --------------------------------- -function ACF_Check(Entity, ForceUpdate) -- IsValid but for ACF +function ACF.Check(Entity, ForceUpdate) -- IsValid but for ACF if not IsValid(Entity) then return false end local Class = Entity:GetClass() @@ -125,15 +126,15 @@ function ACF_Check(Entity, ForceUpdate) -- IsValid but for ACF return false end - ACF_Activate(Entity) + ACF.Activate(Entity) elseif ForceUpdate or Entity.ACF.Mass ~= PhysObj:GetMass() or Entity.ACF.PhysObj ~= PhysObj then - ACF_Activate(Entity, true) + ACF.Activate(Entity, true) end return Entity.ACF.Type end -function ACF_Activate(Entity, Recalc) +function ACF.Activate(Entity, Recalc) --Density of steel = 7.8g cm3 so 7.8kg for a 1mx1m plate 1m thick local PhysObj = Entity:GetPhysicsObject() @@ -191,5 +192,7 @@ function ACF_Activate(Entity, Recalc) end -- Globalize ------------------------------------ -ACF_IsLegal = IsLegal -ACF_CheckLegal = CheckLegal +ACF_IsLegal = IsLegal +ACF_CheckLegal = CheckLegal +ACF_Check = ACF.Check +ACF_Activate = ACF.Activate diff --git a/lua/acf/server/damage.lua b/lua/acf/server/damage.lua index edaa41654..185dd5f18 100644 --- a/lua/acf/server/damage.lua +++ b/lua/acf/server/damage.lua @@ -4,7 +4,7 @@ local ACF_HEPUSH = GetConVar("acf_hepush") local TimerCreate = timer.Create local TraceRes = {} local TraceData = { output = TraceRes, mask = MASK_SOLID, filter = false } -local Check = ACF_Check +local Check = ACF.Check local HookRun = hook.Run local Trace = ACF.TraceF local ValidDebris = ACF.ValidDebris diff --git a/lua/acf/shared/ammo_types/ap.lua b/lua/acf/shared/ammo_types/ap.lua index 481413757..60eff0973 100644 --- a/lua/acf/shared/ammo_types/ap.lua +++ b/lua/acf/shared/ammo_types/ap.lua @@ -125,7 +125,7 @@ if SERVER then function Ammo:PropImpact(Bullet, Trace) local Target = Trace.Entity - if ACF_Check(Target) then + if ACF.Check(Target) then local Speed = Bullet.Flight:Length() / ACF.Scale local Energy = ACF_Kinetic(Speed, Bullet.ProjMass, Bullet.LimitVel) local HitRes = ACF_RoundImpact(Bullet, Speed, Energy, Target, Trace.HitPos, Trace.HitNormal, Trace.HitGroup) diff --git a/lua/acf/shared/ammo_types/he.lua b/lua/acf/shared/ammo_types/he.lua index 34c6e4e51..2795ecfa6 100644 --- a/lua/acf/shared/ammo_types/he.lua +++ b/lua/acf/shared/ammo_types/he.lua @@ -91,7 +91,7 @@ if SERVER then function Ammo:PropImpact(Bullet, Trace) local Target = Trace.Entity - if ACF_Check(Target) then + if ACF.Check(Target) then local Speed = Bullet.Flight:Length() / ACF.Scale local Energy = ACF_Kinetic(Speed, Bullet.ProjMass - Bullet.FillerMass, Bullet.LimitVel) local HitRes = ACF_RoundImpact(Bullet, Speed, Energy, Target, Trace.HitPos, Trace.HitNormal, Trace.HitGroup) diff --git a/lua/acf/shared/ammo_types/heat.lua b/lua/acf/shared/ammo_types/heat.lua index b45d4ede1..5d2372ffa 100644 --- a/lua/acf/shared/ammo_types/heat.lua +++ b/lua/acf/shared/ammo_types/heat.lua @@ -203,7 +203,7 @@ if SERVER then function Ammo:PropImpact(Bullet, Trace) local Target = Trace.Entity - if ACF_Check(Target) then + if ACF.Check(Target) then local Speed = Bullet.Flight:Length() / ACF.Scale local HitPos = Trace.HitPos local HitNormal = Trace.HitNormal diff --git a/lua/acf/shared/ammo_types/smoke.lua b/lua/acf/shared/ammo_types/smoke.lua index 660cc1b83..44e8ae3aa 100644 --- a/lua/acf/shared/ammo_types/smoke.lua +++ b/lua/acf/shared/ammo_types/smoke.lua @@ -156,7 +156,7 @@ if SERVER then function Ammo:PropImpact(Bullet, Trace) local Target = Trace.Entity - if ACF_Check(Target) then + if ACF.Check(Target) then local Speed = Bullet.Flight:Length() / ACF.Scale local Energy = ACF_Kinetic(Speed, Bullet.ProjMass - (Bullet.FillerMass + Bullet.WPMass), Bullet.LimitVel) local HitRes = ACF_RoundImpact(Bullet, Speed, Energy, Target, Trace.HitPos, Trace.HitNormal, Trace.HitGroup) diff --git a/lua/entities/acf_ammo/init.lua b/lua/entities/acf_ammo/init.lua index 77a1ea647..4c4f0b126 100644 --- a/lua/entities/acf_ammo/init.lua +++ b/lua/entities/acf_ammo/init.lua @@ -364,7 +364,7 @@ do -- Spawning and Updating -------------------- end end - ACF_Activate(Entity, true) -- Makes Crate.ACF table + ACF.Activate(Entity, true) -- Makes Crate.ACF table Entity.ACF.Model = Entity:GetModel() diff --git a/lua/entities/acf_engine/init.lua b/lua/entities/acf_engine/init.lua index 2f323d0c3..c62f400d6 100644 --- a/lua/entities/acf_engine/init.lua +++ b/lua/entities/acf_engine/init.lua @@ -312,7 +312,7 @@ do -- Spawn and Update functions Entity.FuelUse = ACF.FuelRate * Entity.Efficiency * Entity.peakkw / 3600 end - ACF_Activate(Entity, true) + ACF.Activate(Entity, true) Entity.ACF.LegalMass = EngineData.Mass Entity.ACF.Model = EngineData.Model diff --git a/lua/entities/acf_fueltank/init.lua b/lua/entities/acf_fueltank/init.lua index e15b35a20..bc046c786 100644 --- a/lua/entities/acf_fueltank/init.lua +++ b/lua/entities/acf_fueltank/init.lua @@ -110,7 +110,7 @@ do -- Spawn and Update functions Entity.Fuel = Percentage * Entity.Capacity - ACF_Activate(Entity, true) + ACF.Activate(Entity, true) Entity.ACF.Model = FuelTank.Model diff --git a/lua/entities/acf_gearbox/init.lua b/lua/entities/acf_gearbox/init.lua index d29c0a737..0c97cd886 100644 --- a/lua/entities/acf_gearbox/init.lua +++ b/lua/entities/acf_gearbox/init.lua @@ -354,7 +354,7 @@ do -- Spawn and Update functions Entity:SetNWString("WireName", "ACF " .. Entity.Name) - ACF_Activate(Entity, true) + ACF.Activate(Entity, true) Entity.ACF.LegalMass = Gearbox.Mass Entity.ACF.Model = Gearbox.Model diff --git a/lua/entities/acf_gun/init.lua b/lua/entities/acf_gun/init.lua index 685c5d0bd..add03026e 100644 --- a/lua/entities/acf_gun/init.lua +++ b/lua/entities/acf_gun/init.lua @@ -146,7 +146,7 @@ do -- Spawn and Update functions -------------------------------- WireLib.TriggerOutput(Entity, "Rate of Fire", 60 / Entity.Cyclic) end - ACF_Activate(Entity, true) + ACF.Activate(Entity, true) Entity.ACF.LegalMass = Weapon.Mass Entity.ACF.Model = Weapon.Model diff --git a/lua/entities/gmod_wire_expression2/core/custom/acffunctions.lua b/lua/entities/gmod_wire_expression2/core/custom/acffunctions.lua index 454c416f7..6406020ce 100644 --- a/lua/entities/gmod_wire_expression2/core/custom/acffunctions.lua +++ b/lua/entities/gmod_wire_expression2/core/custom/acffunctions.lua @@ -211,7 +211,7 @@ end e2function number entity:acfPropHealth() if not validPhysics(this) then return 0 end if RestrictInfo(self, this) then return 0 end - if not ACF_Check(this) then return 0 end + if not ACF.Check(this) then return 0 end local Health = this.ACF.Health @@ -222,7 +222,7 @@ end e2function number entity:acfPropArmor() if not validPhysics(this) then return 0 end if RestrictInfo(self, this) then return 0 end - if not ACF_Check(this) then return 0 end + if not ACF.Check(this) then return 0 end local Armor = this.ACF.Armour @@ -233,7 +233,7 @@ end e2function number entity:acfPropHealthMax() if not validPhysics(this) then return 0 end if RestrictInfo(self, this) then return 0 end - if not ACF_Check(this) then return 0 end + if not ACF.Check(this) then return 0 end local MaxHealth = this.ACF.MaxHealth @@ -244,7 +244,7 @@ end e2function number entity:acfPropArmorMax() if not validPhysics(this) then return 0 end if RestrictInfo(self, this) then return 0 end - if not ACF_Check(this) then return 0 end + if not ACF.Check(this) then return 0 end local MaxArmor = this.ACF.MaxArmour @@ -255,7 +255,7 @@ end e2function number entity:acfPropDuctility() if not validPhysics(this) then return 0 end if RestrictInfo(self, this) then return 0 end - if not ACF_Check(this) then return 0 end + if not ACF.Check(this) then return 0 end local Ductility = this.ACF.Ductility @@ -273,7 +273,7 @@ end e2function number ranger:acfEffectiveArmor() if not (this and validPhysics(this.Entity)) then return 0 end if RestrictInfo(self, this.Entity) then return 0 end - if not ACF_Check(this.Entity) then return 0 end + if not ACF.Check(this.Entity) then return 0 end local Armor = this.Entity.ACF.Armour local HitAngle = ACF_GetHitAngle(this.HitNormal , this.HitPos - this.StartPos) diff --git a/lua/weapons/gmod_tool/stools/acfarmorprop.lua b/lua/weapons/gmod_tool/stools/acfarmorprop.lua index 4ec7e012a..1985968dd 100644 --- a/lua/weapons/gmod_tool/stools/acfarmorprop.lua +++ b/lua/weapons/gmod_tool/stools/acfarmorprop.lua @@ -22,10 +22,10 @@ end local function ApplySettings(_, Entity, Data) if CLIENT then return end if not Data then return end - if not ACF_Check(Entity) then return end + if not ACF.Check(Entity) then return end if Data.Mass then - local PhysObj = Entity.ACF.PhysObj -- If it passed ACF_Check, then the PhysObj will always be valid + local PhysObj = Entity.ACF.PhysObj -- If it passed ACF.Check, then the PhysObj will always be valid local Mass = math.Clamp(Data.Mass, 0.1, 50000) PhysObj:SetMass(Mass) @@ -41,7 +41,7 @@ local function ApplySettings(_, Entity, Data) duplicator.StoreEntityModifier(Entity, "acfsettings", { Ductility = Ductility }) end - ACF_Check(Entity, true) -- Forcing the entity to update its information + ACF.Check(Entity, true) -- Forcing the entity to update its information end if CLIENT then @@ -228,7 +228,7 @@ else -- Serverside-only stuff local Ductility = Entity.ACF.Ductility local Thickness = Entity.ACF.MaxArmour - ACF_Check(Entity) -- We need to update again to get the Area + ACF.Check(Entity) -- We need to update again to get the Area local Area = Entity.ACF.Area local Mass = CalcArmor(Area, Ductility, Thickness) @@ -247,7 +247,7 @@ else -- Serverside-only stuff local Weapon = self.Weapon - if ACF_Check(Ent) then + if ACF.Check(Ent) then Player:ConCommand("acfarmorprop_area " .. Ent.ACF.Area) Player:ConCommand("acfarmorprop_thickness " .. self:GetClientNumber("thickness")) -- Force sliders to update themselves @@ -274,7 +274,7 @@ else -- Serverside-only stuff hook.Add("ProperClippingPhysicsClipped", "ACF Physclip Armor", UpdateMass) hook.Add("ProperClippingPhysicsReset", "ACF Physclip Armor", UpdateMass) hook.Add("ProperClippingCanPhysicsClip", "ACF PhysClip Armor", function(Entity) - ACF_Check(Entity, true) -- Just creating the ACF table on the entity + ACF.Check(Entity, true) -- Just creating the ACF table on the entity end) duplicator.RegisterEntityModifier("acfsettings", ApplySettings) @@ -300,7 +300,7 @@ function TOOL:LeftClick(Trace) if not IsValid(Ent) then return false end if Ent:IsPlayer() or Ent:IsNPC() then return false end if CLIENT then return true end - if not ACF_Check(Ent) then return false end + if not ACF.Check(Ent) then return false end local Player = self:GetOwner() @@ -323,7 +323,7 @@ function TOOL:RightClick(Trace) if not IsValid(Ent) then return false end if Ent:IsPlayer() or Ent:IsNPC() then return false end if CLIENT then return true end - if not ACF_Check(Ent) then return false end + if not ACF.Check(Ent) then return false end local Player = self:GetOwner() @@ -359,7 +359,7 @@ do -- Armor readout local PhysTotal = 0 for _, Ent in ipairs(Entities) do - if not ACF_Check(Ent) then + if not ACF.Check(Ent) then if not Ent:IsWeapon() then -- We don't want to count weapon entities OtherNum = OtherNum + 1 end diff --git a/lua/weapons/torch/shared.lua b/lua/weapons/torch/shared.lua index 70fe447bd..44d1c1b57 100644 --- a/lua/weapons/torch/shared.lua +++ b/lua/weapons/torch/shared.lua @@ -78,7 +78,7 @@ function SWEP:Think() self.LastDistance = Trace.StartPos:DistToSqr(Trace.HitPos) self.LastTrace = Trace - if ACF_Check(Entity) and self.LastDistance <= self.MaxDistance then + if ACF.Check(Entity) and self.LastDistance <= self.MaxDistance then if Entity:IsPlayer() or Entity:IsNPC() then Health = Entity:Health() MaxHealth = Entity:GetMaxHealth() @@ -120,7 +120,7 @@ function SWEP:PrimaryAttack() local Trace = self.LastTrace local Owner = self.Owner - if ACF_Check(Entity) then + if ACF.Check(Entity) then if Entity:IsPlayer() or Entity:IsNPC() then local Health = Entity:Health() local MaxHealth = Entity:GetMaxHealth() @@ -180,7 +180,7 @@ function SWEP:SecondaryAttack() local Trace = self.LastTrace local Owner = self.Owner - if ACF_Check(Entity) then + if ACF.Check(Entity) then local HitRes = {} if Entity:IsPlayer() or Entity:IsNPC() then From 8a6eb0035949dc21ee5eb2954da0af37b0fd0c78 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Fri, 11 Dec 2020 14:33:09 -0300 Subject: [PATCH 204/279] Fixed StarfallEx library - Rewrote most of the StarfallEx library, so it can work properly with the latest changes from the menu branch. Some functions got renamed, a few mobility related ones were split between engines and gearboxes and ammo type data functions no longer returns a few functions to help validate information. - As a micro optimization, every entity will hold a flag depending on what kind of ACF entity they are. - Engines will now save their ID as "Engine" instead of "Id". - Fuel tanks will now save their ID as "FuelTank" instead of "Id". - Weapons will now save their ID as "Weapon" instead of "Id". - Some gearbox input actions will now have checks inside for the gearbox type, so they can fail silently if the gearbox shouldn't use said input. --- lua/acf/base/util/sv_util.lua | 18 + lua/entities/acf_engine/init.lua | 21 +- lua/entities/acf_engine/shared.lua | 1 + lua/entities/acf_fueltank/init.lua | 24 +- lua/entities/acf_fueltank/shared.lua | 5 +- lua/entities/acf_gearbox/init.lua | 20 +- lua/entities/acf_gearbox/shared.lua | 5 +- lua/entities/acf_gun/init.lua | 65 +- lua/entities/acf_gun/shared.lua | 2 + .../core/custom/acffunctions.lua | 46 +- lua/starfall/libs_sv/acffunctions.lua | 3251 ++++++++--------- 11 files changed, 1656 insertions(+), 1802 deletions(-) diff --git a/lua/acf/base/util/sv_util.lua b/lua/acf/base/util/sv_util.lua index 65c80cf40..db9aa48d9 100644 --- a/lua/acf/base/util/sv_util.lua +++ b/lua/acf/base/util/sv_util.lua @@ -237,6 +237,24 @@ do -- Entity linking return EntityLink[Class][VarName] end + function ACF.GetLinkedEntities(Entity) + if not IsValid(Entity) then return {} end + + local Links = EntityLink[Entity:GetClass()] + + if not Links then return {} end + + local Result = {} + + for _, Function in pairs(Links) do + for Ent in pairs(Function(Entity)) do + Result[Ent] = true + end + end + + return Result + end + local ClassLink = { Link = {}, Unlink = {} } local function RegisterNewLink(Action, Class1, Class2, Function) if not isfunction(Function) then return end diff --git a/lua/entities/acf_engine/init.lua b/lua/entities/acf_engine/init.lua index c62f400d6..e85e7a884 100644 --- a/lua/entities/acf_engine/init.lua +++ b/lua/entities/acf_engine/init.lua @@ -231,17 +231,16 @@ end do -- Spawn and Update functions local function VerifyData(Data) - -- Entity was created via menu tool - if Data.Engine then - Data.Id = Data.Engine + if not Data.Engine then + Data.Engine = Data.Id or "5.7-V8" end - local Class = ACF.GetClassGroup(Engines, Data.Id) + local Class = ACF.GetClassGroup(Engines, Data.Engine) if not Class then - Data.Id = "5.7-V8" + Data.Engine = "5.7-V8" - Class = ACF.GetClassGroup(Engines, Data.Id) + Class = ACF.GetClassGroup(Engines, "5.7-V8") end do -- External verifications @@ -324,8 +323,8 @@ do -- Spawn and Update functions function MakeACF_Engine(Player, Pos, Angle, Data) VerifyData(Data) - local Class = ACF.GetClassGroup(Engines, Data.Id) - local EngineData = Class.Lookup[Data.Id] + local Class = ACF.GetClassGroup(Engines, Data.Engine) + local EngineData = Class.Lookup[Data.Engine] local Limit = Class.LimitConVar.Name if not Player:CheckLimit(Limit) then return false end @@ -382,7 +381,7 @@ do -- Spawn and Update functions return Engine end - ACF.RegisterEntityClass("acf_engine", MakeACF_Engine, "Id") + ACF.RegisterEntityClass("acf_engine", MakeACF_Engine, "Engine") ACF.RegisterLinkSource("acf_engine", "FuelTanks") ACF.RegisterLinkSource("acf_engine", "Gearboxes") @@ -393,8 +392,8 @@ do -- Spawn and Update functions VerifyData(Data) - local Class = ACF.GetClassGroup(Engines, Data.Id) - local EngineData = Class.Lookup[Data.Id] + local Class = ACF.GetClassGroup(Engines, Data.Engine) + local EngineData = Class.Lookup[Data.Engine] local OldClass = self.ClassData local Feedback = "" diff --git a/lua/entities/acf_engine/shared.lua b/lua/entities/acf_engine/shared.lua index a10c8db9c..19cfd17af 100644 --- a/lua/entities/acf_engine/shared.lua +++ b/lua/entities/acf_engine/shared.lua @@ -2,5 +2,6 @@ DEFINE_BASECLASS("base_wire_entity") ENT.PrintName = "ACF Engine" ENT.WireDebugName = "ACF Engine" +ENT.IsEngine = true cleanup.Register("acf_engine") diff --git a/lua/entities/acf_fueltank/init.lua b/lua/entities/acf_fueltank/init.lua index bc046c786..41d7ca13c 100644 --- a/lua/entities/acf_fueltank/init.lua +++ b/lua/entities/acf_fueltank/init.lua @@ -34,18 +34,16 @@ end do -- Spawn and Update functions local function VerifyData(Data) - if Data.FuelTank then -- Entity was created via menu tool - Data.Id = Data.FuelTank - elseif Data.SizeId then -- Backwards compatibility with ACF-2 dupes - Data.Id = Data.SizeId + if not Data.FuelTank then + Data.FuelTank = Data.SizeId or Data.Id or "Jerry_Can" end - local Class = ACF.GetClassGroup(FuelTanks, Data.Id) + local Class = ACF.GetClassGroup(FuelTanks, Data.FuelTank) if not Class then - Data.Id = "Jerry_Can" + Data.FuelTank = "Jerry_Can" - Class = ACF.GetClassGroup(FuelTanks, Data.Id) + Class = ACF.GetClassGroup(FuelTanks, "Jerry_Can") end -- Making sure to provide a valid fuel type @@ -85,7 +83,7 @@ do -- Spawn and Update functions end Entity.Name = FuelTank.Name - Entity.ShortName = Entity.Id + Entity.ShortName = Entity.FuelTank Entity.EntType = Class.Name Entity.ClassData = Class Entity.FuelDensity = FuelData.Density @@ -123,8 +121,8 @@ do -- Spawn and Update functions function MakeACF_FuelTank(Player, Pos, Angle, Data) VerifyData(Data) - local Class = ACF.GetClassGroup(FuelTanks, Data.Id) - local FuelTank = Class.Lookup[Data.Id] + local Class = ACF.GetClassGroup(FuelTanks, Data.FuelTank) + local FuelTank = Class.Lookup[Data.FuelTank] local Limit = Class.LimitConVar.Name if not Player:CheckLimit(Limit) then return end @@ -179,7 +177,7 @@ do -- Spawn and Update functions return Tank end - ACF.RegisterEntityClass("acf_fueltank", MakeACF_FuelTank, "Id", "FuelType") + ACF.RegisterEntityClass("acf_fueltank", MakeACF_FuelTank, "FuelTank", "FuelType") ACF.RegisterLinkSource("acf_fueltank", "Engines") ------------------- Updating --------------------- @@ -187,8 +185,8 @@ do -- Spawn and Update functions function ENT:Update(Data) VerifyData(Data) - local Class = ACF.GetClassGroup(FuelTanks, Data.Id) - local FuelTank = Class.Lookup[Data.Id] + local Class = ACF.GetClassGroup(FuelTanks, Data.FuelTank) + local FuelTank = Class.Lookup[Data.FuelTank] local OldClass = self.ClassData local Feedback = "" diff --git a/lua/entities/acf_fueltank/shared.lua b/lua/entities/acf_fueltank/shared.lua index 375c2e4f4..37b646ffd 100644 --- a/lua/entities/acf_fueltank/shared.lua +++ b/lua/entities/acf_fueltank/shared.lua @@ -1,6 +1,7 @@ DEFINE_BASECLASS("base_wire_entity") -ENT.PrintName = "ACF Fuel Tank" -ENT.WireDebugName = "ACF Fuel Tank" +ENT.PrintName = "ACF Fuel Tank" +ENT.WireDebugName = "ACF Fuel Tank" +ENT.IsFuelTank = true cleanup.Register("acf_fueltank") diff --git a/lua/entities/acf_gearbox/init.lua b/lua/entities/acf_gearbox/init.lua index 0c97cd886..22b4f8c60 100644 --- a/lua/entities/acf_gearbox/init.lua +++ b/lua/entities/acf_gearbox/init.lua @@ -687,7 +687,7 @@ ACF.AddInputAction("acf_gearbox", "Gear", function(Entity, Value) end) ACF.AddInputAction("acf_gearbox", "Gear Up", function(Entity, Value) - if Value == 0 then return end + if not tobool(Value) then return end if Entity.Automatic then Entity:ChangeDrive(Entity.Drive + 1) @@ -697,7 +697,7 @@ ACF.AddInputAction("acf_gearbox", "Gear Up", function(Entity, Value) end) ACF.AddInputAction("acf_gearbox", "Gear Down", function(Entity, Value) - if Value == 0 then return end + if not tobool(Value) then return end if Entity.Automatic then Entity:ChangeDrive(Entity.Drive - 1) @@ -712,10 +712,14 @@ ACF.AddInputAction("acf_gearbox", "Clutch", function(Entity, Value) end) ACF.AddInputAction("acf_gearbox", "Left Clutch", function(Entity, Value) + if not Entity.DualClutch then return end + Entity.LClutch = Clamp(1 - Value, 0, 1) end) ACF.AddInputAction("acf_gearbox", "Right Clutch", function(Entity, Value) + if not Entity.DualClutch then return end + Entity.RClutch = Clamp(1 - Value, 0, 1) end) @@ -727,30 +731,42 @@ ACF.AddInputAction("acf_gearbox", "Brake", function(Entity, Value) end) ACF.AddInputAction("acf_gearbox", "Left Brake", function(Entity, Value) + if not Entity.DualClutch then return end + Entity.LBrake = Clamp(Value, 0, 100) SetCanApplyBrakes(Entity) end) ACF.AddInputAction("acf_gearbox", "Right Brake", function(Entity, Value) + if not Entity.DualClutch then return end + Entity.RBrake = Clamp(Value, 0, 100) SetCanApplyBrakes(Entity) end) ACF.AddInputAction("acf_gearbox", "CVT Ratio", function(Entity, Value) + if not Entity.CVT then return end + Entity.CVTRatio = Clamp(Value, 0, 1) end) ACF.AddInputAction("acf_gearbox", "Steer Rate", function(Entity, Value) + if not Entity.DoubleDiff then return end + Entity.SteerRate = Clamp(Value, -1, 1) end) ACF.AddInputAction("acf_gearbox", "Hold Gear", function(Entity, Value) + if not Entity.Automatic then return end + Entity.Hold = tobool(Value) end) ACF.AddInputAction("acf_gearbox", "Shift Speed Scale", function(Entity, Value) + if not Entity.Automatic then return end + Entity.ShiftScale = Clamp(Value, 0.1, 1.5) end) diff --git a/lua/entities/acf_gearbox/shared.lua b/lua/entities/acf_gearbox/shared.lua index e30fbbd9f..ba05fc25e 100644 --- a/lua/entities/acf_gearbox/shared.lua +++ b/lua/entities/acf_gearbox/shared.lua @@ -1,6 +1,7 @@ DEFINE_BASECLASS("base_wire_entity") -ENT.PrintName = "ACF Gearbox" -ENT.WireDebugName = "ACF Gearbox" +ENT.PrintName = "ACF Gearbox" +ENT.WireDebugName = "ACF Gearbox" +ENT.IsGearbox = true cleanup.Register("acf_gearbox") diff --git a/lua/entities/acf_gun/init.lua b/lua/entities/acf_gun/init.lua index add03026e..6c73a080a 100644 --- a/lua/entities/acf_gun/init.lua +++ b/lua/entities/acf_gun/init.lua @@ -43,15 +43,14 @@ do -- Spawn and Update functions -------------------------------- } local function VerifyData(Data) - -- Entity was created via menu tool - if Data.Weapon then - Data.Id = Data.Weapon + if not Data.Weapon then + Data.Weapon = Data.Id or "50mmC" end - local Class = ACF.GetClassGroup(Weapons, Data.Id) + local Class = ACF.GetClassGroup(Weapons, Data.Weapon) if not Class then - Data.Id = Data.Id and Updated[Data.Id] or "50mmC" + Data.Weapon = Data.Weapon and Updated[Data.Weapon] or "50mmC" end do -- External verifications @@ -132,7 +131,7 @@ do -- Spawn and Update functions -------------------------------- -- Set NWvars Entity:SetNWString("WireName", "ACF " .. Weapon.Name) Entity:SetNWString("Class", Entity.Class) - Entity:SetNWString("ID", Entity.Id) + Entity:SetNWString("ID", Entity.Weapon) -- Adjustable barrel length if Entity.Long then @@ -167,8 +166,8 @@ do -- Spawn and Update functions -------------------------------- function MakeACF_Weapon(Player, Pos, Angle, Data) VerifyData(Data) - local Class = ACF.GetClassGroup(Weapons, Data.Id) - local Weapon = Class.Lookup[Data.Id] + local Class = ACF.GetClassGroup(Weapons, Data.Weapon) + local Weapon = Class.Lookup[Data.Weapon] local Limit = Class.LimitConVar.Name if not Player:CheckLimit(Limit) then return false end -- Check gun spawn limits @@ -231,7 +230,7 @@ do -- Spawn and Update functions -------------------------------- return Gun end - ACF.RegisterEntityClass("acf_gun", MakeACF_Weapon, "Id") + ACF.RegisterEntityClass("acf_gun", MakeACF_Weapon, "Weapon") ACF.RegisterLinkSource("acf_gun", "Crates") ------------------- Updating --------------------- @@ -241,8 +240,8 @@ do -- Spawn and Update functions -------------------------------- VerifyData(Data) - local Class = ACF.GetClassGroup(Weapons, Data.Id) - local Weapon = Class.Lookup[Data.Id] + local Class = ACF.GetClassGroup(Weapons, Data.Weapon) + local Weapon = Class.Lookup[Data.Weapon] local OldClass = self.ClassData if self.State ~= "Empty" then @@ -291,28 +290,28 @@ do -- Metamethods -------------------------------- WireLib.AddOutputAlias("AmmoCount", "Total Ammo") WireLib.AddOutputAlias("Muzzle Weight", "Projectile Mass") - ACF.RegisterClassLink("acf_gun", "acf_ammo", function(Weapon, Target) - if Weapon.Crates[Target] then return false, "This weapon is already linked to this crate." end - if Target.Weapons[Weapon] then return false, "This weapon is already linked to this crate." end - if Target.IsRefill then return false, "Refill crates cannot be linked to weapons." end - if Weapon.Id ~= Target.Weapon then return false, "Wrong ammo type for this weapon." end + ACF.RegisterClassLink("acf_gun", "acf_ammo", function(This, Crate) + if This.Crates[Crate] then return false, "This weapon is already linked to this crate." end + if Crate.Weapons[This] then return false, "This weapon is already linked to this crate." end + if Crate.IsRefill then return false, "Refill crates cannot be linked to weapons." end + if This.Weapon ~= Crate.Weapon then return false, "Wrong ammo type for this weapon." end - local Blacklist = Target.RoundData.Blacklist + local Blacklist = Crate.RoundData.Blacklist - if Blacklist[Weapon.Class] then + if Blacklist[This.Class] then return false, "The ammo type in this crate cannot be used for this weapon." end - Weapon.Crates[Target] = true - Target.Weapons[Weapon] = true + This.Crates[Crate] = true + Crate.Weapons[This] = true - Weapon:UpdateOverlay(true) - Target:UpdateOverlay(true) + This:UpdateOverlay(true) + Crate:UpdateOverlay(true) - if Weapon.State == "Empty" then -- When linked to an empty weapon, attempt to load it + if This.State == "Empty" then -- When linked to an empty weapon, attempt to load it timer.Simple(0.5, function() -- Delay by 500ms just in case the wiring isn't applied at the same time or whatever weird dupe shit happens - if IsValid(Weapon) and IsValid(Target) and Weapon.State == "Empty" and Target:CanConsume() then - Weapon:Load() + if IsValid(This) and IsValid(Crate) and This.State == "Empty" and Crate:CanConsume() then + This:Load() end end) end @@ -320,17 +319,17 @@ do -- Metamethods -------------------------------- return true, "Weapon linked successfully." end) - ACF.RegisterClassUnlink("acf_gun", "acf_ammo", function(Weapon, Target) - if Weapon.Crates[Target] or Target.Weapons[Weapon] then - if Weapon.CurrentCrate == Target then - Weapon.CurrentCrate = next(Weapon.Crates, Target) + ACF.RegisterClassUnlink("acf_gun", "acf_ammo", function(This, Crate) + if This.Crates[Crate] or Crate.Weapons[This] then + if This.CurrentCrate == Crate then + This.CurrentCrate = next(This.Crates, Crate) end - Weapon.Crates[Target] = nil - Target.Weapons[Weapon] = nil + This.Crates[Crate] = nil + Crate.Weapons[This] = nil - Weapon:UpdateOverlay(true) - Target:UpdateOverlay(true) + This:UpdateOverlay(true) + Crate:UpdateOverlay(true) return true, "Weapon unlinked successfully." end diff --git a/lua/entities/acf_gun/shared.lua b/lua/entities/acf_gun/shared.lua index aed110513..1c309d426 100644 --- a/lua/entities/acf_gun/shared.lua +++ b/lua/entities/acf_gun/shared.lua @@ -2,5 +2,7 @@ DEFINE_BASECLASS("base_wire_entity") ENT.PrintName = "ACF Gun" ENT.WireDebugName = "ACF Gun" +ENT.IsWeapon = true cleanup.Register("acf_gun") +cleanup.Register("acf_smokelauncher") diff --git a/lua/entities/gmod_wire_expression2/core/custom/acffunctions.lua b/lua/entities/gmod_wire_expression2/core/custom/acffunctions.lua index 6406020ce..257a0eccf 100644 --- a/lua/entities/gmod_wire_expression2/core/custom/acffunctions.lua +++ b/lua/entities/gmod_wire_expression2/core/custom/acffunctions.lua @@ -108,7 +108,7 @@ end __e2setcost(5) --- Returns the full name of an ACF entity, or the next projectile on a rack +-- Returns the full name of an ACF entity e2function string entity:acfName() if not IsACFEntity(this) then return "" end if RestrictInfo(self, this) then return "" end @@ -137,7 +137,7 @@ e2function number entity:acfIsEngine() if not validPhysics(this) then return 0 end if RestrictInfo(self, this) then return 0 end - return this:GetClass() == "acf_engine" and 1 or 0 + return this.IsEngine and 1 or 0 end -- Returns 1 if the entity is an ACF gearbox @@ -145,7 +145,7 @@ e2function number entity:acfIsGearbox() if not validPhysics(this) then return 0 end if RestrictInfo(self, this) then return 0 end - return this:GetClass() == "acf_gearbox" and 1 or 0 + return this.IsGearbox and 1 or 0 end -- Returns 1 if the entity is an ACF gun @@ -153,7 +153,7 @@ e2function number entity:acfIsGun() if not validPhysics(this) then return 0 end if RestrictInfo(self, this) then return 0 end - return this:GetClass() == "acf_gun" and 1 or 0 + return this.IsWeapon and 1 or 0 end -- Returns 1 if the entity is an ACF ammo crate @@ -161,7 +161,7 @@ e2function number entity:acfIsAmmo() if not validPhysics(this) then return 0 end if RestrictInfo(self, this) then return 0 end - return this:GetClass() == "acf_ammo" and 1 or 0 + return this.IsAmmoCrate and 1 or 0 end -- Returns 1 if the entity is an ACF fuel tank @@ -169,7 +169,7 @@ e2function number entity:acfIsFuel() if not validPhysics(this) then return 0 end if RestrictInfo(self, this) then return 0 end - return this:GetClass() == "acf_fueltank" and 1 or 0 + return this.IsFuelTank and 1 or 0 end -- Returns the capacity of an acf ammo crate or fuel tank @@ -296,15 +296,13 @@ e2function array entity:acfLinks() if not IsACFEntity(this) then return {} end if RestrictInfo(self, this) then return {} end - local Sources = AllLinkSources(this:GetClass()) local Result = {} local Count = 0 - for _, Function in pairs(Sources) do - for Entity in pairs(Function(this)) do - Count = Count + 1 - Result[Count] = Entity - end + for Entity in pairs(ACF.GetLinkedEntities(this)) do + Count = Count + 1 + + Result[Count] = Entity end return Result @@ -615,9 +613,7 @@ e2function number entity:acfGearRatio(number Gear) if RestrictInfo(self, this) then return 0 end if not this.Gears then return 0 end - local Index = math.Clamp(floor(Gear), 0, this.GearCount) - - return this.Gears[Index] + return this.Gears[floor(Gear)] or 0 end -- Returns the current torque output for an ACF gearbox @@ -632,7 +628,6 @@ end e2function void entity:acfCVTRatio(number Ratio) if not IsACFEntity(this) then return end if not isOwner(self, this) then return end - if not this.CVT then return end this:TriggerInput("CVT Ratio", math.Clamp(Ratio, 0, 1)) end @@ -673,7 +668,6 @@ end e2function void entity:acfBrakeLeft(number Brake) if not IsACFEntity(this) then return end if not isOwner(self, this) then return end - if not this.DualClutch then return end this:TriggerInput("Left Brake", Brake) end @@ -682,7 +676,6 @@ end e2function void entity:acfBrakeRight(number Brake) if not IsACFEntity(this) then return end if not isOwner(self, this) then return end - if not this.DualClutch then return end this:TriggerInput("Right Brake", Brake) end @@ -699,7 +692,6 @@ end e2function void entity:acfClutchLeft(number Clutch) if not IsACFEntity(this) then return end if not isOwner(self, this) then return end - if not this.DualClutch then return end this:TriggerInput("Left Clutch", Clutch) end @@ -708,7 +700,6 @@ end e2function void entity:acfClutchRight(number Clutch) if not IsACFEntity(this) then return end if not isOwner(self, this) then return end - if not this.DualClutch then return end this:TriggerInput("Right Clutch", Clutch) end @@ -717,7 +708,6 @@ end e2function void entity:acfSteerRate(number Rate) if not IsACFEntity(this) then return end if not isOwner(self, this) then return end - if not this.DoubleDiff then return end this:TriggerInput("Steer Rate", Rate) end @@ -726,7 +716,6 @@ end e2function void entity:acfHoldGear(number Hold) if not IsACFEntity(this) then return end if not isOwner(self, this) then return end - if not this.Automatic then return end this:TriggerInput("Hold Gear", Hold) end @@ -735,7 +724,6 @@ end e2function void entity:acfShiftPointScale(number Scale) if not IsACFEntity(this) then return end if not isOwner(self, this) then return end - if not this.Automatic then return end this:TriggerInput("Shift Speed Scale", Scale) end @@ -909,9 +897,10 @@ end e2function number entity:acfFireRate() if not IsACFEntity(this) then return 0 end if RestrictInfo(self, this) then return 0 end - if not this.ReloadTime then return 0 end - return Round(60 / this.ReloadTime, 2) + local Time = this.ReloadTime + + return Time and Round(60 / Time, 2) or 0 end -- Returns the number of rounds left in a magazine for an ACF gun @@ -1009,7 +998,7 @@ e2function number entity:acfDragCoef() if not IsACFEntity(this) then return 0 end if RestrictInfo(self, this) then return 0 end - local BulletData = BulletData + local BulletData = this.BulletData local DragCoef = BulletData and BulletData.DragCoef return DragCoef and DragCoef / ACF.DragDiv or 0 @@ -1064,7 +1053,8 @@ e2function number entity:acfFLSpikeRadius() if not IsACFEntity(this) then return 0 end if RestrictInfo(self, this) then return 0 end - local Radius = this.BulletData and this.BulletData.FlechetteRadius + local BulletData = this.BulletData + local Radius = BulletData and BulletData.FlechetteRadius return Radius and Round(Radius * 10, 2) or 0 end @@ -1098,7 +1088,7 @@ e2function number entity:acfBlastRadius() if not AmmoType then return 0 end local DisplayData = AmmoType:GetDisplayData(BulletData) - local Radius = DisplayData and DisplayData.BlastRadius + local Radius = DisplayData and DisplayData.BlastRadius return Radius and Round(Radius, 2) or 0 end diff --git a/lua/starfall/libs_sv/acffunctions.lua b/lua/starfall/libs_sv/acffunctions.lua index debe2c7c4..e6d89d63c 100644 --- a/lua/starfall/libs_sv/acffunctions.lua +++ b/lua/starfall/libs_sv/acffunctions.lua @@ -7,7 +7,7 @@ -- #gearbox -- #gun ---use an input to set reload manually, to remove timer? +--use an input to set reload manually, to remove timer? (what?) -- #ammo @@ -18,57 +18,105 @@ -- #fuel -local checkluatype = SF.CheckLuaType -local checkpermission = SF.Permissions.check -local registerprivilege = SF.Permissions.registerPrivilege +local ACF = ACF +local math = math +local match = string.match +local Restrict = GetConVar("acf_restrict_info") +local AmmoTypes = ACF.Classes.AmmoTypes +local Engines = ACF.Classes.Engines +local FuelTanks = ACF.Classes.FuelTanks +local FuelTypes = ACF.Classes.FuelTypes +local Gearboxes = ACF.Classes.Gearboxes +local Weapons = ACF.Classes.Weapons +local CheckLuaType = SF.CheckLuaType +local CheckPerms = SF.Permissions.check +local RegisterPrivilege = SF.Permissions.registerPrivilege + +local Ignored = { + LimitConVar = true, + BaseClass = true, + Loaded = true, + Lookup = true, + Class = true, + Count = true, + Items = true, +} -registerprivilege("acf.createMobility", "Create acf engine", "Allows the user to create ACF engines and gearboxes", { usergroups = { default = 3 } }) -registerprivilege("acf.createFuelTank", "Create acf fuel tank", "Allows the user to create ACF fuel tanks", { usergroups = { default = 3 } }) -registerprivilege("acf.createGun", "Create acf gun", "Allows the user to create ACF guns", { usergroups = { default = 3 } }) -registerprivilege("acf.createAmmo", "Create acf ammo", "Allows the user to create ACF ammoboxes", { usergroups = { default = 3 } } ) -registerprivilege("entities.acf", "ACF", "Allows the user to control ACF components", { entities = {} }) +RegisterPrivilege("acf.createAmmo", "Create ACF Ammo Crate", "Allows the user to create ACF Ammo Crates", { usergroups = { default = 3 } }) +RegisterPrivilege("acf.createEngine", "Create ACF Engine", "Allows the user to create ACF Engines", { usergroups = { default = 3 } }) +RegisterPrivilege("acf.createFuelTank", "Create ACF Fuel Tank", "Allows the user to create ACF Fuel Tanks", { usergroups = { default = 3 } }) +RegisterPrivilege("acf.createGearbox", "Create ACF Gearbox", "Allows the user to create ACF Gearboxes", { usergroups = { default = 3 } }) +RegisterPrivilege("acf.createWeapon", "Create ACF Weapon", "Allows the user to create ACF Weapons", { usergroups = { default = 3 } }) +RegisterPrivilege("entities.acf", "ACF", "Allows the user to control ACF components", { entities = {} }) local plyCount = SF.LimitObject("acf_components", "acf_components", -1, "The number of ACF components allowed to spawn via Starfall") local plyBurst = SF.BurstObject("acf_components", "acf_components", 4, 4, "Rate ACF components can be spawned per second.", "Number of ACF components that can be spawned in a short time.") -- [ Helper Functions ] -- -local function isEngine ( ent ) - if not validPhysics( ent ) then return false end - if ( ent:GetClass() == "acf_engine" ) then return true else return false end -end +local function IsACFEntity(Entity) + if not ACF.Check(Entity) then return false end -local function isGearbox ( ent ) - if not validPhysics( ent ) then return false end - if ( ent:GetClass() == "acf_gearbox" ) then return true else return false end -end + local Match = match(Entity:GetClass(), "^acf_") -local function isGun ( ent ) - if not validPhysics( ent ) then return false end - if ( ent:GetClass() == "acf_gun" ) then return true else return false end + return Match and true or false end -local function isRack ( ent ) - if not validPhysics( ent ) then return false end - if ( ent:GetClass() == "acf_rack" ) then return true else return false end -end +local function GetReloadTime(Entity) + local Unloading = Entity.State == "Unloading" + local NewLoad = Entity.State ~= "Loaded" and Entity.CurrentShot == 0 -local function isAmmo ( ent ) - if not validPhysics( ent ) then return false end - if ( ent:GetClass() == "acf_ammo" ) then return true else return false end + return (Unloading or NewLoad) and Entity.MagReload or Entity.ReloadTime or 0 end -local function isFuel ( ent ) - if not validPhysics(ent) then return false end - if ( ent:GetClass() == "acf_fueltank" ) then return true else return false end -end +local function GetMaxPower(Entity) + if not Entity.PeakTorque then return 0 end + + local MaxPower + + if Entity.IsElectric then + if not Entity.LimitRPM then return 0 end + + MaxPower = math.floor(Entity.PeakTorque * Entity.LimitRPM / 38195.2) --(4*9548.8) + else + if not Entity.PeakMaxRPM then return 0 end + + MaxPower = math.floor(Entity.PeakTorque * Entity.PeakMaxRPM / 9548.8) + end -local function reloadTime( ent ) - if ent.CurrentShot and ent.CurrentShot > 0 then return ent.ReloadTime end - return ent.MagReload + return MaxPower end -local propProtectionInstalled = FindMetaTable("Entity").CPPIGetOwner and true +local function GetLinkedWheels(Target) + local Current, Class, Sources + local Queued = { [Target] = true } + local Checked = {} + local Linked = {} + + while next(Queued) do + Current = next(Queued) + Class = Current:GetClass() + Sources = AllLinkSources(Class) + + Queued[Current] = nil + Checked[Current] = true + + for Name, Action in pairs(Sources) do + for Entity in pairs(Action(Current)) do + if not (Checked[Entity] or Queued[Entity]) then + if Name == "Wheels" then + Checked[Entity] = true + Linked[Entity] = true + else + Queued[Entity] = true + end + end + end + end + end + + return Linked +end ---------------------------------------- -- ACF Library @@ -80,41 +128,83 @@ SF.RegisterLibrary("acf") -- Local to each starfall return function(instance) -- Called for library declarations - -local checktype = instance.CheckType +local CheckType = instance.CheckType local acf_library = instance.Libraries.acf local owrap, ounwrap = instance.WrapObject, instance.UnwrapObject -local ents_methods, ent_meta, wrap, unwrap = instance.Types.Entity.Methods, instance.Types.Entity, instance.Types.Entity.Wrap, instance.Types.Entity.Unwrap -local ang_meta, awrap, aunwrap = instance.Types.Angle, instance.Types.Angle.Wrap, instance.Types.Angle.Unwrap -local vec_meta, vwrap, vunwrap = instance.Types.Vector, instance.Types.Vector.Wrap, instance.Types.Vector.Unwrap +local ents_methods, wrap, unwrap = instance.Types.Entity.Methods, instance.Types.Entity.Wrap, instance.Types.Entity.Unwrap +local ang_meta, aunwrap = instance.Types.Angle, instance.Types.Angle.Unwrap +local vec_meta, vunwrap = instance.Types.Vector, instance.Types.Vector.Unwrap + +local function RestrictInfo(Entity) + if not Restrict:GetBool() then return false end + + return not isOwner(instance, Entity) +end + +local function WrapTable(Table, Ignore, Checked) + local Result = {} + if not Checked then Checked = {} end + if not Ignore then Ignore = {} end -local function restrictInfo ( ent ) - if not propProtectionInstalled then return false end - if GetConVar("acf_restrict_info"):GetInt() ~= 0 then - if ent:CPPIGetOwner() ~= instance.player then return true else return false end + for K, V in pairs(Table) do + if istable(V) then + if not (Ignore[K] or Checked[V]) then + Result[K] = WrapTable(V, Ignore, Checked) + Checked[V] = true + end + elseif not Ignore[K] then + Result[K] = owrap(V) + end end - return false + + return Result end -local function propOnDestroy(ent, instance) - local ply = instance.player - plyCount:free(ply, 1) - instance.data.props.props[ent] = nil +local function UnwrapTable(Table, Checked) + local Result = {} + + if not Checked then Checked = {} end + + for K, V in pairs(Table) do + if istable(V) then + if not Checked[V] then + Result[K] = ounwrap(V) or UnwrapTable(V, Checked) + Checked[V] = true + end + else + Result[K] = ounwrap(V) + end + end + + return Result end -local function register(ent, instance) - ent:CallOnRemove("starfall_prop_delete", propOnDestroy, instance) - plyCount:free(instance.player, -1) - instance.data.props.props[ent] = true +local function OnRemove(Entity, Player) + plyCount:free(Player, 1) + + instance.data.props.props[Entity] = nil +end + +local function RegisterEntity(Entity) + local Player = instance.player + + Entity:CallOnRemove("starfall_prop_delete", OnRemove, Player) + + plyCount:free(Player, -1) + + instance.data.props.props[Entity] = true end +--===============================================================================================-- +-- General Functions +--===============================================================================================-- --- Returns true if functions returning sensitive info are restricted to owned props -- @server -- @return True if restriced, False if not function acf_library.infoRestricted() - return GetConVar("acf_restrict_info"):GetInt() ~= 0 + return Restrict:GetBool() end --- Returns current ACF drag divisor @@ -128,2275 +218,2014 @@ end -- @server -- @return The effective armor function acf_library.effectiveArmor(armor, angle) - checkluatype(armor, TYPE_NUMBER) - checkluatype(angle, TYPE_NUMBER) - + CheckLuaType(armor, TYPE_NUMBER) + CheckLuaType(angle, TYPE_NUMBER) + return math.Round(armor / math.abs(math.cos(math.rad(math.min(angle, 89.999)))), 1) end --- Dont create a cache on init because maby a new entity get registered later on? -local id_name_cache = {} -local function idFromName(list, name) - id_name_cache[list] = id_name_cache[list] or {} - - if id_name_cache[list][name] then return id_name_cache[list][name] end - - for id, data in pairs(list) do - if data.name == name then - id_name_cache[list][name] = id - - return id - end +--- Creates an ACF ammo crate using the information from the data table argument +-- @server +function acf_library.createAmmo(pos, ang, data, frozen) + CheckPerms(instance, nil, "acf.createAmmo") + + local Player = instance.player + + if not hook.Run("CanTool", Player, { Hit = true, Entity = game.GetWorld() }, "acf_menu") then + SF.Throw("No permission to spawn ACF components", 2) end + + CheckType(pos, vec_meta) + CheckType(ang, ang_meta) + CheckLuaType(data, TYPE_TABLE) + + local Position = SF.clampPos(vunwrap(pos)) + local Angles = aunwrap(ang) + local Data = UnwrapTable(data) + local Undo = not instance.data.props.undo + local Frozen = not tobool(frozen) + + local Success, Entity = ACF.CreateEntity("acf_ammo", Player, Position, Angles, Data, Undo, Frozen) + + if not Success then SF.Throw("Unable to create ACF Ammo Crate", 2) end + + plyBurst:use(Player, 1) + plyCount:checkuse(Player, 1) + + RegisterEntity(Entity) + + return owrap(Entity) end ---- Creates a engine or gearbox given the id or name --- @param pos Position of created engine or gearbox --- @param ang Angle of created engine or gearbox --- @param id id or name of the engine or gearbox to create --- @param frozen True to spawn frozen --- @param gear_ratio A table containing the gear ratios, only applied if the mobility is a gearbox. -1 is final drive --- @server --- @return The created engine or gearbox -function acf_library.createMobility(pos, ang, id, frozen, gear_ratio) - checkpermission(instance, nil, "acf.createMobility") - - local ply = instance.player - - if not hook.Run("CanTool", ply, {Hit = true, Entity = game.GetWorld()}, "acfmenu") then SF.Throw("No permission to spawn ACF components", 2) end - - checktype(pos, vec_meta) - checktype(ang, ang_meta) - checkluatype(id, TYPE_STRING) - frozen = frozen and true or false - gear_ratio = type(gear_ratio) == "table" and gear_ratio or {} - - local pos = vunwrap(pos) - local ang = aunwrap(ang) - - local list_entries = ACF.Weapons.Mobility -- REPLACE - - -- Not a valid id, try name - if not list_entries[id] then - id = idFromName(list_entries, id) - - -- Name is also invalid, error - if not id or not list_entries[id] then - SF.Throw("Invalid id or name", 2) - end +--- Creates an ACF engine using the information from the data table argument +-- @server +function acf_library.createEngine(pos, ang, data, frozen) + CheckPerms(instance, nil, "acf.createEngine") + + local Player = instance.player + + if not hook.Run("CanTool", Player, { Hit = true, Entity = game.GetWorld() }, "acf_menu") then + SF.Throw("No permission to spawn ACF components", 2) end - - local type_id = list_entries[id] - local dupe_class = duplicator.FindEntityClass(type_id.ent) - - if not dupe_class then SF.Throw("Didn't find entity duplicator records", 2) end - - plyBurst:use(ply, 1) - plyCount:checkuse(ply, 1) - - local args_table = { - SF.clampPos(pos), - ang, - id - } - - if type_id.ent == "acf_gearbox" then - for i = 1, 9 do - args_table[3 + i] = type(gear_ratio[i]) == "number" and gear_ratio[i] or (i < type_id.gears and i / 10 or -0.1) - end - - args_table[13] = type(gear_ratio[-1]) == "number" and gear_ratio[-1] or 0.5 + + CheckType(pos, vec_meta) + CheckType(ang, ang_meta) + CheckLuaType(data, TYPE_TABLE) + + local Position = SF.clampPos(vunwrap(pos)) + local Angles = aunwrap(ang) + local Data = UnwrapTable(data) + local Undo = not instance.data.props.undo + local Frozen = not tobool(frozen) + + local Success, Entity = ACF.CreateEntity("acf_engine", Player, Position, Angles, Data, Undo, Frozen) + + if not Success then SF.Throw("Unable to create ACF Engine", 2) end + + plyBurst:use(Player, 1) + plyCount:checkuse(Player, 1) + + RegisterEntity(Entity) + + return owrap(Entity) +end + +--- Creates an ACF fuel tank using the information from the data table argument +-- @server +function acf_library.createFuelTank(pos, ang, data, frozen) + CheckPerms(instance, nil, "acf.createFuelTank") + + local Player = instance.player + + if not hook.Run("CanTool", Player, { Hit = true, Entity = game.GetWorld() }, "acf_menu") then + SF.Throw("No permission to spawn ACF components", 2) end - - local ent = dupe_class.Func(ply, unpack(args_table)) - ent:Activate() - - local phys = ent:GetPhysicsObject() - if phys:IsValid() then - phys:EnableMotion(not frozen) + + CheckType(pos, vec_meta) + CheckType(ang, ang_meta) + CheckLuaType(data, TYPE_TABLE) + + local Position = SF.clampPos(vunwrap(pos)) + local Angles = aunwrap(ang) + local Data = UnwrapTable(data) + local Undo = not instance.data.props.undo + local Frozen = not tobool(frozen) + + local Success, Entity = ACF.CreateEntity("acf_fueltank", Player, Position, Angles, Data, Undo, Frozen) + + if not Success then SF.Throw("Unable to create ACF Fuel Tank", 2) end + + plyBurst:use(Player, 1) + plyCount:checkuse(Player, 1) + + RegisterEntity(Entity) + + return owrap(Entity) +end + +--- Creates an ACF gearbox using the information from the data table argument +-- @server +function acf_library.createGearbox(pos, ang, data, frozen) + CheckPerms(instance, nil, "acf.createGearbox") + + local Player = instance.player + + if not hook.Run("CanTool", Player, { Hit = true, Entity = game.GetWorld() }, "acf_menu") then + SF.Throw("No permission to spawn ACF components", 2) end - - if instance.data.props.undo then - undo.Create("ACF Mobility") - undo.SetPlayer(ply) - undo.AddEntity(ent) - undo.Finish("ACF Mobility (" .. tostring(id) .. ")") + + CheckType(pos, vec_meta) + CheckType(ang, ang_meta) + CheckLuaType(data, TYPE_TABLE) + + local Position = SF.clampPos(vunwrap(pos)) + local Angles = aunwrap(ang) + local Data = UnwrapTable(data) + local Undo = not instance.data.props.undo + local Frozen = not tobool(frozen) + + local Success, Entity = ACF.CreateEntity("acf_gearbox", Player, Position, Angles, Data, Undo, Frozen) + + if not Success then SF.Throw("Unable to create ACF Gearbox", 2) end + + plyBurst:use(Player, 1) + plyCount:checkuse(Player, 1) + + RegisterEntity(Entity) + + return owrap(Entity) +end + +--- Creates an ACF weapon using the information from the data table argument +-- @server +function acf_library.createWeapon(pos, ang, data, frozen) + CheckPerms(instance, nil, "acf.createWeapon") + + local Player = instance.player + + if not hook.Run("CanTool", Player, { Hit = true, Entity = game.GetWorld() }, "acf_menu") then + SF.Throw("No permission to spawn ACF components", 2) end - - ply:AddCleanup("props", ent) - register(ent, instance) - - return owrap(ent) -end - ---- Returns the specs of the engine or gearbox --- @param id id or name of the engine or gearbox --- @server --- @return The specs table -function acf_library.getMobilitySpecs(id) - checkluatype(id, TYPE_STRING) - - local list_entries = ACF.Weapons.Mobility -- REPLACE - - -- Not a valid id, try name - if not list_entries[id] then - id = idFromName(list_entries, id) - - -- Name is also invalid, error - if not id or not list_entries[id] then - SF.Throw("Invalid id or name", 2) - end + + CheckType(pos, vec_meta) + CheckType(ang, ang_meta) + CheckLuaType(data, TYPE_TABLE) + + local Position = SF.clampPos(vunwrap(pos)) + local Angles = aunwrap(ang) + local Data = UnwrapTable(data) + local Undo = not instance.data.props.undo + local Frozen = not tobool(frozen) + + local Success, Entity = ACF.CreateEntity("acf_gun", Player, Position, Angles, Data, Undo, Frozen) + + if not Success then SF.Throw("Unable to create ACF Weapon", 2) end + + plyBurst:use(Player, 1) + plyCount:checkuse(Player, 1) + + RegisterEntity(Entity) + + return owrap(Entity) +end + +--- Returns a list of every registered ACF ammo type +-- @server +function acf_library.listAllAmmoTypes() + local Result = {} + local Count = 0 + + for ID in pairs(AmmoTypes) do + Count = Count + 1 + + Result[Count] = ID end - - local specs = table.Copy(list_entries[id]) - specs.BaseClass = nil - - return specs + + return Result end ---- Returns a list of all mobility components +--- Returns a list of every registered ACF engine class -- @server --- @return The mobility component list -function acf_library.getAllMobility() - local list = {} - - for id, _ in pairs(ACF.Weapons.Mobility) do - table.insert(list, id) +function acf_library.listAllEngineClasses() + local Result = {} + local Count = 0 + + for _, Class in pairs(Engines) do + Count = Count + 1 + + Result[Count] = Class.ID end - - return list + + return Result end ---- Returns a list of all engines +--- Returns a list of every registered ACF engine -- @server --- @return The engine list -function acf_library.getAllEngines() - local list = {} - - for id, d in pairs(ACF.Weapons.Mobility) do - if d.ent == "acf_engine" then - table.insert(list, id) +function acf_library.listAllEngines() + local Result = {} + local Count = 0 + + for _, Class in pairs(Engines) do + for _, Engine in ipairs(Class.Items) do + Count = Count + 1 + + Result[Count] = Engine.ID end end - - return list + + return Result end ---- Returns a list of all gearboxes +--- Returns a list of every registered ACF fuel tank class -- @server --- @return The gearbox list -function acf_library.getAllGearboxes() - local list = {} - - for id, d in pairs(ACF.Weapons.Mobility) do - if d.ent == "acf_gearbox" then - table.insert(list, id) - end +function acf_library.listAllFuelTankClasses() + local Result = {} + local Count = 0 + + for _, Class in pairs(FuelTanks) do + Count = Count + 1 + + Result[Count] = Class.ID end - - return list -end - ---- Creates a fuel tank given the id --- @param pos Position of created fuel tank --- @param ang Angle of created fuel tank --- @param id id of the fuel tank to create --- @param frozen True to spawn frozen --- @param fueltype The type of fuel to use (Diesel, Electric, Petrol) --- @server --- @return The created fuel tank -function acf_library.createFuelTank(pos, ang, id, fueltype, frozen) - checkpermission(instance, nil, "acf.createFuelTank") - - local ply = instance.player - - if not hook.Run("CanTool", ply, {Hit = true, Entity = game.GetWorld()}, "acfmenu") then SF.Throw("No permission to spawn ACF components", 2) end - - checktype(pos, vec_meta) - checktype(ang, ang_meta) - checkluatype(id, TYPE_STRING) - frozen = frozen and true or false - fueltype = fueltype or "Diesel" - checkluatype(fueltype, TYPE_STRING) - - local pos = vunwrap(pos) - local ang = aunwrap(ang) - - if fueltype ~= "Diesel" and fueltype ~= "Electric" and fueltype ~= "Petrol" then SF.Throw("Invalid fuel type") end - - local list_entries = ACF.Weapons.FuelTanks -- REPLACE - if not list_entries[id] then SF.Throw("Invalid id", 2) end - - local type_id = list_entries[id] - local dupe_class = duplicator.FindEntityClass(type_id.ent) - - if not dupe_class then SF.Throw("Didn't find entity duplicator records", 2) end - - plyBurst:use(ply, 1) - plyCount:checkuse(ply, 1) - - local ent = dupe_class.Func(ply, SF.clampPos(pos), ang, "Basic_FuelTank", id, fueltype) - ent:Activate() - - local phys = ent:GetPhysicsObject() - if phys:IsValid() then - phys:EnableMotion(not frozen) + + return Result +end + +--- Returns a list of every registered ACF fuel tank +-- @server +function acf_library.listAllFuelTanks() + local Result = {} + local Count = 0 + + for _, Class in pairs(FuelTanks) do + for _, Tank in ipairs(Class.Items) do + Count = Count + 1 + + Result[Count] = Tank.ID + end end - - if instance.data.props.undo then - undo.Create("ACF Fuel Tank") - undo.SetPlayer(ply) - undo.AddEntity(ent) - undo.Finish("ACF Fuel Tank (" .. tostring(id) .. ")") + + return Result +end + +--- Returns a list of every registered ACF fuel type +-- @server +function acf_library.listAllFuelTypes() + local Result = {} + local Count = 0 + + for ID in pairs(FuelTypes) do + Count = Count + 1 + + Result[Count] = ID end - - ply:AddCleanup("props", ent) - register(ent, instance) - - return owrap(ent) + + return Result end ---- Returns the specs of the fuel tank --- @param id id of the engine or gearbox +--- Returns a list of every registered ACF gearbox class -- @server --- @return The specs table -function acf_library.getFuelTankSpecs(id) - checkluatype(id, TYPE_STRING) - - local list_entries = ACF.Weapons.FuelTanks -- REPLACE - if not list_entries[id] then SF.Throw("Invalid id", 2) end - - local specs = table.Copy(list_entries[id]) - specs.BaseClass = nil - - return specs -end - ---- Returns a list of all fuel tanks --- @server --- @return The fuel tank list -function acf_library.getAllFuelTanks() - local list = {} - - for id, _ in pairs(ACF.Weapons.FuelTanks) do - table.insert(list, id) +function acf_library.listAllGearboxClasses() + local Result = {} + local Count = 0 + + for _, Class in pairs(Gearboxes) do + Count = Count + 1 + + Result[Count] = Class.ID end - - return list -end - ---- Creates a fun given the id or name --- @param pos Position of created gun --- @param ang Angle of created gun --- @param id id or name of the gun to create --- @param frozen True to spawn frozen --- @server --- @return The created gun -function acf_library.createGun(pos, ang, id, frozen) - checkpermission(instance, nil, "acf.createGun") - - local ply = instance.player - - if not hook.Run("CanTool", ply, {Hit = true, Entity = game.GetWorld()}, "acfmenu") then SF.Throw("No permission to spawn ACF components", 2) end - - checktype(pos, vec_meta) - checktype(ang, ang_meta) - checkluatype(id, TYPE_STRING) - frozen = frozen and true or false - - local pos = vunwrap(pos) - local ang = aunwrap(ang) - - local list_entries = ACF.Weapons.Guns -- REPLACE - - -- Not a valid id, try name - if not list_entries[id] then - id = idFromName(list_entries, id) - - -- Name is also invalid, error - if not id or not list_entries[id] then - SF.Throw("Invalid id or name", 2) + + return Result +end + +--- Returns a list of every registered ACF gearbox +-- @server +function acf_library.listAllGearboxes() + local Result = {} + local Count = 0 + + for _, Class in pairs(Gearboxes) do + for _, Gearbox in ipairs(Class.Items) do + Count = Count + 1 + + Result[Count] = Gearbox.ID end end - - local type_id = list_entries[id] - local dupe_class = duplicator.FindEntityClass(type_id.ent) - - if not dupe_class then SF.Throw("Didn't find entity duplicator records", 2) end - - plyBurst:use(ply, 1) - plyCount:checkuse(ply, 1) - - local ent = dupe_class.Func(ply, SF.clampPos(pos), ang, id) - ent:Activate() - - local phys = ent:GetPhysicsObject() - if phys:IsValid() then - phys:EnableMotion(not frozen) - end - - if instance.data.props.undo then - undo.Create("ACF Gun") - undo.SetPlayer(ply) - undo.AddEntity(ent) - undo.Finish("ACF Gun (" .. tostring(id) .. ")") + + return Result +end + +--- Returns a list of every registered ACF weapon class +-- @server +function acf_library.listAllWeaponClasses() + local Result = {} + local Count = 0 + + for _, Class in pairs(Weapons) do + Count = Count + 1 + + Result[Count] = Class.ID end - - ply:AddCleanup("props", ent) - register(ent, instance) - - return owrap(ent) -end - ---- Returns the specs of gun --- @param id id or name of the gun --- @server --- @return The specs table -function acf_library.getGunSpecs(id) - checkluatype(id, TYPE_STRING) - - local list_entries = ACF.Weapons.Guns -- REPLACE - - -- Not a valid id, try name - if not list_entries[id] then - id = idFromName(list_entries, id) - - -- Name is also invalid, error - if not id or not list_entries[id] then - SF.Throw("Invalid id or name", 2) + + return Result +end + +--- Returns a list of every registered ACF weapon +-- @server +function acf_library.listAllWeapons() + local Result = {} + local Count = 0 + + for _, Class in pairs(Weapons) do + for _, Weapon in ipairs(Class.Items) do + Count = Count + 1 + + Result[Count] = Weapon.ID end end - - local specs = table.Copy(list_entries[id]) - specs.BaseClass = nil - - return specs + + return Result end ---- Returns a list of all guns +--- Returns the specifications of an ACF ammo type +-- @param id The ID of the engine class you want to get the information from -- @server --- @return The guns list -function acf_library.getAllGuns() - local list = {} - - for id, _ in pairs(ACF.Weapons.Guns) do - table.insert(list, id) - end - - return list -end - --- Set ammo properties -local ammo_properties = {} - -for id, data in pairs(ACF.RoundTypes) do -- REPLACE - ammo_properties[id] = { - name = data.name, - desc = data.desc, - model = data.model, - gun_blacklist = ACF.AmmoBlacklist[id], -- REPLACE - create_data = {} - } -end - --- No other way to get this so hardcoded here it is ;( -local ammo_property_data = { - propellantLength = { - type = "number", - default = 0.01, - data = 3, - convert = function(value) return value end - }, - - projectileLength = { - type = "number", - default = 15, - data = 4, - convert = function(value) return value end - }, - - heFillerVolume = { - type = "number", - default = 0, - data = 5, - convert = function(value) return value end - }, - - tracer = { - type = "boolean", - default = false, - data = 10, - convert = function(value) return value and 0.5 or 0 end - } -} +function acf_library.getAmmoTypeSpecs(id) + CheckLuaType(id, TYPE_STRING) -ammo_properties.AP.create_data = { - propellantLength = ammo_property_data.propellantLength, - projectileLength = ammo_property_data.projectileLength, - tracer = ammo_property_data.tracer -} + local Ammo = AmmoTypes[id] -ammo_properties.APHE.create_data = { - propellantLength = ammo_property_data.propellantLength, - projectileLength = ammo_property_data.projectileLength, - heFillerVolume = ammo_property_data.heFillerVolume, - tracer = ammo_property_data.tracer -} + if not Ammo then SF.Throw("Invalid ammo type ID, not found.", 2) end -ammo_properties.FL.create_data = { - propellantLength = ammo_property_data.propellantLength, - projectileLength = ammo_property_data.projectileLength, - flechettes = { - type = "number", - default = 6, - data = 5, - convert = function(value) return value end - }, - flechettesSpread = { - type = "number", - default = 10, - data = 6, - convert = function(value) return value end - }, - tracer = ammo_property_data.tracer -} + return WrapTable(Ammo, Ignored) +end -ammo_properties.HE.create_data = { - propellantLength = ammo_property_data.propellantLength, - projectileLength = ammo_property_data.projectileLength, - heFillerVolume = ammo_property_data.heFillerVolume, - tracer = ammo_property_data.tracer -} +--- Returns the specifications of an ACF engine class +-- @param id The ID of the engine class you want to get the information from +-- @server +function acf_library.getEngineClassSpecs(id) + CheckLuaType(id, TYPE_STRING) -ammo_properties.HEAT.create_data = { - propellantLength = ammo_property_data.propellantLength, - projectileLength = ammo_property_data.projectileLength, - heFillerVolume = ammo_property_data.heFillerVolume, - crushConeAngle = { - type = "number", - default = 0, - data = 6, - convert = function(value) return value end - }, - tracer = ammo_property_data.tracer -} + local Class = Engines[id] -ammo_properties.HP.create_data = { - propellantLength = ammo_property_data.propellantLength, - projectileLength = ammo_property_data.projectileLength, - heFillerVolume = ammo_property_data.heFillerVolume, - hollowPointCavityVolume = { - type = "number", - default = 0, - data = 5, - convert = function(value) return value end - }, - tracer = ammo_property_data.tracer -} + if not Class then SF.Throw("Invalid engine class ID, not found.", 2) end -ammo_properties.SM.create_data = { - propellantLength = ammo_property_data.propellantLength, - projectileLength = ammo_property_data.projectileLength, - smokeFillerVolume = ammo_property_data.heFillerVolume, - wpFillerVolume = { - type = "number", - default = 0, - data = 6, - convert = function(value) return value end - }, - fuseTime = { - type = "number", - default = 0, - data = 7, - convert = function(value) return value end - }, - tracer = ammo_property_data.tracer -} + return WrapTable(Class, Ignored) +end -ammo_properties.Refill.create_data = {} - ---- Creates a ammo box given the id --- If ammo_data isn't provided default values will be used (same as in the ACF menu) --- Possible values for ammo_data corresponding to ammo_id: --- @param pos Position of created ammo box --- @param ang Angle of created ammo box --- @param id id of the ammo box to create or size vector --- @param gun_id id of the gun --- @param ammo_id id of the ammo --- @param frozen True to spawn frozen --- @param ammo_data the ammo data --- @server --- @return The created ammo box --- --- AP: --- \- propellantLength (number) --- \- projectileLength (number) --- \- tracer (bool) --- --- APHE: --- \- propellantLength (number) --- \- projectileLength (number) --- \- heFillerVolume (number) --- \- tracer (bool) --- --- FL: --- \- propellantLength (number) --- \- projectileLength (number) --- \- flechettes (number) --- \- flechettesSpread (number) --- \- tracer (bool) --- --- HE: --- \- propellantLength (number) --- \- projectileLength (number) --- \- heFillerVolume (number) --- \- tracer (bool) --- --- HEAT: --- \- propellantLength (number) --- \- projectileLength (number) --- \- heFillerVolume (number) --- \- crushConeAngle (number) --- \- tracer (bool) --- --- HP: --- \- propellantLength (number) --- \- projectileLength (number) --- \- heFillerVolume (number) --- \- hollowPointCavityVolume (number) --- \- tracer (bool) --- --- SM: --- \- propellantLength (number) --- \- projectileLength (number) --- \- smokeFillerVolume (number) --- \- wpFillerVolume (number) --- \- fuseTime (number) --- \- tracer (bool) --- --- Refil: --- -function acf_library.createAmmo(pos, ang, id, gun_id, ammo_id, frozen, ammo_data) - checkpermission(instance, nil, "acf.createAmmo") - - local ply = instance.player - - if not hook.Run("CanTool", ply, {Hit = true, Entity = game.GetWorld()}, "acfmenu") then SF.Throw("No permission to spawn ACF components", 2) end - - checktype(pos, vec_meta) - checktype(ang, ang_meta) - checkluatype(ammo_id, TYPE_STRING) - checkluatype(gun_id, TYPE_STRING) - frozen = frozen and true or false - ammo_data = type(ammo_data) == "table" and ammo_data or {} - - local pos = vunwrap(pos) - local ang = aunwrap(ang) - local size - - if type(id) == "string" then - local list_entries = ACF.Weapons.Ammo -- REPLACE - local type_id = list_entries[id] - if not type_id then SF.Throw("Invalid id", 2) end - - pos = pos + LocalToWorld(type_id.Offset, Angle(), Vector(), ang) - size = type_id.Size - else - size = vunwrap(id) - end - - local ammo = ammo_properties[ammo_id] - if not ammo then SF.Throw("Invalid ammo id", 2) end - - local gun_list_entries = ACF.Weapons.Guns -- REPLACE - if not gun_list_entries[gun_id] then - gun_id = idFromName(gun_list_entries, gun_id) - - if not gun_id or not gun_list_entries[gun_id] then - SF.Throw("Invalid gun id or name", 2) - end - end - - local dupe_class = duplicator.FindEntityClass("acf_ammo") - if not dupe_class then SF.Throw("Didn't find entity duplicator records", 2) end - - plyBurst:use(ply, 1) - plyCount:checkuse(ply, 1) - - local args_table = { - SF.clampPos(pos), - ang, - gun_id, - ammo_id, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0 - } - - for k, v in pairs(ammo.create_data) do - local value = ammo_data[k] - - if value then - if type(value) == v.type then - args_table[3 + v.data] = v.convert(value) - else - args_table[3 + v.data] = v.convert(v.default) - end - else - args_table[3 + v.data] = v.convert(v.default) - end - end - - args_table[13] = size.x - args_table[14] = size.y - args_table[15] = size.z - - local ent = dupe_class.Func(ply, unpack(args_table)) - ent:Activate() - - local phys = ent:GetPhysicsObject() - if phys:IsValid() then - phys:EnableMotion(not frozen) - end - - if instance.data.props.undo then - undo.Create("ACF Ammo") - undo.SetPlayer(ply) - undo.AddEntity(ent) - undo.Finish("ACF Ammo (" .. tostring(id) .. ")") - end - - ply:AddCleanup("props", ent) - register(ent, instance) - - return owrap(ent) -end - ---- Returns the specs of the ammo --- @param id id of the ammo --- @server --- @return The specs table -function acf_library.getAmmoSpecs(id) - checkluatype(id, TYPE_STRING) - - local data = ammo_properties[id] - if not data then SF.Throw("Invalid id", 2) end - - local properties = {} - for name, d in pairs(data.create_data) do - properties[name] = { - type = d.type, - default = d.default, - convert = d.convert - } - end - - return { - name = data.name, - desc = data.desc, - model = data.model, - properties = table.Copy(data.create_data)--properties - } -end - ---- Returns a list of all ammo types --- @server --- @return The ammo list -function acf_library.getAllAmmo() - local list = {} - - for id, _ in pairs(ammo_properties) do - table.insert(list, id) - end - - return list +--- Returns the specifications of an ACF engine class +-- @param id The ID of the engine class you want to get the information from +-- @server +function acf_library.getEngineClassSpecs(id) + CheckLuaType(id, TYPE_STRING) + + local Class = Engines[id] + + if not Class then SF.Throw("Invalid engine class ID, not found.", 2) end + + return WrapTable(Class, Ignored) end ---- Returns a list of all ammo boxes +--- Returns the specifications of an ACF engine +-- @param id The ID of the engine you want to get the information from -- @server --- @return The ammo box list -function acf_library.getAllAmmoBoxes() - local list = {} - - for id, _ in pairs(ACF.Weapons.Ammo) do - table.insert(list, id) - end - - return list +function acf_library.getEngineSpecs(id) + CheckLuaType(id, TYPE_STRING) + + local Class = ACF.GetClassGroup(Engines, id) + + if not Class then SF.Throw("Invalid engine ID, not found.", 2) end + + return WrapTable(Class.Lookup[id], Ignored) end ----------------------------------------- --- Entity Methods +--- Returns the specifications of an ACF fuel tank class +-- @param id The ID of the fuel tank class you want to get the information from +-- @server +function acf_library.getFuelTankClassSpecs(id) + CheckLuaType(id, TYPE_STRING) + + local Class = FuelTanks[id] + + if not Class then SF.Throw("Invalid fuel tank class ID, not found.", 2) end + + return WrapTable(Class, Ignored) +end + +--- Returns the specifications of an ACF fuel tank +-- @param id The ID of the fuel tank you want to get the information from +-- @server +function acf_library.getFuelTankSpecs(id) + CheckLuaType(id, TYPE_STRING) + + local Class = ACF.GetClassGroup(FuelTanks, id) + + if not Class then SF.Throw("Invalid fuel tank ID, not found.", 2) end + + return WrapTable(Class.Lookup[id], Ignored) +end + +--- Returns the specifications of an ACF fuel type +-- @param id The ID of the fuel type you want to get the information from +-- @server +function acf_library.getFuelTypeSpecs(id) + CheckLuaType(id, TYPE_STRING) + + local Type = FuelTypes[id] + + if not Type then SF.Throw("Invalid fuel type ID, not found.", 2) end + + return WrapTable(Type, Ignored) +end + +--- Returns the specifications of an ACF gearbox class +-- @param id The ID of the gearbox class you want to get the information from +-- @server +function acf_library.getGearboxClassSpecs(id) + CheckLuaType(id, TYPE_STRING) --- [General Functions ] -- + local Class = Gearboxes[id] --- Moved to acf lib --- Returns true if functions returning sensitive info are restricted to owned props ---[[function ents_methods:acfInfoRestricted () - return GetConVar( "acf_restrict_info" ):GetInt() ~= 0 -end]] + if not Class then SF.Throw("Invalid gearbox class ID, not found.", 2) end + + return WrapTable(Class, Ignored) +end ---- Returns true if this entity contains sensitive info and is not accessable to us +--- Returns the specifications of an ACF gearbox +-- @param id The ID of the gearbox you want to get the information from -- @server -function ents_methods:acfIsInfoRestricted () - checktype( self, ents_metatable ) - local this = unwrap( self ) +function acf_library.getGearboxSpecs(id) + CheckLuaType(id, TYPE_STRING) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + local Class = ACF.GetClassGroup(Gearboxes, id) - return restrictInfo( this ) + if not Class then SF.Throw("Invalid gearbox ID, not found.", 2) end + + return WrapTable(Class.Lookup[id], Ignored) +end + +--- Returns the specifications of an ACF weapon class +-- @param id The ID of the weapon class you want to get the information from +-- @server +function acf_library.getWeaponClassSpecs(id) + CheckLuaType(id, TYPE_STRING) + + local Class = Weapons[id] + + if not Class then SF.Throw("Invalid weapon class ID, not found.", 2) end + + return WrapTable(Class, Ignored) +end + +--- Returns the specifications of an ACF weapon +-- @param id The ID of the weapon you want to get the information from +-- @server +function acf_library.getWeaponSpecs(id) + CheckLuaType(id, TYPE_STRING) + + local Class = ACF.GetClassGroup(Weapons, id) + + if not Class then SF.Throw("Invalid weapon ID, not found.", 2) end + + return WrapTable(Class.Lookup[id], Ignored) +end + +--- Returns true if This entity contains sensitive info and is not accessable to us +-- @server +function ents_methods:acfIsInfoRestricted() + CheckType(self, ents_metatable) + + local This = unwrap(self) + + if not ACF.Check(This) then SF.Throw("Entity is not valid", 2) end + + return RestrictInfo(This) +end + +--- Returns the full name of an ACF entity +-- @server +function ents_methods:acfName() + CheckType(self, ents_metatable) + + local This = unwrap(self) + + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return "" end + + return This.Name or "" end --- Returns the short name of an ACF entity -- @server -function ents_methods:acfNameShort () - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfNameShort() + CheckType(self, ents_metatable) + + local This = unwrap(self) + + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return "" end + + return This.ShortName or "" +end + +--- Returns the type of ACF entity +-- @server +function ents_methods:acfType() + CheckType(self, ents_metatable) + + local This = unwrap(self) + + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return "" end + + return This.EntType or "" +end + +--- Returns true if the entity is an ACF engine +-- @server +function ents_methods:acfIsEngine() + CheckType(self, ents_metatable) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + local This = unwrap(self) - if isEngine( this ) then return this.Id or "" end - if isGearbox( this ) then return this.Id or "" end - if isGun( this ) then return this.Id or "" end - if isAmmo( this ) then return this.Weapon or "" end - if isFuel( this ) then return this.FuelType .. " " .. this.SizeId end + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return false end - return "" + return This.IsEngine or false +end + +--- Returns true if the entity is an ACF gearbox +-- @server +function ents_methods:acfIsGearbox() + CheckType(self, ents_metatable) + + local This = unwrap(self) + + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return false end + + return This.IsGearbox or false +end + +--- Returns true if the entity is an ACF gun +-- @server +function ents_methods:acfIsGun() + CheckType(self, ents_metatable) + + local This = unwrap(self) + + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return false end + + return This.IsWeapon or false +end + +--- Returns true if the entity is an ACF ammo crate +-- @server +function ents_methods:acfIsAmmo() + CheckType(self, ents_metatable) + + local This = unwrap(self) + + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return false end + + return This.IsAmmoCrate or false +end + +--- Returns true if the entity is an ACF fuel tank +-- @server +function ents_methods:acfIsFuel() + CheckType(self, ents_metatable) + + local This = unwrap(self) + + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return false end + + return This.IsFuelTank or false end --- Returns the capacity of an acf ammo crate or fuel tank -- @server -function ents_methods:acfCapacity () - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfCapacity() + CheckType(self, ents_metatable) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + local This = unwrap(self) - if not ( isAmmo( this ) or isFuel( this ) ) then return 0 end - if restrictInfo( this ) then return 0 end - return this.Capacity or 1 + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return 0 end + + return This.Capacity or 0 +end + +--- Returns the path of an ACF entity's sound +-- @server +function ents_methods:acfSoundPath() + CheckType(self, ents_metatable) + + local This = unwrap(self) + + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return "" end + + return This.SoundPath or "" end --- Returns true if the acf engine, fuel tank, or ammo crate is active -- @server -function ents_methods:acfGetActive () - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfGetActive() + CheckType(self, ents_metatable) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + local This = unwrap(self) - if not ( isEngine( this ) or isAmmo( this ) or isFuel( this ) ) then return false end - if restrictInfo( this ) then return false end - if not isAmmo( this ) then - if this.Active then return true end - else - if this.Load then return true end - end - return false + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return false end + if This.CanConsume then return This:CanConsume() end + + return (This.Active or This.Load) or false end --- Turns an ACF engine, ammo crate, or fuel tank on or off +-- @param on The new active state of the entity -- @server -function ents_methods:acfSetActive ( on ) - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfSetActive(on) + CheckType(self, ents_metatable) + CheckLuaType(on, TYPE_BOOL) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end - checkpermission( instance, this, "entities.acf" ) + local This = unwrap(self) - if not ( isEngine( this ) or isAmmo( this ) or isFuel( this ) ) then return end - this:TriggerInput( "Active", on and 1 or 0 ) + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + + CheckPerms(instance, This, "entities.acf") + + -- Both have the same function on different entities + This:TriggerInput("Load", on) + This:TriggerInput("Active", on) end ---- Returns true if hitpos is on a clipped part of prop +--- Returns the current health of an entity -- @server -function ents_methods:acfHitClip( hitpos ) - checktype( self, ents_metatable ) - checktype( hitpos, vec_meta ) - local this = unwrap( self ) - local hitpos = vunwrap( hitpos ) +function ents_methods:acfPropHealth() + CheckType(self, ents_metatable) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end - checkpermission( instance, this, "entities.acf" ) -- E2 has owner check so i guess having a check if the player has permission is sufficient enough? + local This = unwrap(self) - if ACF_CheckClips( nil, nil, this, hitpos ) then return true else return false end + if not ACF.Check(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return 0 end + + local Health = This.ACF.Health + + return Health and math.Round(Health, 2) or 0 end -local linkTables = -{ -- link resources within each ent type. should point to an ent: true if adding link.Ent, false to add link itself - acf_engine = { GearLink = true, FuelLink = false }, - acf_gearbox = { WheelLink = true, Master = false }, - acf_fueltank = { Master = false }, - acf_gun = { AmmoLink = false }, - acf_ammo = { Master = false } -} +--- Returns the current armor of an entity +-- @server +function ents_methods:acfPropArmor() + CheckType(self, ents_metatable) -local function getLinks ( ent, enttype ) - local ret = {} - -- find the link resources available for this ent type - for entry, mode in pairs( linkTables[ enttype ] ) do - if not ent[ entry ] then error( "Couldn't find link resource " .. entry .. " for entity " .. tostring( ent ) ) return end + local This = unwrap(self) - -- find all the links inside the resources - for _, link in pairs( ent[ entry ] ) do - ret[ #ret + 1 ] = mode and wrap( link.Ent ) or link - end - end + if not ACF.Check(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return 0 end + + local Armor = This.ACF.Armour - return ret + return Armor and math.Round(Armor, 2) or 0 end -local function searchForGearboxLinks ( ent ) - local boxes = ents.FindByClass( "acf_gearbox" ) +--- Returns the max health of an entity +-- @server +function ents_methods:acfPropHealthMax() + CheckType(self, ents_metatable) - local ret = {} + local This = unwrap(self) - for _, box in pairs( boxes ) do - if IsValid( box ) then - for _, link in pairs( box.WheelLink ) do - if link.Ent == ent then - ret[ #ret + 1 ] = wrap( box ) - break - end - end - end - end + if not ACF.Check(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return 0 end + + local MaxHealth = This.ACF.MaxHealth - return ret + return MaxHealth and math.Round(MaxHealth, 2) or 0 end ---- Returns the ACF links associated with the entity +--- Returns the max armor of an entity -- @server -function ents_methods:acfLinks () - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfPropArmorMax() + CheckType(self, ents_metatable) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + local This = unwrap(self) - local enttype = this:GetClass() + if not ACF.Check(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return 0 end - if not linkTables[ enttype ] then - return searchForGearboxLinks( this ) - end + local MaxArmor = This.ACF.MaxArmour - return getLinks( this, enttype ) + return MaxArmor and math.Round(MaxArmor, 2) or 0 end ---- Returns the full name of an ACF entity +--- Returns the ductility of an entity -- @server -function ents_methods:acfName () - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfPropDuctility() + CheckType(self, ents_metatable) + + local This = unwrap(self) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + if not ACF.Check(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return 0 end - if isAmmo( this ) then return this.Weapon .. " " .. this.AmmoType end - if isFuel( this ) then return this.FuelType .. " " .. this.SizeId end + local Ductility = This.ACF.Ductility - local acftype = "" - if isEngine( this ) then acftype = "Mobility" end - if isGearbox( this ) then acftype = "Mobility" end - if isGun( this ) then acftype = "Guns" end - if ( acftype == "" ) then return "" end - local List = list.Get( "ACFEnts" ) - return List[ acftype ][ this.Id ][ "name" ] or "" -- REPLACE + return Ductility and math.Round(Ductility * 100, 2) or 0 end ---- Returns the type of ACF entity +--- Returns true if hitpos is on a clipped part of prop +-- @param hitpos The world hit position we want to check -- @server -function ents_methods:acfType () - checktype( self, ents_metatable ) - local this = unwrap( self ) +-- @return Returns true if hitpos is inside a visclipped part of the entity +function ents_methods:acfHitClip(hitpos) + CheckType(self, ents_metatable) + CheckType(hitpos, vec_meta) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + local This = unwrap(self) - if isEngine( this ) or isGearbox( this ) then - local List = list.Get( "ACFEnts" ) - return List[ "Mobility" ][ this.Id ][ "category" ] or "" -- REPLACE - end - if isGun( this ) then - local Classes = list.Get( "ACFClasses" ) - return Classes[ "GunClass" ][ this.Class ][ "name" ] or "" -- REPLACE - end - if isAmmo( this ) then return this.AmmoType or "" end - if isFuel( this ) then return this.FuelType or "" end - return "" + if not ACF.Check(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return false end + + local Position = vunwrap(hitpos) + + return ACF.CheckClips(This, Position) end ---- Perform ACF links +--- Returns the ACF links associated with the entity -- @server -function ents_methods:acfLinkTo ( target, notify ) - checktype( self, ents_metatable ) - checktype( target, ents_metatable ) +function ents_methods:acfLinks() + CheckType(self, ents_metatable) - local this = unwrap( self ) - local tar = unwrap( target ) + local This = unwrap(self) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end - if not ( tar and tar:IsValid() ) then SF.Throw( "Invalid Link Entity", 2 ) end + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return {} end - checkpermission( instance, this, "entities.acf" ) - checkpermission( instance, tar, "entities.acf" ) + local Result = {} + local Count = 0 - if not ( isGun( this ) or isEngine( this ) or isGearbox( this ) ) then - SF.Throw( "Target must be a gun, engine, or gearbox", 2 ) - end + for Entity in pairs(ACF.GetLinkedEntities(This)) do + Count = Count + 1 - local success, msg = this:Link( tar ) - if notify then - ACF_SendNotify( self.player, success, msg ) + Result[Count] = wrap(Entity) end - return success, msg + + return Result end ---- Perform ACF unlinks +--- Perform ACF links +-- @param target The entity to get linked to +-- @param notify If set, a notification will be sent to the player -- @server -function ents_methods:acfUnlinkFrom ( target, notify ) - checktype( self, ents_metatable ) - checktype( target, ents_metatable ) +-- @return Returns the result of the operation, along with the result message as a second argument +function ents_methods:acfLinkTo(target, notify) + CheckType(self, ents_metatable) + CheckType(target, ents_metatable) - local this = unwrap( self ) - local tar = unwrap( target ) + local This = unwrap(self) + local Target = unwrap(target) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end - if not ( tar and tar:IsValid() ) then SF.Throw( "Invalid Link Entity", 2 ) end + if not ACF.Check(This) then SF.Throw("Entity is not valid", 2) end + if not ACF.Check(Target) then SF.Throw("Invalid Link Entity", 2) end + if RestrictInfo(This) then SF.Throw("You don't have permission to link this entity to something", 2) end + if RestrictInfo(Target) then SF.Throw("You don't have permission to link something to this entity", 2) end + if not isfunction(This.Link) then SF.Throw("Entity does not support linking", 2) end - checkpermission( instance, this, "entities.acf" ) - checkpermission( instance, tar, "entities.acf" ) + CheckPerms(instance, This, "entities.acf") + CheckPerms(instance, Target, "entities.acf") - if not ( isGun( this ) or isEngine( this ) or isGearbox( this ) ) then - SF.Throw( "Target must be a gun, engine, or gearbox", 2 ) - end + local Success, Message = This:Link(Target) - local success, msg = this:Unlink( tar ) if notify then - ACF_SendNotify( self.player, success, msg ) + ACF_SendNotify(instance.player, Success, Message) end - return success, msg + + return Success, Message end ---- returns any wheels linked to this engine/gearbox or child gearboxes +--- TODO: Perform ACF unlinks -- @server -function ents_methods:acfGetLinkedWheels () - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfUnlinkFrom(target, notify) + CheckType(self, ents_metatable) + CheckType(target, ents_metatable) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end - if not ( isEngine(this) or isGearbox(this) ) then SF.Throw( "Target must be a engine, or gearbox", 2 ) end + local This = unwrap(self) + local Target = unwrap(target) - local wheels = {} - for k, ent in pairs( ACF_GetLinkedWheels( this ) ) do - table.insert( wheels, wrap( ent ) ) - end - - return wheels -end + if not ACF.Check(This) then SF.Throw("Entity is not valid", 2) end + if not ACF.Check(Target) then SF.Throw("Invalid Link Entity", 2) end + if RestrictInfo(This) then SF.Throw("You don't have permission to unlink this entity from something", 2) end + if RestrictInfo(Target) then SF.Throw("You don't have permission to unlink something from this entity", 2) end + if not isfunction(This.Unlink) then SF.Throw("Entity does not support unlinking", 2) end --- [ Engine Functions ] -- + CheckPerms(instance, This, "entities.acf") + CheckPerms(instance, Target, "entities.acf") ---- Returns true if the entity is an ACF engine --- @server -function ents_methods:acfIsEngine () - checktype( self, ents_metatable ) - local this = unwrap( self ) + local Success, Message = This:Unlink(Target) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + if notify then + ACF_SendNotify(instance.player, Success, Message) + end - return isEngine( this ) + return Success, Message end +--===============================================================================================-- +-- Mobility Functions +--===============================================================================================-- + --- Returns true if an ACF engine is electric -- @server -function ents_methods:acfIsElectric () - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfIsElectric() + CheckType(self, ents_metatable) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + local This = unwrap(self) - return this.iselec == true + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return false end + + return This.IsElectric or false end --- Returns the torque in N/m of an ACF engine -- @server -function ents_methods:acfMaxTorque () - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfMaxTorque() + CheckType(self, ents_metatable) + + local This = unwrap(self) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return 0 end - if not isEngine( this ) then return 0 end - return this.PeakTorque or 0 + return This.PeakTorque or 0 end ---- Returns the torque in N/m of an ACF engine with fuel +--- Returns the power in kW of an ACF engine -- @server -function ents_methods:acfMaxTorqueWithFuel () - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfMaxPower() + CheckType(self, ents_metatable) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + local This = unwrap(self) - if not isEngine( this ) then return 0 end - return this.PeakTorque or 0 -end + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return 0 end -local function getMaxPower( ent ) - local peakpower - - if ent.iselec then - peakpower = math.floor( ent.PeakTorque * ent.LimitRPM / ( 4 * 9548.8 ) ) - else - peakpower = math.floor( ent.PeakTorque * ent.PeakMaxRPM / 9548.8 ) - end - - return peakpower or 0 + return GetMaxPower(This) end ---- Returns the power in kW of an ACF engine +--- (DEPRECATED) Returns the torque in N/m of an ACF engine. Use Entity:acfMaxTorque() -- @server -function ents_methods:acfMaxPower () - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfMaxTorqueWithFuel() + CheckType(self, ents_metatable) + + local This = unwrap(self) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return 0 end - return isEngine( this ) and getMaxPower( this ) or 0 + return This.PeakTorque or 0 end ---- Returns the power in kW of an ACF engine with fuel +--- (DEPRECATED) Returns the power in kW of an ACF engine. Use Entity:acfMaxPower() -- @server -function ents_methods:acfMaxPowerWithFuel () - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfMaxPowerWithFuel() + CheckType(self, ents_metatable) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + local This = unwrap(self) - return isEngine( this ) and getMaxPower( this ) or 0 + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return 0 end + + return GetMaxPower(This) end --- Returns the idle rpm of an ACF engine -- @server -function ents_methods:acfIdleRPM () - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfIdleRPM() + CheckType(self, ents_metatable) + + local This = unwrap(self) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return 0 end - if not isEngine( this ) then return 0 end - return this.IdleRPM or 0 + return This.IdleRPM or 0 end --- Returns the powerband min and max of an ACF Engine -- @server -function ents_methods:acfPowerband () - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfPowerband() + CheckType(self, ents_metatable) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + local This = unwrap(self) - if not isEngine( this ) then return 0, 0 end - return this.PeakMinRPM or 0, this.PeakMaxRPM or 0 + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return 0, 0 end + + return This.PeakMinRPM or 0, This.PeakMaxRPM or 0 end --- Returns the powerband min of an ACF engine -- @server -function ents_methods:acfPowerbandMin () - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfPowerbandMin() + CheckType(self, ents_metatable) + + local This = unwrap(self) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return 0 end - if not isEngine( this ) then return 0 end - return this.PeakMinRPM or 0 + return This.PeakMinRPM or 0 end --- Returns the powerband max of an ACF engine -- @server -function ents_methods:acfPowerbandMax () - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfPowerbandMax() + CheckType(self, ents_metatable) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + local This = unwrap(self) - if not isEngine( this ) then return 0 end - return this.PeakMaxRPM or 0 + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return 0 end + + return This.PeakMaxRPM or 0 end --- Returns the redline rpm of an ACF engine -- @server -function ents_methods:acfRedline () - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfRedline() + CheckType(self, ents_metatable) + + local This = unwrap(self) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return 0 end - if not isEngine( this ) then return 0 end - return this.LimitRPM or 0 + return This.LimitRPM or 0 end --- Returns the current rpm of an ACF engine -- @server -function ents_methods:acfRPM () - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfRPM() + CheckType(self, ents_metatable) + + local This = unwrap(self) + + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return 0 end - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + local RPM = This.FlyRPM - if not isEngine( this ) then return 0 end - if restrictInfo( this ) then return 0 end - return math.floor( this.FlyRPM ) or 0 + return RPM and math.floor(RPM) or 0 end --- Returns the current torque of an ACF engine -- @server -function ents_methods:acfTorque () - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfTorque() + CheckType(self, ents_metatable) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + local This = unwrap(self) - if not isEngine( this ) then return 0 end - if restrictInfo( this ) then return 0 end - return math.floor( this.Torque or 0 ) + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return 0 end + + local Torque = This.Torque + + return Torque and math.floor(Torque) or 0 end --- Returns the inertia of an ACF engine's flywheel -- @server -function ents_methods:acfFlyInertia () - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfFlyInertia() + CheckType(self, ents_metatable) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + local This = unwrap(self) - if not isEngine( this ) then return nil end - if restrictInfo( this ) then return 0 end - return this.Inertia or 0 + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return 0 end + + return This.Inertia or 0 end --- Returns the mass of an ACF engine's flywheel -- @server -function ents_methods:acfFlyMass () - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfFlyMass() + CheckType(self, ents_metatable) + + local This = unwrap(self) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return 0 end - if not isEngine( this ) then return nil end - if restrictInfo( this ) then return 0 end - return this.Inertia / ( 3.1416 )^2 or 0 + return This.FlywheelMass or 0 end --- Returns the current power of an ACF engine -- @server -function ents_methods:acfPower () - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfPower() + CheckType(self, ents_metatable) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + local This = unwrap(self) - if not isEngine( this ) then return 0 end - if restrictInfo( this ) then return 0 end - return math.floor( ( this.Torque or 0 ) * ( this.FlyRPM or 0 ) / 9548.8 ) + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return 0 end + if not This.Torque then return 0 end + if not This.FlyRPM then return 0 end + + return math.floor(This.Torque * This.FlyRPM / 9548.8) end --- Returns true if the RPM of an ACF engine is inside the powerband -- @server -function ents_methods:acfInPowerband () - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfInPowerband() + CheckType(self, ents_metatable) + + local This = unwrap(self) + + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return false end + if not This.FlyRPM then return false end + + local PowerbandMin, PowerbandMax - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + if This.IsElectric then + PowerbandMin = This.IdleRPM + PowerbandMax = floor((This.LimitRPM or 0) * 0.5) + else + PowerbandMin = This.PeakMinRPM + PowerbandMax = This.PeakMaxRPM + end - if not isEngine( this ) then return false end - if restrictInfo( this ) then return false end - if ( this.FlyRPM < this.PeakMinRPM ) then return false end - if ( this.FlyRPM > this.PeakMaxRPM ) then return false end + if not PowerbandMin then return false end + if not PowerbandMax then return false end + if This.FlyRPM < PowerbandMin then return false end + if This.FlyRPM > PowerbandMax then return false end return true end --- Returns the throttle value -- @server -function ents_methods:acfGetThrottle () - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfGetThrottle() + CheckType(self, ents_metatable) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end - - if not isEngine( this ) then return 0 end - if restrictInfo( this ) then return 0 end - return ( this.Throttle or 0 ) * 100 -end + local This = unwrap(self) ---- Sets the throttle value for an ACF engine --- @server -function ents_methods:acfSetThrottle ( throttle ) - checktype( self, ents_metatable ) - checkluatype( throttle, TYPE_NUMBER ) - local this = unwrap( self ) + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return 0 end - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end - checkpermission( instance, this, "entities.acf" ) + local Throttle = This.Throttle - if not isEngine( this ) then return end - this:TriggerInput( "Throttle", throttle ) + return Throttle and Throttle * 100 or 0 end +--- Sets the throttle value for an ACF engine +-- @server +function ents_methods:acfSetThrottle(throttle) + CheckType(self, ents_metatable) + CheckLuaType(throttle, TYPE_NUMBER) --- [ Gearbox Functions ] -- + local This = unwrap(self) ---- Returns true if the entity is an ACF gearbox --- @server -function ents_methods:acfIsGearbox () - checktype( self, ents_metatable ) - local this = unwrap( self ) + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return end - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + CheckPerms(instance, This, "entities.acf") - return isGearbox( this ) + This:TriggerInput("Throttle", throttle) end --- Returns the current gear for an ACF gearbox -- @server -function ents_methods:acfGear () - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfGear() + CheckType(self, ents_metatable) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + local This = unwrap(self) - if not isGearbox( this ) then return 0 end - if restrictInfo( this ) then return 0 end - return this.Gear or 0 + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return 0 end + + return This.Gear or 0 end --- Returns the number of gears for an ACF gearbox -- @server -function ents_methods:acfNumGears () - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfNumGears() + CheckType(self, ents_metatable) + + local This = unwrap(self) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return 0 end - if not isGearbox( this ) then return 0 end - if restrictInfo( this ) then return 0 end - return this.Gears or 0 + return This.GearCount or 0 end --- Returns the final ratio for an ACF gearbox -- @server -function ents_methods:acfFinalRatio () - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfFinalRatio() + CheckType(self, ents_metatable) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + local This = unwrap(self) - if not isGearbox( this ) then return 0 end - if restrictInfo( this ) then return 0 end - return this.GearTable[ "Final" ] or 0 + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return 0 end + + return This.FinalDrive or 0 end --- Returns the total ratio (current gear * final) for an ACF gearbox -- @server -function ents_methods:acfTotalRatio () - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfTotalRatio() + CheckType(self, ents_metatable) + + local This = unwrap(self) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return 0 end - if not isGearbox( this ) then return 0 end - if restrictInfo( this ) then return 0 end - return this.GearRatio or 0 + return This.GearRatio or 0 end --- Returns the max torque for an ACF gearbox -- @server -function ents_methods:acfTorqueRating () - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfTorqueRating() + CheckType(self, ents_metatable) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + local This = unwrap(self) - if not isGearbox( this ) then return 0 end - return this.MaxTorque or 0 + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return 0 end + + return This.MaxTorque or 0 end --- Returns whether an ACF gearbox is dual clutch -- @server -function ents_methods:acfIsDual () - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfIsDual() + CheckType(self, ents_metatable) + + local This = unwrap(self) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return false end - if not isGearbox( this ) then return false end - if restrictInfo( this ) then return false end - - return this.Dual + return This.DualClutch or false end --- Returns the time in ms an ACF gearbox takes to change gears -- @server -function ents_methods:acfShiftTime () - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfShiftTime() + CheckType(self, ents_metatable) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + local This = unwrap(self) - if not isGearbox( this ) then return 0 end - return ( this.SwitchTime or 0 ) * 1000 + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return 0 end + + local Time = This.SwitchTime + + return Time and Time * 1000 or 0 end --- Returns true if an ACF gearbox is in gear -- @server -function ents_methods:acfInGear () - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfInGear() + CheckType(self, ents_metatable) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + local This = unwrap(self) - if not isGearbox( this ) then return false end - if restrictInfo( this ) then return false end - - return this.InGear + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return false end + + return This.InGear or false end --- Returns the ratio for a specified gear of an ACF gearbox -- @server -function ents_methods:acfGearRatio ( gear ) - checktype( self, ents_metatable ) - checkluatype( gear, TYPE_NUMBER ) - local this = unwrap( self ) +function ents_methods:acfGearRatio(gear) + CheckType(self, ents_metatable) + CheckLuaType(gear, TYPE_NUMBER) + + local This = unwrap(self) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return 0 end + if not This.Gears then return 0 end - if not isGearbox( this ) then return 0 end - if restrictInfo( this ) then return 0 end - local g = math.Clamp( math.floor( gear ), 1, this.Gears ) - return this.GearTable[ g ] or 0 + return This.Gears[math.floor(gear)] or 0 end --- Returns the current torque output for an ACF gearbox -- @server -function ents_methods:acfTorqueOut () - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfTorqueOut() + CheckType(self, ents_metatable) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + local This = unwrap(self) - if not isGearbox( this ) then return 0 end - return math.min( this.TotalReqTq or 0, this.MaxTorque or 0 ) / ( this.GearRatio or 1 ) + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return 0 end + + return math.min(This.TotalReqTq or 0, This.MaxTorque or 0) / (This.GearRatio or 1) end --- Sets the gear ratio of a CVT, set to 0 to use built-in algorithm -- @server -function ents_methods:acfCVTRatio ( ratio ) - checktype( self, ents_metatable ) - checkluatype( ratio, TYPE_NUMBER ) - local this = unwrap( self ) +function ents_methods:acfCVTRatio(ratio) + CheckType(self, ents_metatable) + CheckLuaType(ratio, TYPE_NUMBER) + + local This = unwrap(self) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end - checkpermission( instance, this, "entities.acf" ) + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return end + if not This.CVT then return end - if not isGearbox( this ) then return end - if restrictInfo( this ) then return end - if not this.CVT then return end - this.CVTRatio = math.Clamp( ratio, 0, 1 ) + CheckPerms(instance, This, "entities.acf") + + This:TriggerInput("CVT Ratio", math.Clamp(ratio, 0, 1)) end --- Sets the current gear for an ACF gearbox -- @server -function ents_methods:acfShift ( gear ) - checktype( self, ents_metatable ) - checkluatype( gear, TYPE_NUMBER ) - local this = unwrap( self ) +function ents_methods:acfShift(gear) + CheckType(self, ents_metatable) + CheckLuaType(gear, TYPE_NUMBER) + + local This = unwrap(self) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end - checkpermission( instance, this, "entities.acf" ) + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return end - if not isGearbox( this ) then return end - if restrictInfo( this ) then return end - this:TriggerInput( "Gear", gear ) + CheckPerms(instance, This, "entities.acf") + + This:TriggerInput("Gear", gear) end --- Cause an ACF gearbox to shift up -- @server -function ents_methods:acfShiftUp () - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfShiftUp() + CheckType(self, ents_metatable) + + local This = unwrap(self) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end - checkpermission( instance, this, "entities.acf" ) + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return end - if not isGearbox( this ) then return end - if restrictInfo( this ) then return end - this:TriggerInput( "Gear Up", 1 ) --doesn't need to be toggled off + CheckPerms(instance, This, "entities.acf") + + This:TriggerInput("Gear Up", true) --doesn't need to be toggled off end --- Cause an ACF gearbox to shift down -- @server -function ents_methods:acfShiftDown () - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfShiftDown() + CheckType(self, ents_metatable) + + local This = unwrap(self) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end - checkpermission( instance, this, "entities.acf" ) + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return end - if not isGearbox( this ) then return end - if restrictInfo( this ) then return end - this:TriggerInput( "Gear Down", 1 ) --doesn't need to be toggled off + CheckPerms(instance, This, "entities.acf") + + This:TriggerInput("Gear Down", true) --doesn't need to be toggled off end --- Sets the brakes for an ACF gearbox -- @server -function ents_methods:acfBrake ( brake ) - checktype( self, ents_metatable ) - checkluatype( brake, TYPE_NUMBER ) - local this = unwrap( self ) +function ents_methods:acfBrake(brake) + CheckType(self, ents_metatable) + CheckLuaType(brake, TYPE_NUMBER) + + local This = unwrap(self) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end - checkpermission( instance, this, "entities.acf" ) + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return end - if not isGearbox( this ) then return end - if restrictInfo( this ) then return end - this:TriggerInput( "Brake", brake ) + CheckPerms(instance, This, "entities.acf") + + This:TriggerInput("Brake", brake) end --- Sets the left brakes for an ACF gearbox -- @server -function ents_methods:acfBrakeLeft ( brake ) - checktype( self, ents_metatable ) - checkluatype( brake, TYPE_NUMBER ) - local this = unwrap( self ) +function ents_methods:acfBrakeLeft(brake) + CheckType(self, ents_metatable) + CheckLuaType(brake, TYPE_NUMBER) + + local This = unwrap(self) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end - checkpermission( instance, this, "entities.acf" ) + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return end - if not isGearbox( this ) then return end - if restrictInfo( this ) then return end - if not this.Dual then return end - this:TriggerInput( "Left Brake", brake ) + CheckPerms(instance, This, "entities.acf") + + This:TriggerInput("Left Brake", brake) end --- Sets the right brakes for an ACF gearbox -- @server -function ents_methods:acfBrakeRight ( brake ) - checktype( self, ents_metatable ) - checkluatype( brake, TYPE_NUMBER ) - local this = unwrap( self ) +function ents_methods:acfBrakeRight(brake) + CheckType(self, ents_metatable) + CheckLuaType(brake, TYPE_NUMBER) + + local This = unwrap(self) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end - checkpermission( instance, this, "entities.acf" ) + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return end - if not isGearbox( this ) then return end - if restrictInfo( this ) then return end - if not this.Dual then return end - this:TriggerInput("Right Brake", brake ) + CheckPerms(instance, This, "entities.acf") + + This:TriggerInput("Right Brake", brake) end --- Sets the clutch for an ACF gearbox -- @server -function ents_methods:acfClutch ( clutch ) - checktype( self, ents_metatable ) - checkluatype( clutch, TYPE_NUMBER ) - local this = unwrap( self ) +function ents_methods:acfClutch(clutch) + CheckType(self, ents_metatable) + CheckLuaType(clutch, TYPE_NUMBER) + + local This = unwrap(self) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end - checkpermission( instance, this, "entities.acf" ) + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return end - if not isGearbox( this ) then return end - if restrictInfo( this ) then return end - this:TriggerInput( "Clutch", clutch ) + CheckPerms(instance, This, "entities.acf") + + This:TriggerInput("Clutch", clutch) end --- Sets the left clutch for an ACF gearbox -- @server -function ents_methods:acfClutchLeft( clutch ) - checktype( self, ents_metatable ) - checkluatype( clutch, TYPE_NUMBER ) - local this = unwrap( self ) +function ents_methods:acfClutchLeft(clutch) + CheckType(self, ents_metatable) + CheckLuaType(clutch, TYPE_NUMBER) + + local This = unwrap(self) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end - checkpermission( instance, this, "entities.acf" ) + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return end - if not isGearbox( this ) then return end - if restrictInfo( this ) then return end - if not this.Dual then return end - this:TriggerInput( "Left Clutch", clutch ) + CheckPerms(instance, This, "entities.acf") + + This:TriggerInput("Left Clutch", clutch) end --- Sets the right clutch for an ACF gearbox -- @server -function ents_methods:acfClutchRight ( clutch ) - checktype( self, ents_metatable ) - checkluatype( clutch, TYPE_NUMBER ) - local this = unwrap( self ) +function ents_methods:acfClutchRight(clutch) + CheckType(self, ents_metatable) + CheckLuaType(clutch, TYPE_NUMBER) + + local This = unwrap(self) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end - checkpermission( instance, this, "entities.acf" ) + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return end - if not isGearbox( this ) then return end - if restrictInfo( this ) then return end - if not this.Dual then return end - this:TriggerInput( "Right Clutch", clutch ) + CheckPerms(instance, This, "entities.acf") + + This:TriggerInput("Right Clutch", clutch) end --- Sets the steer ratio for an ACF gearbox -- @server -function ents_methods:acfSteerRate ( rate ) - checktype( self, ents_metatable ) - checkluatype( rate, TYPE_NUMBER ) - local this = unwrap( self ) +function ents_methods:acfSteerRate(rate) + CheckType(self, ents_metatable) + CheckLuaType(rate, TYPE_NUMBER) + + local This = unwrap(self) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end - checkpermission( instance, this, "entities.acf" ) + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return end - if not isGearbox( this ) then return end - if restrictInfo( this ) then return end - if not this.DoubleDiff then return end - this:TriggerInput( "Steer Rate", rate ) + CheckPerms(instance, This, "entities.acf") + + This:TriggerInput("Steer Rate", rate) end --- Applies gear hold for an automatic ACF gearbox -- @server -function ents_methods:acfHoldGear( hold ) - checktype( self, ents_metatable ) - checkluatype( hold, TYPE_NUMBER ) - local this = unwrap( self ) +function ents_methods:acfHoldGear(hold) + CheckType(self, ents_metatable) + CheckLuaType(hold, TYPE_BOOL) + + local This = unwrap(self) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end - checkpermission( instance, this, "entities.acf" ) + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return end - if not isGearbox( this ) then return end - if restrictInfo( this ) then return end - if not this.Auto then return end - this:TriggerInput( "Hold Gear", hold ) + CheckPerms(instance, This, "entities.acf") + + This:TriggerInput("Hold Gear", hold) end --- Sets the shift point scaling for an automatic ACF gearbox -- @server -function ents_methods:acfShiftPointScale( scale ) - checktype( self, ents_metatable ) - checkluatype( scale, TYPE_NUMBER ) - local this = unwrap( self ) +function ents_methods:acfShiftPointScale(scale) + CheckType(self, ents_metatable) + CheckLuaType(scale, TYPE_NUMBER) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end - checkpermission( instance, this, "entities.acf" ) + local This = unwrap(self) - if not isGearbox( this ) then return end - if restrictInfo( this ) then return end - if not this.Auto then return end - this:TriggerInput( "Shift Speed Scale", scale ) -end + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return end + CheckPerms(instance, This, "entities.acf") --- [ Gun Functions ] -- + This:TriggerInput("Shift Speed Scale", scale) +end ---- Returns true if the entity is an ACF gun +--- Sets the ACF fuel tank refuel duty status, which supplies fuel to other fuel tanks -- @server -function ents_methods:acfIsGun () - checktype( self, ents_metatable ) - local this = unwrap( self ) - - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end +function ents_methods:acfRefuelDuty(on) + CheckType(self, ents_metatable) + CheckLuaType(on, TYPE_BOOL) - if isGun( this ) and not restrictInfo( this ) then return true else return false end -end + local This = unwrap(self) ---- Returns true if the ACF gun is ready to fire --- @server -function ents_methods:acfReady () - checktype( self, ents_metatable ) - local this = unwrap( self ) + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return end - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + CheckPerms(instance, This, "entities.acf") - if not isGun( this ) then return false end - if restrictInfo( this ) then return false end - if ( this.Ready ) then return true end - return false + This:TriggerInput("Refuel Duty", on) end ---- Returns the magazine size for an ACF gun +--- Returns the remaining liters or kilowatt hours of fuel in an ACF fuel tank or engine -- @server -function ents_methods:acfMagSize () - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfFuel() + CheckType(self, ents_metatable) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + local This = unwrap(self) - if not isGun( this ) then return 0 end - return this.MagSize or 1 -end + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return 0 end + if This.Fuel then return math.Round(This.Fuel, 2) end ---- Returns the spread for an ACF gun or flechette ammo --- @server -function ents_methods:acfSpread () - checktype( self, ents_metatable ) - local this = unwrap( self ) + local Source = LinkSource(This:GetClass(), "FuelTanks") - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + if not Source then return 0 end - if not isGun( this ) or isAmmo( this ) then return 0 end - local Spread = this.GetInaccuracy and this:GetInaccuracy() or this.Inaccuracy or 0 - if this.BulletData[ "Type" ] == "FL" then - if restrictInfo( this ) then return Spread end - return Spread + ( this.BulletData[ "FlechetteSpread" ] or 0 ) + local Fuel = 0 + + for Tank in pairs(Source(This)) do + Fuel = Fuel + Tank.Fuel end - return Spread + + return math.Round(Fuel, 2) end ---- Returns true if an ACF gun is reloading +--- Returns the amount of fuel in an ACF fuel tank or linked to engine as a percentage of capacity -- @server -function ents_methods:acfIsReloading () - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfFuelLevel() + CheckType(self, ents_metatable) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + local This = unwrap(self) - if not isGun( this ) then return false end - if restrictInfo( this ) then return false end - if (this.Reloading) then return true end - return false -end + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return 0 end + if This.Capacity then + return math.Round(This.Fuel or 0 / This.Capacity, 2) + end ---- Returns the rate of fire of an acf gun --- @server -function ents_methods:acfFireRate () - checktype( self, ents_metatable ) - local this = unwrap( self ) + local Source = LinkSource(This:GetClass(), "FuelTanks") + + if not Source then return 0 end - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + local Capacity = 0 + local Fuel = 0 - if not isGun( this ) then return 0 end - return math.Round( this.RateOfFire or 0, 3 ) + for Tank in pairs(Source(This)) do + Capacity = Capacity + Tank.Capacity + Fuel = Fuel + Tank.Fuel + end + + return math.Round(Fuel / Capacity, 2) end ---- Returns the number of rounds left in a magazine for an ACF gun +--- Returns the current fuel consumption in liters per minute or kilowatts of an engine -- @server -function ents_methods:acfMagRounds () - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfFuelUse() + CheckType(self, ents_metatable) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + local This = unwrap(self) - if not isGun( this ) then return 0 end - if restrictInfo( this ) then return 0 end - if this.MagSize > 1 then - return ( this.MagSize - this.CurrentShot ) or 1 - end - if this.Ready then return 1 end - return 0 + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return 0 end + if not This.GetConsumption then return 0 end + if not This.Throttle then return 0 end + if not This.FlyRPM then return 0 end + + return This:GetConsumption(This.Throttle, This.FlyRPM) * 60 end ---- Sets the firing state of an ACF weapon +--- Returns the peak fuel consumption in liters per minute or kilowatts of an engine at powerband max, for the current fuel type the engine is using -- @server -function ents_methods:acfFire ( fire ) - checktype( self, ents_metatable ) - checkluatype( fire, TYPE_NUMBER ) - local this = unwrap( self ) +function ents_methods:acfPeakFuelUse() + CheckType(self, ents_metatable) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end - checkpermission( instance, this, "entities.acf" ) + local This = unwrap(self) - if not isGun( this ) then return end - - this:TriggerInput( "Fire", fire ) + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return 0 end + if not This.GetConsumption then return 0 end + if not This.LimitRPM then return 0 end + + return This:GetConsumption(1, This.LimitRPM) * 60 end ---- Causes an ACF weapon to unload +--- returns any wheels linked to This engine/gearbox or child gearboxes -- @server -function ents_methods:acfUnload () - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfGetLinkedWheels() + CheckType(self, ents_metatable) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end - checkpermission( instance, this, "entities.acf" ) + local This = unwrap(self) - if not isGun( this ) then return end - - this:UnloadAmmo() -end + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return {} end ---- Causes an ACF weapon to reload --- @server -function ents_methods:acfReload () - checktype( self, ents_metatable ) - local this = unwrap( self ) + local Wheels = {} + local Count = 0 - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end - checkpermission( instance, this, "entities.acf" ) + for Wheel in pairs(GetLinkedWheels(This)) do + Count = Count + 1 + Wheels[Count] = Wheel + end - if not isGun( this ) then return end - - this.Reloading = true + return Wheels end ---- Returns the number of rounds in active ammo crates linked to an ACF weapon +--- Returns true if the ACF gun is ready to fire -- @server -function ents_methods:acfAmmoCount () - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfReady() + CheckType(self, ents_metatable) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + local This = unwrap(self) - if not isGun( this ) then return 0 end - if restrictInfo( this ) then return 0 end - local Ammo = 0 - for AmmoEnt in pairs( this.Crates ) do - if AmmoEnt and AmmoEnt:IsValid() and AmmoEnt[ "Load" ] then - Ammo = Ammo + ( AmmoEnt.Ammo or 0 ) - end - end - return Ammo + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return false end + + return This.State == "Loaded" end ---- Returns the number of rounds in all ammo crates linked to an ACF weapon +--- Returns a string with the current state of the entity -- @server -function ents_methods:acfTotalAmmoCount () - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfState() + CheckType(self, ents_metatable) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + local This = unwrap(self) - if not isGun( this ) then return 0 end - if restrictInfo( this ) then return 0 end - local Ammo = 0 - for AmmoEnt in pairs( this.Crates ) do - if AmmoEnt and AmmoEnt:IsValid() then - Ammo = Ammo + ( AmmoEnt.Ammo or 0 ) - end - end - return Ammo + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return "" end + + return This.State or "" end --- Returns time to next shot of an ACF weapon -- @server -function ents_methods:acfReloadTime () - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfReloadTime() + CheckType(self, ents_metatable) + + local This = unwrap(self) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return 0 end + if This.State == "Loaded" then return 0 end - if restrictInfo( this ) or not isGun( this ) or this.Ready then return 0 end - return reloadTime( this ) + return GetReloadTime(This) end --- Returns number between 0 and 1 which represents reloading progress of an ACF weapon. Useful for progress bars -- @server -function ents_methods:acfReloadProgress () - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfReloadProgress() + CheckType(self, ents_metatable) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + local This = unwrap(self) - if restrictInfo( this ) or not isGun( this ) or this.Ready then return 1 end - return math.Clamp( 1 - (this.NextFire - CurTime()) / reloadTime( this ), 0, 1 ) + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return 0 end + if not This.NextFire then return This.State == "Loaded" and 1 or 0 end + + return math.Clamp(1 - (This.NextFire - ACF.CurTime) / GetReloadTime(This), 0, 1) end --- Returns time it takes for an ACF weapon to reload magazine -- @server -function ents_methods:acfMagReloadTime () - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfMagReloadTime() + CheckType(self, ents_metatable) + + local This = unwrap(self) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return 0 end - if restrictInfo( instance.player , this ) or not isGun( this ) or not this.MagReload then return 0 end - return this.MagReload + return This.MagReload or 0 end --- [ Ammo Functions ] -- +--- Returns the magazine size for an ACF gun +-- @server +function ents_methods:acfMagSize() + CheckType(self, ents_metatable) + + local This = unwrap(self) ---- Returns true if the entity is an ACF ammo crate + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return 0 end + + return This.MagSize or 0 +end + +--- Returns the spread for an ACF gun or flechette ammo -- @server -function ents_methods:acfIsAmmo () - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfSpread() + CheckType(self, ents_metatable) + + local This = unwrap(self) + + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return 0 end - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + local Spread = (This.GetSpread and This:GetSpread()) or This.Spread or 0 - return isAmmo( this ) and not restrictInfo( this ) + if This.BulletData and This.BulletData.Type == "FL" then -- TODO: Replace this hardcoded bit + return Spread + (This.BulletData.FlechetteSpread or 0) + end + + return Spread end ---- Returns the rounds left in an acf ammo crate +--- Returns true if an ACF gun is reloading -- @server -function ents_methods:acfRounds () - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfIsReloading() + CheckType(self, ents_metatable) + + local This = unwrap(self) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return false end - if not isAmmo( this ) then return 0 end - if restrictInfo( this ) then return 0 end - return this.Ammo or 0 + return This.State == "Loading" end ---- Returns the type of weapon the ammo in an ACF ammo crate loads into +--- Returns the rate of fire of an acf gun -- @server -function ents_methods:acfRoundType () --cartridge? - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfFireRate() + CheckType(self, ents_metatable) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + local This = unwrap(self) - if not isAmmo( this ) then return "" end - if restrictInfo( this ) then return "" end + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return 0 end - return this.AmmoType or "" -- E2 uses this one now + local Time = This.ReloadTime + + return Time and math.Round(60 / Time, 2) or 0 end ---- Returns the type of ammo in a crate or gun +--- Returns the number of rounds left in a magazine for an ACF gun -- @server -function ents_methods:acfAmmoType () - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfMagRounds() + CheckType(self, ents_metatable) + + local This = unwrap(self) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return 0 end - if not isAmmo( this ) or isGun( this ) then return "" end - if restrictInfo( this ) then return "" end - return this.BulletData[ "Type" ] or "" + return This.CurrentShot or 0 end ---- Returns the caliber of an ammo or gun +--- Sets the firing state of an ACF weapon -- @server -function ents_methods:acfCaliber () - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfFire(fire) + CheckType(self, ents_metatable) + CheckLuaType(fire, TYPE_BOOL) + + local This = unwrap(self) + + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return end - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + CheckPerms(instance, This, "entities.acf") - if not ( isAmmo( this ) or isGun( this ) or isRack( this )) then return 0 end - if restrictInfo( this ) then return 0 end + This:TriggerInput("Fire", fire) +end - if not this.Caliber then -- If not a gun or ammo crate - if not this.BulletData then return 0 end -- If not a a rack - if not this.BulletData.Id then return 0 end +--- Causes an ACF weapon to unload +-- @server +function ents_methods:acfUnload() + CheckType(self, ents_metatable) - local GunData = ACF.Weapons.Guns[this.BulletData.Id] -- REPLACE + local This = unwrap(self) - if not GunData then return 0 end + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return end - return GunData.caliber * 10 or 0 - end + CheckPerms(instance, This, "entities.acf") - return this.Caliber * 10 or 0 + This:TriggerInput("Unload", true) end ---- Returns the muzzle velocity of the ammo in a crate or gun +--- Causes an ACF weapon to reload -- @server -function ents_methods:acfMuzzleVel () - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfReload() + CheckType(self, ents_metatable) + + local This = unwrap(self) + + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return end - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + CheckPerms(instance, This, "entities.acf") - if not ( isAmmo( this ) or isGun( this ) ) then return 0 end - if restrictInfo( this ) then return 0 end - return math.Round( ( this.BulletData[ "MuzzleVel" ] or 0 ) * ACF.Scale, 3 ) + This:TriggerInput("Reload", true) end ---- Returns the mass of the projectile in a crate or gun +--- Returns the rounds left in an acf ammo crate -- @server -function ents_methods:acfProjectileMass () - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfRounds() + CheckType(self, ents_metatable) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + local This = unwrap(self) - if not ( isAmmo( this ) or isGun( this ) ) then return 0 end - if restrictInfo( this ) then return 0 end - return math.Round( this.BulletData[ "ProjMass" ] or 0, 3 ) + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return 0 end + + return This.Ammo or 0 end ---- Returns the number of projectiles in a flechette round +--- Returns the type of weapon the ammo in an ACF ammo crate loads into -- @server -function ents_methods:acfFLSpikes () - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfRoundType() + CheckType(self, ents_metatable) + + local This = unwrap(self) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return "" end - if not ( isAmmo( this ) or isGun( this ) ) then return 0 end - if restrictInfo( this ) then return 0 end - if not this.BulletData[ "Type" ] == "FL" then return 0 end - return this.BulletData[ "Flechettes" ] or 0 + local BulletData = This.BulletData + + return BulletData and BulletData.Id or "" end ---- Returns the mass of a single spike in a FL round in a crate or gun +--- Returns the type of ammo in a crate or gun -- @server -function ents_methods:acfFLSpikeMass () - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfAmmoType() + CheckType(self, ents_metatable) + + local This = unwrap(self) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return "" end - if not ( isAmmo( this ) or isGun( this ) ) then return 0 end - if restrictInfo( this ) then return 0 end - if not this.BulletData[ "Type" ] == "FL" then return 0 end - return math.Round( this.BulletData[ "FlechetteMass" ] or 0, 3) + local BulletData = This.BulletData + + return BulletData and BulletData.Type or "" end ---- Returns the radius of the spikes in a flechette round in mm +--- Returns the caliber of an ammo or gun -- @server -function ents_methods:acfFLSpikeRadius () - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfCaliber() + CheckType(self, ents_metatable) + + local This = unwrap(self) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return 0 end - if not ( isAmmo( this ) or isGun( this ) ) then return 0 end - if restrictInfo( this ) then return 0 end - if not this.BulletData[ "Type" ] == "FL" then return 0 end - return math.Round( ( this.BulletData[ "FlechetteRadius" ] or 0 ) * 10, 3) + local Caliber = This.Caliber + + return Caliber and Caliber * 10 or 0 end ---- Returns the penetration of an AP, APHE, or HEAT round +--- Returns the muzzle velocity of the ammo in a crate or gun -- @server -function ents_methods:acfPenetration () - checktype( self, ents_metatable ) - local this = unwrap( self ) - - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end - - if not ( isAmmo( this ) or isGun( this ) ) then return 0 end - if restrictInfo( this ) then return 0 end - local Type = this.BulletData[ "Type" ] or "" - local Energy - - --[[if Type == "AP" or Type == "APHE" then - Energy = ACF_Kinetic( this.BulletData[ "MuzzleVel" ] * 39.37, this.BulletData[ "ProjMass" ] - ( this.BulletData[ "FillerMass" ] or 0 ), this.BulletData[ "LimitVel" ] ) - return math.Round( ( Energy.Penetration / this.BulletData[ "PenArea" ] ) * ACF.KEtoRHA, 3 ) - elseif Type == "HEAT" then - Energy = ACF_Kinetic( this.BulletData[ "SlugMV" ] * 39.37, this.BulletData[ "SlugMass" ], 9999999 ) - return math.Round( ( Energy.Penetration / this.BulletData[ "SlugPenArea" ] ) * ACF.KEtoRHA, 3 ) - elseif Type == "FL" then - Energy = ACF_Kinetic( this.BulletData[ "MuzzleVel" ] * 39.37 , this.BulletData[ "FlechetteMass" ], this.BulletData[ "LimitVel" ] ) - return math.Round( ( Energy.Penetration / this.BulletData[ "FlechettePenArea" ] ) * ACF.KEtoRHA, 3 ) - end]] - - if Type == "AP" or Type == "APHE" then - Energy = ACF_Kinetic(this.BulletData["MuzzleVel"]*39.37, this.BulletData["ProjMass"] - (this.BulletData["FillerMass"] or 0), this.BulletData["LimitVel"] ) - return math.Round((Energy.Penetration/this.BulletData["PenArea"])*ACF.KEtoRHA,3) - elseif Type == "HEAT" then - local Crushed, HEATFillerMass, BoomFillerMass = ACF.RoundTypes["HEAT"].CrushCalc(this.BulletData.MuzzleVel, this.BulletData.FillerMass) -- REPLACE - if Crushed == 1 then return 0 end -- no HEAT jet to fire off, it was all converted to HE - Energy = ACF_Kinetic(ACF.RoundTypes["HEAT"].CalcSlugMV( this.BulletData, HEATFillerMass )*39.37, this.BulletData["SlugMass"], 9999999 ) -- REPLACE - return math.Round((Energy.Penetration/this.BulletData["SlugPenArea"])*ACF.KEtoRHA,3) - elseif Type == "FL" then - Energy = ACF_Kinetic(this.BulletData["MuzzleVel"]*39.37 , this.BulletData["FlechetteMass"], this.BulletData["LimitVel"] ) - return math.Round((Energy.Penetration/this.BulletData["FlechettePenArea"])*ACF.KEtoRHA, 3) - end - - return 0 +function ents_methods:acfMuzzleVel() + CheckType(self, ents_metatable) + + local This = unwrap(self) + + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return 0 end + + local BulletData = This.BulletData + local MuzzleVel = BulletData and BulletData.MuzzleVel + + return MuzzleVel and MuzzleVel * ACF.Scale or 0 end ---- Returns the blast radius of an HE, APHE, or HEAT round +--- Returns the mass of the projectile in a crate or gun -- @server -function ents_methods:acfBlastRadius () - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfProjectileMass() + CheckType(self, ents_metatable) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + local This = unwrap(self) - if not ( isAmmo( this ) or isGun( this ) ) then return 0 end - if restrictInfo( this ) then return 0 end - local Type = this.BulletData[ "Type" ] or "" - if Type == "HE" or Type == "APHE" then - return math.Round( this.BulletData[ "FillerMass" ]^0.33 * 8, 3 ) - elseif Type == "HEAT" then - return math.Round( ( this.BulletData[ "FillerMass" ] / 3)^0.33 * 8, 3 ) - end - return 0 + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return 0 end + + local BulletData = This.BulletData + + return BulletData and BulletData.ProjMass or 0 end --- Returns the drag coef of the ammo in a crate or gun -- @server function ents_methods:acfDragCoef() - checktype( self, ents_metatable ) - local this = unwrap( self ) + CheckType(self, ents_metatable) + + local This = unwrap(self) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return 0 end - if not ( isAmmo( this ) or isGun( this ) ) then return 0 end - if restrictInfo( this ) then return 0 end - return ( this.BulletData[ "DragCoef" ] or 0 ) / ACF.DragDiv + local BulletData = This.BulletData + local DragCoef = BulletData and BulletData.DragCoef + + return DragCoef and DragCoef / ACF.DragDiv or 0 end --- Returns the fin multiplier of the ammo in a crate or launcher -- @server function ents_methods:acfFinMul() - checktype( self, ents_metatable ) - local this = unwrap( self ) - - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + CheckType(self, ents_metatable) - if not ( isAmmo( this ) or isRack( this ) ) then return 0 end - if restrictInfo( this ) then return 0 end - if not this.BulletData.Id then return 0 end + local This = unwrap(self) - local GunData = ACF.Weapons.Guns[this.BulletData.Id] -- REPLACE + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return 0 end - if not GunData then return 0 end - if not GunData.round then return 0 end - - return ( GunData.round.finmul or 0 ) + return This.FinMultiplier or 0 end -- Returns the weight of the missile in a crate or rack -- @server function ents_methods:acfMissileWeight() - checktype( self, ents_metatable ) - local this = unwrap( self ) - - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + CheckType(self, ents_metatable) - if not ( isAmmo( this ) or isRack( this ) ) then return 0 end - if restrictInfo( this ) then return 0 end - if not this.BulletData.Id then return 0 end + local This = unwrap(self) - local GunData = ACF.Weapons.Guns[this.BulletData.Id] -- REPLACE - if not GunData then return 0 end + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return 0 end - return ( GunData.weight or 0 ) + return This.ForcedMass or 0 end -- Returns the weight of the missile in a crate or rack -- @server function ents_methods:acfMissileLength() - checktype( self, ents_metatable ) - local this = unwrap( self ) + CheckType(self, ents_metatable) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + local This = unwrap(self) - if not ( isAmmo( this ) or isRack( this ) ) then return 0 end - if restrictInfo( this ) then return 0 end - if not this.BulletData.Id then return 0 end + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return 0 end - local GunData = ACF.Weapons.Guns[this.BulletData.Id] -- REPLACE - if not GunData then return 0 end - - return ( GunData.length or 0 ) + return This.Length or 0 end --- [ Armor Functions ] -- - ---- Returns the current health of an entity +--- Returns the number of projectiles in a flechette round -- @server -function ents_methods:acfPropHealth () - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfFLSpikes() + CheckType(self, ents_metatable) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + local This = unwrap(self) - if not validPhysics( this ) then return 0 end - if restrictInfo( this ) then return 0 end - if not ACF_Check( this ) then return 0 end - return math.Round( this.ACF.Health or 0, 3 ) -end - ---- Returns the current armor of an entity --- @server -function ents_methods:acfPropArmor () - checktype( self, ents_metatable ) - local this = unwrap( self ) + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return 0 end - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + local BulletData = This.BulletData - if not validPhysics( this ) then return 0 end - if restrictInfo( this ) then return 0 end - if not ACF_Check( this ) then return 0 end - return math.Round( this.ACF.Armour or 0, 3 ) + return BulletData and BulletData.Flechettes or 0 end ---- Returns the max health of an entity +--- Returns the mass of a single spike in a FL round in a crate or gun -- @server -function ents_methods:acfPropHealthMax () - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfFLSpikeMass() + CheckType(self, ents_metatable) + + local This = unwrap(self) + + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return 0 end - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + local BulletData = This.BulletData - if not validPhysics( this ) then return 0 end - if restrictInfo( this ) then return 0 end - if not ACF_Check( this ) then return 0 end - return math.Round( this.ACF.MaxHealth or 0, 3 ) + return BulletData and BulletData.FlechetteMass or 0 end ---- Returns the max armor of an entity +--- Returns the radius of the spikes in a flechette round in mm -- @server -function ents_methods:acfPropArmorMax () - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfFLSpikeRadius() + CheckType(self, ents_metatable) + + local This = unwrap(self) + + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return 0 end - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + local BulletData = This.BulletData + local Radius = BulletData and BulletData.FlechetteRadius - if not validPhysics( this ) then return 0 end - if restrictInfo( this ) then return 0 end - if not ACF_Check( this ) then return 0 end - return math.Round( this.ACF.MaxArmour or 0, 3 ) + return Radius and math.Round(Radius * 10, 2) or 0 end ---- Returns the ductility of an entity +--- Returns the penetration of an AP, APHE, or HEAT round -- @server -function ents_methods:acfPropDuctility () - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfPenetration() + CheckType(self, ents_metatable) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + local This = unwrap(self) - if not validPhysics( this ) then return 0 end - if restrictInfo( this ) then return 0 end - if not ACF_Check( this ) then return 0 end - return ( this.ACF.Ductility or 0 ) * 100 -end + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return 0 end --- [ Fuel Functions ] -- + local BulletData = This.BulletData + local AmmoType = BulletData and AmmoTypes[BulletData.Type] ---- Returns true if the entity is an ACF fuel tank --- @server -function ents_methods:acfIsFuel () - checktype( self, ents_metatable ) - local this = unwrap( self ) + if not AmmoType then return 0 end - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + local DisplayData = AmmoType:GetDisplayData(BulletData) + local MaxPen = DisplayData and DisplayData.MaxPen - return isFuel( this ) and not restrictInfo( this ) + return MaxPen and Round(MaxPen, 2) or 0 end ---- Sets the ACF fuel tank refuel duty status, which supplies fuel to other fuel tanks +--- Returns the blast radius of an HE, APHE, or HEAT round -- @server -function ents_methods:acfRefuelDuty ( on ) - checktype( self, ents_metatable ) - local this = unwrap( self ) - - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end - checkpermission( instance, this, "entities.acf" ) +function ents_methods:acfBlastRadius() + CheckType(self, ents_metatable) - if not isFuel( this ) then return end - - this:TriggerInput( "Refuel Duty", on and true or false ) -end + local This = unwrap(self) ---- Returns the remaining liters or kilowatt hours of fuel in an ACF fuel tank or engine --- @server -function ents_methods:acfFuel () - checktype( self, ents_metatable ) - local this = unwrap( self ) + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return 0 end - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + local BulletData = This.BulletData + local AmmoType = BulletData and AmmoTypes[BulletData.Type] - if restrictInfo( this ) then return 0 end - if isFuel( this ) then - return math.Round( this.Fuel, 3 ) - elseif isEngine( this ) then - if not #(this.FuelLink) then return 0 end --if no tanks, return 0 + if not AmmoType then return 0 end - local liters = 0 - for _, tank in pairs( this.FuelLink ) do - if validPhysics( tank ) and tank.Active then - liters = liters + tank.Fuel - end - end + local DisplayData = AmmoType:GetDisplayData(BulletData) + local Radius = DisplayData and DisplayData.BlastRadius - return math.Round( liters, 3 ) - end - return 0 + return Radius and Round(Radius, 2) or 0 end ---- Returns the amount of fuel in an ACF fuel tank or linked to engine as a percentage of capacity +--- Returns the number of rounds in active ammo crates linked to an ACF weapon -- @server -function ents_methods:acfFuelLevel () - checktype( self, ents_metatable ) - local this = unwrap( self ) - - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end - - if isFuel( this ) then - if restrictInfo( this ) then return 0 end - return math.Round( this.Fuel / this.Capacity, 3 ) - elseif isEngine( this ) then - if restrictInfo( this ) then return 0 end - if not #( this.FuelLink ) then return 0 end --if no tanks, return 0 - - local liters = 0 - local capacity = 0 - for _, tank in pairs( this.FuelLink ) do - if validPhysics( tank ) and tank.Active then - capacity = capacity + tank.Capacity - liters = liters + tank.Fuel - end - end - if not capacity > 0 then return 0 end +function ents_methods:acfAmmoCount() + CheckType(self, ents_metatable) - return math.Round( liters / capacity, 3 ) - end - return 0 -end + local This = unwrap(self) ---- Returns the current fuel consumption in liters per minute or kilowatts of an engine --- @server -function ents_methods:acfFuelUse () - checktype( self, ents_metatable ) - local this = unwrap( self ) + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return 0 end - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + local Source = LinkSource(This:GetClass(), "Crates") - if not isEngine( this ) then return 0 end - if restrictInfo( this ) then return 0 end - if not #( this.FuelLink ) then return 0 end --if no tanks, return 0 + if not Source then return 0 end - local tank - for _, fueltank in pairs( this.FuelLink ) do - if validPhysics( fueltank ) and fueltank.Fuel > 0 and fueltank.Active then - tank = fueltank - break + local Count = 0 + + for Crate in pairs(Source(This)) do + if Crate:CanConsume() then + Count = Count + Crate.Ammo end end - if not tank then return 0 end - local Consumption - if this.FuelType == "Electric" then - Consumption = 60 * ( this.Torque * this.FlyRPM / 9548.8 ) * this.FuelUse - else - local Load = 0.3 + this.Throttle * 0.7 - Consumption = 60 * Load * this.FuelUse * ( this.FlyRPM / this.PeakKwRPM ) / ACF.FuelDensity[ tank.FuelType ] -- REPLACE - end - return math.Round( Consumption, 3 ) + return Count end ---- Returns the peak fuel consumption in liters per minute or kilowatts of an engine at powerband max, for the current fuel type the engine is using +--- Returns the number of rounds in all ammo crates linked to an ACF weapon -- @server -function ents_methods:acfPeakFuelUse () - checktype( self, ents_metatable ) - local this = unwrap( self ) +function ents_methods:acfTotalAmmoCount() + CheckType(self, ents_metatable) - if not ( this and this:IsValid() ) then SF.Throw( "Entity is not valid", 2 ) end + local This = unwrap(self) - if not isEngine( this ) then return 0 end - if restrictInfo( this ) then return 0 end - if not #( this.FuelLink ) then return 0 end --if no tanks, return 0 + if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end + if RestrictInfo(This) then return 0 end - local fuel = "Petrol" - local tank - for _, fueltank in pairs( this.FuelLink ) do - if fueltank.Fuel > 0 and fueltank.Active then tank = fueltank break end - end - if tank then fuel = tank.Fuel end + local Source = LinkSource(This:GetClass(), "Crates") - local Consumption - if this.FuelType == "Electric" then - Consumption = 60 * ( this.PeakTorque * this.LimitRPM / ( 4 * 9548.8 ) ) * this.FuelUse - else - local Load = 0.3 + this.Throttle * 0.7 - Consumption = 60 * this.FuelUse / ACF.FuelDensity[ fuel ] -- REPLACE + if not Source then return 0 end + + local Count = 0 + + for Crate in pairs(Source(This)) do + Count = Count + Crate.Ammo end - return math.Round( Consumption, 3 ) + + return Count end end From 4566282d5e905388c13e67039df1ad40a260b2f3 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Fri, 11 Dec 2020 14:40:54 -0300 Subject: [PATCH 205/279] Readded Starfall folder to Linter checks - The Starfall folder will no longer be ignored by the linter check. --- .github/workflows/GLuaFixer.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/GLuaFixer.yml b/.github/workflows/GLuaFixer.yml index e58870bb9..3e7767e7d 100644 --- a/.github/workflows/GLuaFixer.yml +++ b/.github/workflows/GLuaFixer.yml @@ -5,12 +5,10 @@ on: paths: - 'lua/**' - '!lua/entities/gmod_wire_expression2/**' - - '!lua/starfall/**' pull_request: paths: - 'lua/**' - '!lua/entities/gmod_wire_expression2/**' - - '!lua/starfall/**' jobs: build: @@ -22,6 +20,6 @@ jobs: - name: Extract glualint.zip run: unzip glualint.zip - name: Remove blacklisted folders - run: rm -r lua/entities/gmod_wire_expression2/ lua/starfall/ + run: rm -r lua/entities/gmod_wire_expression2/ - name: Initiate linting run: ./glualint lua From 560e96f3b2dcd7f155bef6ac9d513a0e0e8e04bf Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Fri, 11 Dec 2020 14:41:45 -0300 Subject: [PATCH 206/279] Removed unused argument on ACF.CreateEntity - Removed unused argument from every place that uses the ACF.CreateEntity function. --- lua/starfall/libs_sv/acffunctions.lua | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/lua/starfall/libs_sv/acffunctions.lua b/lua/starfall/libs_sv/acffunctions.lua index e6d89d63c..a7ec3a140 100644 --- a/lua/starfall/libs_sv/acffunctions.lua +++ b/lua/starfall/libs_sv/acffunctions.lua @@ -226,7 +226,7 @@ end --- Creates an ACF ammo crate using the information from the data table argument -- @server -function acf_library.createAmmo(pos, ang, data, frozen) +function acf_library.createAmmo(pos, ang, data) CheckPerms(instance, nil, "acf.createAmmo") local Player = instance.player @@ -259,7 +259,7 @@ end --- Creates an ACF engine using the information from the data table argument -- @server -function acf_library.createEngine(pos, ang, data, frozen) +function acf_library.createEngine(pos, ang, data) CheckPerms(instance, nil, "acf.createEngine") local Player = instance.player @@ -276,9 +276,8 @@ function acf_library.createEngine(pos, ang, data, frozen) local Angles = aunwrap(ang) local Data = UnwrapTable(data) local Undo = not instance.data.props.undo - local Frozen = not tobool(frozen) - local Success, Entity = ACF.CreateEntity("acf_engine", Player, Position, Angles, Data, Undo, Frozen) + local Success, Entity = ACF.CreateEntity("acf_engine", Player, Position, Angles, Data, Undo) if not Success then SF.Throw("Unable to create ACF Engine", 2) end @@ -292,7 +291,7 @@ end --- Creates an ACF fuel tank using the information from the data table argument -- @server -function acf_library.createFuelTank(pos, ang, data, frozen) +function acf_library.createFuelTank(pos, ang, data) CheckPerms(instance, nil, "acf.createFuelTank") local Player = instance.player @@ -309,9 +308,8 @@ function acf_library.createFuelTank(pos, ang, data, frozen) local Angles = aunwrap(ang) local Data = UnwrapTable(data) local Undo = not instance.data.props.undo - local Frozen = not tobool(frozen) - local Success, Entity = ACF.CreateEntity("acf_fueltank", Player, Position, Angles, Data, Undo, Frozen) + local Success, Entity = ACF.CreateEntity("acf_fueltank", Player, Position, Angles, Data, Undo) if not Success then SF.Throw("Unable to create ACF Fuel Tank", 2) end @@ -325,7 +323,7 @@ end --- Creates an ACF gearbox using the information from the data table argument -- @server -function acf_library.createGearbox(pos, ang, data, frozen) +function acf_library.createGearbox(pos, ang, data) CheckPerms(instance, nil, "acf.createGearbox") local Player = instance.player @@ -342,9 +340,8 @@ function acf_library.createGearbox(pos, ang, data, frozen) local Angles = aunwrap(ang) local Data = UnwrapTable(data) local Undo = not instance.data.props.undo - local Frozen = not tobool(frozen) - local Success, Entity = ACF.CreateEntity("acf_gearbox", Player, Position, Angles, Data, Undo, Frozen) + local Success, Entity = ACF.CreateEntity("acf_gearbox", Player, Position, Angles, Data, Undo) if not Success then SF.Throw("Unable to create ACF Gearbox", 2) end @@ -358,7 +355,7 @@ end --- Creates an ACF weapon using the information from the data table argument -- @server -function acf_library.createWeapon(pos, ang, data, frozen) +function acf_library.createWeapon(pos, ang, data) CheckPerms(instance, nil, "acf.createWeapon") local Player = instance.player @@ -375,9 +372,8 @@ function acf_library.createWeapon(pos, ang, data, frozen) local Angles = aunwrap(ang) local Data = UnwrapTable(data) local Undo = not instance.data.props.undo - local Frozen = not tobool(frozen) - local Success, Entity = ACF.CreateEntity("acf_gun", Player, Position, Angles, Data, Undo, Frozen) + local Success, Entity = ACF.CreateEntity("acf_gun", Player, Position, Angles, Data, Undo) if not Success then SF.Throw("Unable to create ACF Weapon", 2) end From 9f7a14c6263ca46be0486c1337126020194c0e65 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Fri, 11 Dec 2020 14:42:52 -0300 Subject: [PATCH 207/279] Removed a leftover - Removed a leftover from the last change. --- lua/starfall/libs_sv/acffunctions.lua | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lua/starfall/libs_sv/acffunctions.lua b/lua/starfall/libs_sv/acffunctions.lua index a7ec3a140..7e933cc16 100644 --- a/lua/starfall/libs_sv/acffunctions.lua +++ b/lua/starfall/libs_sv/acffunctions.lua @@ -243,9 +243,8 @@ function acf_library.createAmmo(pos, ang, data) local Angles = aunwrap(ang) local Data = UnwrapTable(data) local Undo = not instance.data.props.undo - local Frozen = not tobool(frozen) - local Success, Entity = ACF.CreateEntity("acf_ammo", Player, Position, Angles, Data, Undo, Frozen) + local Success, Entity = ACF.CreateEntity("acf_ammo", Player, Position, Angles, Data, Undo) if not Success then SF.Throw("Unable to create ACF Ammo Crate", 2) end From 37f90c6f8132bf860201889cf48f55476b2e7dc0 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Fri, 11 Dec 2020 19:47:51 -0300 Subject: [PATCH 208/279] Fixed error messages on ACF.CreateEntity - Fixed error messages failing to be delivered due to the ACF.CreateEntity was still using a localized function that doesn't exist on the same scope where it's placed now. --- lua/acf/base/sh_classes.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lua/acf/base/sh_classes.lua b/lua/acf/base/sh_classes.lua index cb03a7ed4..03c093a81 100644 --- a/lua/acf/base/sh_classes.lua +++ b/lua/acf/base/sh_classes.lua @@ -516,19 +516,19 @@ do -- Entity class registration function local ClassData = ACF.GetEntityClass(Class) if not ClassData then - SendMessage(Player, "Error", Class, " is not a registered ACF entity class.") + ACF.SendMessage(Player, "Error", Class, " is not a registered ACF entity class.") return false end if not ClassData.Spawn then - SendMessage(Player, "Error", Class, " doesn't have a spawn function assigned to it.") + ACF.SendMessage(Player, "Error", Class, " doesn't have a spawn function assigned to it.") return false end local Entity = ClassData.Spawn(Player, Position, Angles, Data) if not IsValid(Entity) then - SendMessage(Player, "Error", Class, " entity couldn't be created.") + ACF.SendMessage(Player, "Error", Class, " entity couldn't be created.") return false end From 10880af88cda242068d4d5728f7b0b139bcc0f63 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Fri, 11 Dec 2020 19:49:10 -0300 Subject: [PATCH 209/279] Cleaned up some unused stuff - Cleaned up Undone_X language entries due to them not being used anymore. - Removed acfmenu cleanup register due to it not being used anymore. --- lua/entities/acf_ammo/cl_init.lua | 1 - lua/entities/acf_engine/cl_init.lua | 1 - lua/entities/acf_fueltank/cl_init.lua | 1 - lua/entities/acf_gearbox/cl_init.lua | 1 - lua/entities/acf_gun/cl_init.lua | 1 - lua/weapons/gmod_tool/stools/acf_menu.lua | 2 -- 6 files changed, 7 deletions(-) diff --git a/lua/entities/acf_ammo/cl_init.lua b/lua/entities/acf_ammo/cl_init.lua index 19603adb5..e5bdddf6e 100644 --- a/lua/entities/acf_ammo/cl_init.lua +++ b/lua/entities/acf_ammo/cl_init.lua @@ -1,7 +1,6 @@ include("shared.lua") language.Add("Cleanup_acf_ammo", "ACF Ammo Crates") -language.Add("Undone_acf_ammo", "Undone ACF Ammo Crate") language.Add("Cleaned_acf_ammo", "Cleaned up all ACF Ammo Crates") language.Add("SBoxLimit__acf_ammo", "You've reached the ACF Ammo Crates limit!") diff --git a/lua/entities/acf_engine/cl_init.lua b/lua/entities/acf_engine/cl_init.lua index 79be12aba..0d4a82fa3 100644 --- a/lua/entities/acf_engine/cl_init.lua +++ b/lua/entities/acf_engine/cl_init.lua @@ -3,7 +3,6 @@ include("shared.lua") local HideInfo = ACF.HideInfoBubble language.Add("Cleanup_acf_engine", "ACF Engines") -language.Add("Undone_acf_engine", "Undone ACF Engine") language.Add("Cleaned_acf_engine", "Cleaned up all ACF Engines") language.Add("SBoxLimit__acf_engine", "You've reached the ACF Engines limit!") diff --git a/lua/entities/acf_fueltank/cl_init.lua b/lua/entities/acf_fueltank/cl_init.lua index 0ff8038d2..a9d8ad9d1 100644 --- a/lua/entities/acf_fueltank/cl_init.lua +++ b/lua/entities/acf_fueltank/cl_init.lua @@ -3,7 +3,6 @@ include("shared.lua") local HideInfo = ACF.HideInfoBubble language.Add("Cleanup_acf_fueltank", "ACF Fuel Tanks") -language.Add("Undone_acf_fueltank", "Undone ACF Fuel Tank") language.Add("Cleaned_acf_fueltank", "Cleaned up all ACF Fuel Tanks") language.Add("SBoxLimit__acf_fueltank", "You've reached the ACF Fuel Tanks limit!") diff --git a/lua/entities/acf_gearbox/cl_init.lua b/lua/entities/acf_gearbox/cl_init.lua index 5366849fb..195cbd5ba 100644 --- a/lua/entities/acf_gearbox/cl_init.lua +++ b/lua/entities/acf_gearbox/cl_init.lua @@ -3,7 +3,6 @@ include("shared.lua") local HideInfo = ACF.HideInfoBubble language.Add("Cleanup_acf_gearbox", "ACF Gearboxes") -language.Add("Undone_acf_gearbox", "Undone ACF Gearbox") language.Add("Cleaned_acf_gearbox", "Cleaned up all ACF Gearboxes") language.Add("SBoxLimit__acf_gearbox", "You've reached the ACF Gearboxes limit!") diff --git a/lua/entities/acf_gun/cl_init.lua b/lua/entities/acf_gun/cl_init.lua index dc4a7485b..f681dd4b6 100644 --- a/lua/entities/acf_gun/cl_init.lua +++ b/lua/entities/acf_gun/cl_init.lua @@ -3,7 +3,6 @@ include("shared.lua") local HideInfo = ACF.HideInfoBubble language.Add("Cleanup_acf_gun", "ACF Weapons") -language.Add("Undone_acf_gun", "Undone ACF Weapon") language.Add("Cleaned_acf_gun", "Cleaned up all ACF Weapons") language.Add("Cleanup_acf_smokelauncher", "ACF Smoke Launchers") language.Add("SBoxLimit__acf_gun", "You've reached the ACF Weapons limit!") diff --git a/lua/weapons/gmod_tool/stools/acf_menu.lua b/lua/weapons/gmod_tool/stools/acf_menu.lua index 6741fb237..a595aa4a8 100644 --- a/lua/weapons/gmod_tool/stools/acf_menu.lua +++ b/lua/weapons/gmod_tool/stools/acf_menu.lua @@ -3,8 +3,6 @@ TOOL.Category = "Construction" ACF.LoadToolFunctions(TOOL) -cleanup.Register("acfmenu") - if CLIENT then local DrawBoxes = GetConVar("acf_drawboxes") From a7dc21ea67e9ffb1757a24730f4223df9c0885f5 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sat, 12 Dec 2020 04:02:01 -0300 Subject: [PATCH 210/279] Literally unusable - Removed a few cases of double spacing where there shouldn't be double spacing. ACF can finally work as intended. --- lua/acf/base/acf_globals.lua | 6 +++--- lua/acf/base/permission/sv_permissions.lua | 6 +++--- lua/acf/base/version/sv_version.lua | 2 +- lua/acf/client/cl_permissions.lua | 2 +- lua/acf/server/damage.lua | 4 ++-- lua/acf/server/permissionmodes/pmode_battle.lua | 2 +- lua/acf/server/permissionmodes/pmode_build.lua | 4 ++-- lua/acf/server/permissionmodes/pmode_strictbuild.lua | 2 +- lua/acf/shared/acf_userconfig_example.lua | 10 +++++----- lua/acf/shared/engines/b6.lua | 2 +- lua/acf/shared/engines/special.lua | 2 +- lua/acf/shared/fuel_types/diesel.lua | 2 +- lua/acf/shared/fuel_types/electric.lua | 2 +- lua/acf/shared/fuel_types/petrol.lua | 2 +- lua/acf/shared/fueltanks/size_four.lua | 2 +- lua/acf/shared/fueltanks/size_one.lua | 4 ++-- lua/acf/shared/tool_operations/acf_menu.lua | 2 +- lua/acf/shared/weapons/cannon.lua | 2 +- lua/acf/shared/weapons/heavymachinegun.lua | 2 +- lua/acf/shared/weapons/howitzer.lua | 2 +- lua/entities/acf_ammo/init.lua | 2 +- lua/entities/acf_engine/init.lua | 2 +- lua/entities/acf_gun/init.lua | 2 +- lua/weapons/gmod_tool/stools/acfarmorprop.lua | 4 ++-- 24 files changed, 36 insertions(+), 36 deletions(-) diff --git a/lua/acf/base/acf_globals.lua b/lua/acf/base/acf_globals.lua index bcf9bec82..590babbd5 100644 --- a/lua/acf/base/acf_globals.lua +++ b/lua/acf/base/acf_globals.lua @@ -68,7 +68,7 @@ do -- ACF global vars ACF.HEATMaxCrush = 1200 -- vel where fully crushed -- Debris - ACF.ChildDebris = 50 -- higher is more debris props; Chance = ACF.ChildDebris / num_children; Only applies to children of acf-killed parent props + ACF.ChildDebris = 50 -- higher is more debris props; Chance = ACF.ChildDebris / num_children; Only applies to children of acf-killed parent props ACF.DebrisIgniteChance = 0.25 ACF.DebrisScale = 999999 -- Ignore debris that is less than this bounding radius. ACF.ValidDebris = { -- Whitelist for things that can be turned into debris @@ -82,9 +82,9 @@ do -- ACF global vars } -- Weapon Accuracy - ACF.SpreadScale = 4 -- The maximum amount that damage can decrease a gun"s accuracy. Default 4x + ACF.SpreadScale = 4 -- The maximum amount that damage can decrease a gun"s accuracy. Default 4x ACF.GunInaccuracyScale = 0.5 -- A multiplier for gun accuracy. Must be between 0.5 and 4 - ACF.GunInaccuracyBias = 2 -- Higher numbers make shots more likely to be inaccurate. Choose between 0.5 to 4. Default is 2 (unbiased). + ACF.GunInaccuracyBias = 2 -- Higher numbers make shots more likely to be inaccurate. Choose between 0.5 to 4. Default is 2 (unbiased). -- Fuel ACF.FuelRate = 1 --multiplier for fuel usage, 1.0 is approx real world diff --git a/lua/acf/base/permission/sv_permissions.lua b/lua/acf/base/permission/sv_permissions.lua index 7eca3ff99..f7f4d3f70 100644 --- a/lua/acf/base/permission/sv_permissions.lua +++ b/lua/acf/base/permission/sv_permissions.lua @@ -100,7 +100,7 @@ end hook.Add("Initialize", "ACF_LoadSafesForMap", function() if not getMapSZs() then - print("Safezone file " .. getMapFilename() .. " is missing, invalid or corrupt! Safezones will not be restored this time.") + print("Safezone file " .. getMapFilename() .. " is missing, invalid or corrupt! Safezones will not be restored this time.") end end) @@ -128,7 +128,7 @@ concommand.Add("ACF_AddSafeZone", function(ply, _, args) end or msgtoconsole if not args[1] then - printmsg(HUD_PRINTCONSOLE, " - Add a safezone as an AABB box." .. "\n Input a name and six numbers. First three numbers are minimum co-ords, last three are maxs." .. "\n Example; ACF_addsafezone airbase -500 -500 0 500 500 1000") + printmsg(HUD_PRINTCONSOLE, " - Add a safezone as an AABB box." .. "\n Input a name and six numbers. First three numbers are minimum co-ords, last three are maxs." .. "\n Example; ACF_addsafezone airbase -500 -500 0 500 500 1000") return false end @@ -189,7 +189,7 @@ concommand.Add("ACF_RemoveSafeZone", function(ply, _, args) end or msgtoconsole if not args[1] then - printmsg(HUD_PRINTCONSOLE, " - Delete a safezone using its name." .. "\n Input a safezone name. If it exists, it will be removed." .. "\n Deletion is not permanent until safezones are saved.") + printmsg(HUD_PRINTCONSOLE, " - Delete a safezone using its name." .. "\n Input a safezone name. If it exists, it will be removed." .. "\n Deletion is not permanent until safezones are saved.") return false end diff --git a/lua/acf/base/version/sv_version.lua b/lua/acf/base/version/sv_version.lua index 263a2ab95..667b470d4 100644 --- a/lua/acf/base/version/sv_version.lua +++ b/lua/acf/base/version/sv_version.lua @@ -65,7 +65,7 @@ do -- Github data conversion Message = Message:Replace("\n\n", "\n"):gsub("[\r]*[\n]+[%s]+", "\n- ") local Title = Start and Message:sub(1, Start - 1) or Message - local Body = Start and Message:sub(Start + 1, #Message) or "No Commit Message" + local Body = Start and Message:sub(Start + 1, #Message) or "No Commit Message" return Title, Body end diff --git a/lua/acf/client/cl_permissions.lua b/lua/acf/client/cl_permissions.lua index 8f21b904a..369604529 100644 --- a/lua/acf/client/cl_permissions.lua +++ b/lua/acf/client/cl_permissions.lua @@ -189,7 +189,7 @@ end local cat = Menu.Category local item = Menu.Name -local var = Menu.Command +local var = Menu.Command local open = Menu.OnSpawnmenuOpen local panel = Menu.MakePanel local hookname = string.Replace(item," ","_") diff --git a/lua/acf/server/damage.lua b/lua/acf/server/damage.lua index 185dd5f18..b8afec6b4 100644 --- a/lua/acf/server/damage.lua +++ b/lua/acf/server/damage.lua @@ -132,7 +132,7 @@ do debugoverlay.Cross(Origin, 15, 15, Color( 255, 255, 255 ), true) Filter = Filter or {} - local Power = FillerMass * ACF.HEPower --Power in KiloJoules of the filler mass of TNT + local Power = FillerMass * ACF.HEPower --Power in KiloJoules of the filler mass of TNT local Radius = FillerMass ^ 0.33 * 8 * 39.37 -- Scaling law found on the net, based on 1PSI overpressure from 1 kg of TNT at 15m local MaxSphere = 4 * 3.1415 * (Radius * 2.54) ^ 2 --Surface Area of the sphere at maximum radius local Amp = math.min(Power / 2000, 50) @@ -513,7 +513,7 @@ do -- do an initial processing pass on children, separating out explodey things to handle last for Ent in pairs( Children ) do - Ent.ACF_Killed = true -- mark that it's already processed + Ent.ACF_Killed = true -- mark that it's already processed if not ValidDebris[Ent:GetClass()] then Children[Ent] = nil -- ignoring stuff like holos, wiremod components, etc. diff --git a/lua/acf/server/permissionmodes/pmode_battle.lua b/lua/acf/server/permissionmodes/pmode_battle.lua index 090538cda..76ad46f73 100644 --- a/lua/acf/server/permissionmodes/pmode_battle.lua +++ b/lua/acf/server/permissionmodes/pmode_battle.lua @@ -17,7 +17,7 @@ end local perms = ACF.Permissions -- a short description of what the mode does -local modedescription = "Enables safe-zones and battlefield. No ACF damage can occur in a safe-zone." +local modedescription = "Enables safe-zones and battlefield. No ACF damage can occur in a safe-zone." -- battle-mode specifics: how much hp/armour should the players have? local MAX_HP = 100 local MAX_Armour = 50 diff --git a/lua/acf/server/permissionmodes/pmode_build.lua b/lua/acf/server/permissionmodes/pmode_build.lua index 18b35bf2a..4576345ba 100644 --- a/lua/acf/server/permissionmodes/pmode_build.lua +++ b/lua/acf/server/permissionmodes/pmode_build.lua @@ -2,7 +2,7 @@ ACF Permission mode: Build This mode blocks all damage to entities without the owner's permission. Owners can permit damage from specific players. - Players and NPCs remain vulnerable to damage. This is what admin mods are for. + Players and NPCs remain vulnerable to damage. This is what admin mods are for. This mode requires a CPPI-compatible prop-protector to function properly. //]] @@ -16,7 +16,7 @@ end local perms = ACF.Permissions -- a short description of what the mode does local modedescription = "Disables all ACF damage unless the owner permits it. PvP is allowed." --- if the attacker or victim can't be identified, what should we do? true allows damage, false blocks it. +-- if the attacker or victim can't be identified, what should we do? true allows damage, false blocks it. local DefaultPermission = false --[[ diff --git a/lua/acf/server/permissionmodes/pmode_strictbuild.lua b/lua/acf/server/permissionmodes/pmode_strictbuild.lua index dc081a5f5..0ba965690 100644 --- a/lua/acf/server/permissionmodes/pmode_strictbuild.lua +++ b/lua/acf/server/permissionmodes/pmode_strictbuild.lua @@ -15,7 +15,7 @@ end local perms = ACF.Permissions -- a short description of what the mode does local modedescription = "Disables all ACF damage unless the owner permits it. PvP is disallowed." --- if the attacker or victim can't be identified, what should we do? true allows damage, false blocks it. +-- if the attacker or victim can't be identified, what should we do? true allows damage, false blocks it. local DefaultPermission = false --[[ diff --git a/lua/acf/shared/acf_userconfig_example.lua b/lua/acf/shared/acf_userconfig_example.lua index c57285cdc..96480c9c6 100644 --- a/lua/acf/shared/acf_userconfig_example.lua +++ b/lua/acf/shared/acf_userconfig_example.lua @@ -8,10 +8,10 @@ ]]-- --- Some example settings are below. They enable damage protection, double gun accuracy, and make shots more likely to be accurate. --- There are more settings like this. Find them all in lua/autorun/shared/acf_globals.lua +-- Some example settings are below. They enable damage protection, double gun accuracy, and make shots more likely to be accurate. +-- There are more settings like this. Find them all in lua/autorun/shared/acf_globals.lua ---ACF.EnableDefaultDP = true -- Enable the inbuilt damage protection system. ---ACF.GunInaccuracyScale = 1 -- Make guns 2x less accurate by increasing the spread scale. ---ACF.GunInaccuracyBias = 1.2 -- Shots are more likely to be accurate with bias < 2 \ No newline at end of file +--ACF.EnableDefaultDP = true -- Enable the inbuilt damage protection system. +--ACF.GunInaccuracyScale = 1 -- Make guns 2x less accurate by increasing the spread scale. +--ACF.GunInaccuracyBias = 1.2 -- Shots are more likely to be accurate with bias < 2 \ No newline at end of file diff --git a/lua/acf/shared/engines/b6.lua b/lua/acf/shared/engines/b6.lua index 14033107f..da5c70071 100644 --- a/lua/acf/shared/engines/b6.lua +++ b/lua/acf/shared/engines/b6.lua @@ -44,7 +44,7 @@ do ACF.RegisterEngine("8.3-B6", "B6", { Name = "8.3L Flat 6 Multifuel", - Description = "Military-grade multifuel boxer engine. Although heavy, it is compact, durable, and has excellent performance under adverse conditions.", + Description = "Military-grade multifuel boxer engine. Although heavy, it is compact, durable, and has excellent performance under adverse conditions.", Model = "models/engines/b6med.mdl", Sound = "acf_base/engines/v8_diesel.wav", Fuel = { Petrol = true, Diesel = true }, diff --git a/lua/acf/shared/engines/special.lua b/lua/acf/shared/engines/special.lua index 7af5d35f1..57c9fa42f 100644 --- a/lua/acf/shared/engines/special.lua +++ b/lua/acf/shared/engines/special.lua @@ -127,7 +127,7 @@ end do -- Special V6 Engines ACF.RegisterEngine("2.4L-V6", "SP", { Name = "2.4L V6 Petrol", - Description = "Although the cast iron engine block is fairly weighty, this tiny v6 makes up for it with impressive power. The unique V angle allows uncharacteristically high RPM for a V6.", + Description = "Although the cast iron engine block is fairly weighty, this tiny v6 makes up for it with impressive power. The unique V angle allows uncharacteristically high RPM for a V6.", Model = "models/engines/v6small.mdl", Sound = "acf_extra/vehiclefx/engines/l6/capri_onmid.wav", Fuel = { Petrol = true }, diff --git a/lua/acf/shared/fuel_types/diesel.lua b/lua/acf/shared/fuel_types/diesel.lua index 04f092787..839051414 100644 --- a/lua/acf/shared/fuel_types/diesel.lua +++ b/lua/acf/shared/fuel_types/diesel.lua @@ -1,4 +1,4 @@ ACF.RegisterFuelType("Diesel", { Name = "Diesel Fuel", - Density = 0.745, + Density = 0.745, }) diff --git a/lua/acf/shared/fuel_types/electric.lua b/lua/acf/shared/fuel_types/electric.lua index e875b9812..7f7185603 100644 --- a/lua/acf/shared/fuel_types/electric.lua +++ b/lua/acf/shared/fuel_types/electric.lua @@ -1,6 +1,6 @@ ACF.RegisterFuelType("Electric", { Name = "Lit-Ion Battery", - Density = 3.89, + Density = 3.89, ConsumptionText = function(PeakkW, _, TypeData) local Text = "\n\nPeak Energy Consumption :\n%s kW - %s MJ/min" local Rate = ACF.FuelRate * PeakkW / TypeData.Efficiency diff --git a/lua/acf/shared/fuel_types/petrol.lua b/lua/acf/shared/fuel_types/petrol.lua index 2b2e47558..153662d85 100644 --- a/lua/acf/shared/fuel_types/petrol.lua +++ b/lua/acf/shared/fuel_types/petrol.lua @@ -1,4 +1,4 @@ ACF.RegisterFuelType("Petrol", { Name = "Petrol Fuel", - Density = 0.832, + Density = 0.832, }) diff --git a/lua/acf/shared/fueltanks/size_four.lua b/lua/acf/shared/fueltanks/size_four.lua index c10a1d495..faa9ed866 100644 --- a/lua/acf/shared/fueltanks/size_four.lua +++ b/lua/acf/shared/fueltanks/size_four.lua @@ -70,7 +70,7 @@ do ACF.RegisterFuelTank("Tank_4x8x4","FTS_4", { Name = "4x8x4 Container", - Description = "\'MURRICA FUCKYEAH!", + Description = "\'MURRICA FUCKYEAH!", Model = "models/fueltank/fueltank_4x8x4.mdl", SurfaceArea = 14993.3, Volume = 123693.2, diff --git a/lua/acf/shared/fueltanks/size_one.lua b/lua/acf/shared/fueltanks/size_one.lua index 065fef62f..c4c27efb9 100644 --- a/lua/acf/shared/fueltanks/size_one.lua +++ b/lua/acf/shared/fueltanks/size_one.lua @@ -94,7 +94,7 @@ do ACF.RegisterFuelTank("Tank_1x6x4","FTS_1", { Name = "1x6x4 Container", - Description = "Fuel. Will keep you going for awhile.", + Description = "Fuel. Will keep you going for awhile.", Model = "models/fueltank/fueltank_1x6x4.mdl", SurfaceArea = 6743.3, Volume = 24109.4, @@ -110,7 +110,7 @@ do ACF.RegisterFuelTank("Tank_1x8x2","FTS_1", { Name = "1x8x2 Container", - Description = "Gas stations? We don't need no stinking gas stations!", + Description = "Gas stations? We don't need no stinking gas stations!", Model = "models/fueltank/fueltank_1x8x2.mdl", SurfaceArea = 5113.7, Volume = 16026.2, diff --git a/lua/acf/shared/tool_operations/acf_menu.lua b/lua/acf/shared/tool_operations/acf_menu.lua index 4abce7b7a..1df30107e 100644 --- a/lua/acf/shared/tool_operations/acf_menu.lua +++ b/lua/acf/shared/tool_operations/acf_menu.lua @@ -157,7 +157,7 @@ do -- Linker operation SendMessage(Player, "Info", "Successfully ", Status, " entities to ", tostring(Entity), ".") else - local Status = Total .. " entities could be " .. (Unlink and "unlinked" or "linked") + local Status = Total .. " entities could be " .. (Unlink and "unlinked" or "linked") SendMessage(Player, "Error", "None of the ", Status, " to ", tostring(Entity), ".") end diff --git a/lua/acf/shared/weapons/cannon.lua b/lua/acf/shared/weapons/cannon.lua index 59268269b..ac3158c53 100644 --- a/lua/acf/shared/weapons/cannon.lua +++ b/lua/acf/shared/weapons/cannon.lua @@ -40,7 +40,7 @@ ACF.RegisterWeapon("50mmC", "C", { ACF.RegisterWeapon("75mmC", "C", { Name = "75mm Cannon", - Description = "The 75mm is still rather respectable in rate of fire, but has only modest payload. Often found on the Eastern Front, and on cold war light tanks.", + Description = "The 75mm is still rather respectable in rate of fire, but has only modest payload. Often found on the Eastern Front, and on cold war light tanks.", Model = "models/tankgun/tankgun_75mm.mdl", Caliber = 75, Mass = 1420, diff --git a/lua/acf/shared/weapons/heavymachinegun.lua b/lua/acf/shared/weapons/heavymachinegun.lua index 2b205c5fa..ef57625c9 100644 --- a/lua/acf/shared/weapons/heavymachinegun.lua +++ b/lua/acf/shared/weapons/heavymachinegun.lua @@ -65,7 +65,7 @@ ACF.RegisterWeapon("30mmHMG", "HMG", { ACF.RegisterWeapon("40mmHMG", "HMG", { Name = "40mm Heavy Machinegun", - Description = "The heaviest of the heavy machineguns. Massively powerful with a killer reload and hefty ammunition requirements, it can pop even relatively heavy targets with ease.", + Description = "The heaviest of the heavy machineguns. Massively powerful with a killer reload and hefty ammunition requirements, it can pop even relatively heavy targets with ease.", Model = "models/machinegun/machinegun_40mm_compact.mdl", Caliber = 40, Mass = 780, diff --git a/lua/acf/shared/weapons/howitzer.lua b/lua/acf/shared/weapons/howitzer.lua index cd02eeefb..e32d3760c 100644 --- a/lua/acf/shared/weapons/howitzer.lua +++ b/lua/acf/shared/weapons/howitzer.lua @@ -51,7 +51,7 @@ ACF.RegisterWeapon("122mmHW", "HW", { ACF.RegisterWeapon("155mmHW", "HW", { Name = "155mm Howitzer", - Description = "The 155 is a classic heavy artillery round, with good reason. A versatile weapon, it's found on most modern SPGs.", + Description = "The 155 is a classic heavy artillery round, with good reason. A versatile weapon, it's found on most modern SPGs.", Model = "models/howitzer/howitzer_155mm.mdl", Caliber = 155, Mass = 5340, diff --git a/lua/entities/acf_ammo/init.lua b/lua/entities/acf_ammo/init.lua index 4c4f0b126..2d5513a95 100644 --- a/lua/entities/acf_ammo/init.lua +++ b/lua/entities/acf_ammo/init.lua @@ -329,7 +329,7 @@ do -- Spawning and Updating -------------------- -- for future use in reloading --Entity.isBoxed = ExtraData.isBoxed -- Ammunition is boxed - --Entity.isTwoPiece = ExtraData.isTwoPiece -- Ammunition is broken down to two pieces + --Entity.isTwoPiece = ExtraData.isTwoPiece -- Ammunition is broken down to two pieces ExtraData.MagSize = ExtraData.isBoxed and MagSize or 0 ExtraData.IsRound = not (ExtraData.isBoxed or ExtraData.isTwoPiece or ExtraData.isRacked) diff --git a/lua/entities/acf_engine/init.lua b/lua/entities/acf_engine/init.lua index e85e7a884..161d45ce0 100644 --- a/lua/entities/acf_engine/init.lua +++ b/lua/entities/acf_engine/init.lua @@ -789,7 +789,7 @@ function ENT:PreEntityCopy() end function ENT:PostEntityPaste(Player, Ent, CreatedEntities) - local EntMods = Ent.EntityMods + local EntMods = Ent.EntityMods -- Backwards compatibility if EntMods.GearLink then diff --git a/lua/entities/acf_gun/init.lua b/lua/entities/acf_gun/init.lua index 6c73a080a..9f472dbef 100644 --- a/lua/entities/acf_gun/init.lua +++ b/lua/entities/acf_gun/init.lua @@ -526,7 +526,7 @@ do -- Metamethods -------------------------------- self.CurrentUser = self:GetUser(self.Inputs.Fire.Src) -- Must be updated on every shot self.BulletData.Owner = self.CurrentUser - self.BulletData.Gun = self -- because other guns share this table + self.BulletData.Gun = self -- because other guns share this table self.BulletData.Pos = self:BarrelCheck(Velocity * engine.TickInterval()) self.BulletData.Flight = Dir * self.BulletData.MuzzleVel * 39.37 + Velocity self.BulletData.Fuze = self.Fuze -- Must be set when firing as the table is shared diff --git a/lua/weapons/gmod_tool/stools/acfarmorprop.lua b/lua/weapons/gmod_tool/stools/acfarmorprop.lua index 1985968dd..917d69893 100644 --- a/lua/weapons/gmod_tool/stools/acfarmorprop.lua +++ b/lua/weapons/gmod_tool/stools/acfarmorprop.lua @@ -47,7 +47,7 @@ end if CLIENT then language.Add("tool.acfarmorprop.name", "ACF Armor Properties") language.Add("tool.acfarmorprop.desc", "Sets the weight of a prop by desired armor thickness and ductility.") - language.Add("tool.acfarmorprop.0", "Left click to apply settings. Right click to copy settings. Reload to get the total mass of an object and all constrained objects.") + language.Add("tool.acfarmorprop.0", "Left click to apply settings. Right click to copy settings. Reload to get the total mass of an object and all constrained objects.") surface.CreateFont("Torchfont", { size = 40, weight = 1000, font = "arial" }) @@ -69,7 +69,7 @@ if CLIENT then Panel:ControlHelp("Set the desired armor thickness (in mm) and the mass will be adjusted accordingly.") Panel:NumSlider("Ductility", "acfarmorprop_ductility", -80, 80) - Panel:ControlHelp("Set the desired armor ductility (thickness-vs-health bias). A ductile prop can survive more damage but is penetrated more easily (slider > 0). A non-ductile prop is brittle - hardened against penetration, but more easily shattered by bullets and explosions (slider < 0).") + Panel:ControlHelp("Set the desired armor ductility (thickness-vs-health bias). A ductile prop can survive more damage but is penetrated more easily (slider > 0). A non-ductile prop is brittle - hardened against penetration, but more easily shattered by bullets and explosions (slider < 0).") local SphereCheck = Panel:CheckBox("Use sphere search for armor readout", "acfarmorprop_sphere_search") Panel:ControlHelp("If checked, the tool will find all the props in a sphere around the hit position instead of getting all the entities connected to a prop.") From b9ad64ebb28b66a1ceeef48088cd5da401171d0c Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sat, 12 Dec 2020 06:10:05 -0300 Subject: [PATCH 211/279] Added custom attachments to engine models - Now every engine model will use custom attachments to prevent entity update issues. --- lua/acf/shared/engines/b4.lua | 3 +++ lua/acf/shared/engines/b6.lua | 4 ++++ lua/acf/shared/engines/electric.lua | 8 ++++++++ lua/acf/shared/engines/i2.lua | 3 +++ lua/acf/shared/engines/i3.lua | 6 +++++- lua/acf/shared/engines/i4.lua | 4 ++++ lua/acf/shared/engines/i5.lua | 3 +++ lua/acf/shared/engines/i6.lua | 4 ++++ lua/acf/shared/engines/radial.lua | 6 +++++- lua/acf/shared/engines/rotary.lua | 6 +++++- lua/acf/shared/engines/single.lua | 6 +++++- lua/acf/shared/engines/special.lua | 2 ++ lua/acf/shared/engines/turbine.lua | 7 +++++++ lua/acf/shared/engines/v10.lua | 4 ++++ lua/acf/shared/engines/v12.lua | 4 ++++ lua/acf/shared/engines/v2.lua | 4 ++++ lua/acf/shared/engines/v4.lua | 3 +++ lua/acf/shared/engines/v6.lua | 4 ++++ lua/acf/shared/engines/v8.lua | 4 ++++ 19 files changed, 81 insertions(+), 4 deletions(-) diff --git a/lua/acf/shared/engines/b4.lua b/lua/acf/shared/engines/b4.lua index 36acf5bc0..460cf8da3 100644 --- a/lua/acf/shared/engines/b4.lua +++ b/lua/acf/shared/engines/b4.lua @@ -78,3 +78,6 @@ do }, }) end + +ACF.SetCustomAttachment("models/engines/b4med.mdl", "driveshaft", Vector(), Angle(0, 0, 90)) +ACF.SetCustomAttachment("models/engines/b4small.mdl", "driveshaft", Vector(), Angle(0, 0, 90)) diff --git a/lua/acf/shared/engines/b6.lua b/lua/acf/shared/engines/b6.lua index da5c70071..2189e4461 100644 --- a/lua/acf/shared/engines/b6.lua +++ b/lua/acf/shared/engines/b6.lua @@ -78,3 +78,7 @@ do }, }) end + +ACF.SetCustomAttachment("models/engines/b6large.mdl", "driveshaft", Vector(), Angle(0, 0, 90)) +ACF.SetCustomAttachment("models/engines/b6med.mdl", "driveshaft", Vector(), Angle(0, 0, 90)) +ACF.SetCustomAttachment("models/engines/b6small.mdl", "driveshaft", Vector(), Angle(0, 0, 90)) diff --git a/lua/acf/shared/engines/electric.lua b/lua/acf/shared/engines/electric.lua index 53c0b851c..d07964987 100644 --- a/lua/acf/shared/engines/electric.lua +++ b/lua/acf/shared/engines/electric.lua @@ -154,3 +154,11 @@ do -- Electric Standalone Motors } }) end + +ACF.SetCustomAttachment("models/engines/emotorlarge.mdl", "driveshaft", Vector(), Angle(0, 0, 90)) +ACF.SetCustomAttachment("models/engines/emotormed.mdl", "driveshaft", Vector(), Angle(0, 0, 90)) +ACF.SetCustomAttachment("models/engines/emotorsmall.mdl", "driveshaft", Vector(), Angle(0, 0, 90)) +ACF.SetCustomAttachment("models/engines/emotor-standalone-big.mdl", "driveshaft", Vector(), Angle(0, -90, 90)) +ACF.SetCustomAttachment("models/engines/emotor-standalone-mid.mdl", "driveshaft", Vector(), Angle(0, -90, 90)) +ACF.SetCustomAttachment("models/engines/emotor-standalone-sml.mdl", "driveshaft", Vector(), Angle(0, -90, 90)) +ACF.SetCustomAttachment("models/engines/emotor-standalone-tiny.mdl", "driveshaft", Vector(), Angle(0, -90, 90)) diff --git a/lua/acf/shared/engines/i2.lua b/lua/acf/shared/engines/i2.lua index 4c754c7c9..1dc2b55f6 100644 --- a/lua/acf/shared/engines/i2.lua +++ b/lua/acf/shared/engines/i2.lua @@ -42,3 +42,6 @@ do } }) end + +ACF.SetCustomAttachment("models/engines/inline2b.mdl", "driveshaft", Vector(), Angle(0, 180, 90)) +ACF.SetCustomAttachment("models/engines/inline2s.mdl", "driveshaft", Vector(-6, 0, 4), Angle(0, 180, 90)) diff --git a/lua/acf/shared/engines/i3.lua b/lua/acf/shared/engines/i3.lua index 5bde7973a..0e2224d40 100644 --- a/lua/acf/shared/engines/i3.lua +++ b/lua/acf/shared/engines/i3.lua @@ -115,4 +115,8 @@ do -- Diesel Engines Limit = 2000 } }) -end \ No newline at end of file +end + +ACF.SetCustomAttachment("models/engines/inline3b.mdl", "driveshaft", Vector(-15, 0, 11), Angle(0, 180, 90)) +ACF.SetCustomAttachment("models/engines/inline3m.mdl", "driveshaft", Vector(-9, 0, 6.6), Angle(0, 180, 90)) +ACF.SetCustomAttachment("models/engines/inline3s.mdl", "driveshaft", Vector(-6, 0, 4.4), Angle(0, 180, 90)) diff --git a/lua/acf/shared/engines/i4.lua b/lua/acf/shared/engines/i4.lua index 541e29edb..07ac6b562 100644 --- a/lua/acf/shared/engines/i4.lua +++ b/lua/acf/shared/engines/i4.lua @@ -116,3 +116,7 @@ do -- Diesel Engines } }) end + +ACF.SetCustomAttachment("models/engines/inline4l.mdl", "driveshaft", Vector(-15, 0, 10), Angle(0, 180, 90)) +ACF.SetCustomAttachment("models/engines/inline4m.mdl", "driveshaft", Vector(-9, 0, 6), Angle(0, 180, 90)) +ACF.SetCustomAttachment("models/engines/inline4s.mdl", "driveshaft", Vector(-6, 0, 4), Angle(0, 180, 90)) diff --git a/lua/acf/shared/engines/i5.lua b/lua/acf/shared/engines/i5.lua index b8fa80a4c..774338a24 100644 --- a/lua/acf/shared/engines/i5.lua +++ b/lua/acf/shared/engines/i5.lua @@ -80,3 +80,6 @@ do -- Diesel Engines } }) end + +ACF.SetCustomAttachment("models/engines/inline5m.mdl", "driveshaft", Vector(-15, 0, 6.6), Angle(0, 180, 90)) +ACF.SetCustomAttachment("models/engines/inline5s.mdl", "driveshaft", Vector(-10, 0, 4.4), Angle(0, 180, 90)) diff --git a/lua/acf/shared/engines/i6.lua b/lua/acf/shared/engines/i6.lua index 8a181b165..e59e09056 100644 --- a/lua/acf/shared/engines/i6.lua +++ b/lua/acf/shared/engines/i6.lua @@ -116,3 +116,7 @@ do -- Diesel Engines } }) end + +ACF.SetCustomAttachment("models/engines/inline6l.mdl", "driveshaft", Vector(-30, 0, 11), Angle(0, 180, 90)) +ACF.SetCustomAttachment("models/engines/inline6m.mdl", "driveshaft", Vector(-18, 0, 6.6), Angle(0, 180, 90)) +ACF.SetCustomAttachment("models/engines/inline6s.mdl", "driveshaft", Vector(-12, 0, 4.4), Angle(0, 180, 90)) diff --git a/lua/acf/shared/engines/radial.lua b/lua/acf/shared/engines/radial.lua index 96f5d9ba7..ea0e97f66 100644 --- a/lua/acf/shared/engines/radial.lua +++ b/lua/acf/shared/engines/radial.lua @@ -77,4 +77,8 @@ do Limit = 3500, } }) -end \ No newline at end of file +end + +ACF.SetCustomAttachment("models/engines/radial7l.mdl", "driveshaft", Vector(-12), Angle(0, 180, 90)) +ACF.SetCustomAttachment("models/engines/radial7m.mdl", "driveshaft", Vector(-8), Angle(0, 180, 90)) +ACF.SetCustomAttachment("models/engines/radial7s.mdl", "driveshaft", Vector(-6), Angle(0, 180, 90)) diff --git a/lua/acf/shared/engines/rotary.lua b/lua/acf/shared/engines/rotary.lua index 9aabd8626..9bc016d8e 100644 --- a/lua/acf/shared/engines/rotary.lua +++ b/lua/acf/shared/engines/rotary.lua @@ -60,4 +60,8 @@ do Limit = 9500, } }) -end \ No newline at end of file +end + +ACF.SetCustomAttachment("models/engines/wankel_3_med.mdl", "driveshaft", Vector(), Angle(0, 0, 90)) +ACF.SetCustomAttachment("models/engines/wankel_2_med.mdl", "driveshaft", Vector(), Angle(0, 0, 90)) +ACF.SetCustomAttachment("models/engines/wankel_2_small.mdl", "driveshaft", Vector(), Angle(0, 0, 90)) diff --git a/lua/acf/shared/engines/single.lua b/lua/acf/shared/engines/single.lua index f0bc73cc7..ab265f252 100644 --- a/lua/acf/shared/engines/single.lua +++ b/lua/acf/shared/engines/single.lua @@ -59,4 +59,8 @@ do Limit = 6700, } }) -end \ No newline at end of file +end + +ACF.SetCustomAttachment("models/engines/1cylbig.mdl", "driveshaft", Vector(), Angle(0, -90, 90)) +ACF.SetCustomAttachment("models/engines/1cylmed.mdl", "driveshaft", Vector(), Angle(0, -90, 90)) +ACF.SetCustomAttachment("models/engines/1cylsml.mdl", "driveshaft", Vector(), Angle(0, -90, 90)) diff --git a/lua/acf/shared/engines/special.lua b/lua/acf/shared/engines/special.lua index 57c9fa42f..22896ad87 100644 --- a/lua/acf/shared/engines/special.lua +++ b/lua/acf/shared/engines/special.lua @@ -222,3 +222,5 @@ do -- Special V12 Engines } }) end + +ACF.SetCustomAttachment("models/engines/wankel_4_med.mdl", "driveshaft", Vector(), Angle(0, 0, 90)) diff --git a/lua/acf/shared/engines/turbine.lua b/lua/acf/shared/engines/turbine.lua index f9bc76427..614e807e3 100644 --- a/lua/acf/shared/engines/turbine.lua +++ b/lua/acf/shared/engines/turbine.lua @@ -268,3 +268,10 @@ do -- Transaxial Ground Gas Turbines } }) end + +ACF.SetCustomAttachment("models/engines/turbine_l.mdl", "driveshaft", Vector(0, -15), Angle(0, -90)) +ACF.SetCustomAttachment("models/engines/turbine_m.mdl", "driveshaft", Vector(0, -11.25), Angle(0, -90)) +ACF.SetCustomAttachment("models/engines/turbine_s.mdl", "driveshaft", Vector(0, -7.5), Angle(0, -90)) +ACF.SetCustomAttachment("models/engines/gasturbine_l.mdl", "driveshaft", Vector(-42), Angle(0, -180)) +ACF.SetCustomAttachment("models/engines/gasturbine_m.mdl", "driveshaft", Vector(-31.5), Angle(0, -180)) +ACF.SetCustomAttachment("models/engines/gasturbine_s.mdl", "driveshaft", Vector(-21), Angle(0, -180)) diff --git a/lua/acf/shared/engines/v10.lua b/lua/acf/shared/engines/v10.lua index 79acd8764..f8a337ab0 100644 --- a/lua/acf/shared/engines/v10.lua +++ b/lua/acf/shared/engines/v10.lua @@ -59,3 +59,7 @@ do } }) end + +ACF.SetCustomAttachment("models/engines/v10big.mdl", "driveshaft", Vector(-33, 0, 7.2), Angle(0, 0, 90)) +ACF.SetCustomAttachment("models/engines/v10med.mdl", "driveshaft", Vector(-21.95, 0, 4.79), Angle(0, 0, 90)) +ACF.SetCustomAttachment("models/engines/v10sml.mdl", "driveshaft", Vector(-17.56, 0, 3.83), Angle(0, 0, 90)) diff --git a/lua/acf/shared/engines/v12.lua b/lua/acf/shared/engines/v12.lua index 15973e24d..7a7394395 100644 --- a/lua/acf/shared/engines/v12.lua +++ b/lua/acf/shared/engines/v12.lua @@ -134,3 +134,7 @@ do -- Diesel Engines } }) end + +ACF.SetCustomAttachment("models/engines/v12l.mdl", "driveshaft", Vector(-34, 0, 7.3), Angle(0, 90, 90)) +ACF.SetCustomAttachment("models/engines/v12m.mdl", "driveshaft", Vector(-22.61, 0, 4.85), Angle(0, 90, 90)) +ACF.SetCustomAttachment("models/engines/v12s.mdl", "driveshaft", Vector(-18.09, 0, 3.88), Angle(0, 90, 90)) diff --git a/lua/acf/shared/engines/v2.lua b/lua/acf/shared/engines/v2.lua index 1d30bdc30..53f716a0c 100644 --- a/lua/acf/shared/engines/v2.lua +++ b/lua/acf/shared/engines/v2.lua @@ -60,3 +60,7 @@ do -- Petrol Engines } }) end + +ACF.SetCustomAttachment("models/engines/v-twinl2.mdl", "driveshaft", Vector(), Angle(0, 90, 90)) +ACF.SetCustomAttachment("models/engines/v-twinm2.mdl", "driveshaft", Vector(), Angle(0, 90, 90)) +ACF.SetCustomAttachment("models/engines/v-twins2.mdl", "driveshaft", Vector(), Angle(0, 90, 90)) diff --git a/lua/acf/shared/engines/v4.lua b/lua/acf/shared/engines/v4.lua index 5638c4836..e89650773 100644 --- a/lua/acf/shared/engines/v4.lua +++ b/lua/acf/shared/engines/v4.lua @@ -42,3 +42,6 @@ do -- Diesel Engines } }) end + +ACF.SetCustomAttachment("models/engines/v4m.mdl", "driveshaft", Vector(-5.99, 0, 4.85), Angle(0, 90, 90)) +ACF.SetCustomAttachment("models/engines/v4s.mdl", "driveshaft", Vector(-4.79, 0, 3.88), Angle(0, 90, 90)) diff --git a/lua/acf/shared/engines/v6.lua b/lua/acf/shared/engines/v6.lua index e0dd68e20..02ff06541 100644 --- a/lua/acf/shared/engines/v6.lua +++ b/lua/acf/shared/engines/v6.lua @@ -99,3 +99,7 @@ do -- Diesel Engines } }) end + +ACF.SetCustomAttachment("models/engines/v6large.mdl", "driveshaft", Vector(2), Angle(0, 90, 90)) +ACF.SetCustomAttachment("models/engines/v6med.mdl", "driveshaft", Vector(1.33), Angle(0, 90, 90)) +ACF.SetCustomAttachment("models/engines/v6small.mdl", "driveshaft", Vector(1.06), Angle(0, 90, 90)) diff --git a/lua/acf/shared/engines/v8.lua b/lua/acf/shared/engines/v8.lua index 010e4137c..acd94b6d2 100644 --- a/lua/acf/shared/engines/v8.lua +++ b/lua/acf/shared/engines/v8.lua @@ -116,3 +116,7 @@ do -- Diesel Engines } }) end + +ACF.SetCustomAttachment("models/engines/v8l.mdl", "driveshaft", Vector(-25.6, 0, 7.4), Angle(0, 90, 90)) +ACF.SetCustomAttachment("models/engines/v8m.mdl", "driveshaft", Vector(-17.02, 0, 4.92), Angle(0, 90, 90)) +ACF.SetCustomAttachment("models/engines/v8s.mdl", "driveshaft", Vector(-13.62, 0, 3.94), Angle(0, 90, 90)) From 62f617c0bdf92285a6a6183f10574ee3c24afc98 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sat, 12 Dec 2020 06:41:42 -0300 Subject: [PATCH 212/279] Added custom attachments to gearbox models - Now every gearbox model will use custom attachments to prevent entity update issues. - Minor changes on some weapon model custom attachment definitions. --- lua/acf/shared/gearboxes/clutch.lua | 21 +++++++++++++++ lua/acf/shared/gearboxes/cvt.lua | 20 ++++++++++++-- lua/acf/shared/gearboxes/differential.lua | 31 ++++++++++++++++++++++ lua/acf/shared/weapons/cannon.lua | 10 +++---- lua/acf/shared/weapons/heavymachinegun.lua | 12 ++++----- 5 files changed, 81 insertions(+), 13 deletions(-) diff --git a/lua/acf/shared/gearboxes/clutch.lua b/lua/acf/shared/gearboxes/clutch.lua index df9b7c6e8..01f41059b 100644 --- a/lua/acf/shared/gearboxes/clutch.lua +++ b/lua/acf/shared/gearboxes/clutch.lua @@ -62,3 +62,24 @@ do -- Straight-through Gearboxes MaxTorque = CLT, }) end + +ACF.SetCustomAttachments("models/engines/flywheelclutchb.mdl", { + { Name = "input", Pos = Vector(), Ang = Angle(0, 0, 90) }, + { Name = "driveshaftR", Pos = Vector(0, 6), Ang = Angle(0, 180, 90) }, + { Name = "driveshaftL", Pos = Vector(0, 6), Ang = Angle(0, 180, 90) }, +}) +ACF.SetCustomAttachments("models/engines/flywheelclutchm.mdl", { + { Name = "input", Pos = Vector(), Ang = Angle(0, 0, 90) }, + { Name = "driveshaftR", Pos = Vector(0, 4), Ang = Angle(0, 180, 90) }, + { Name = "driveshaftL", Pos = Vector(0, 4), Ang = Angle(0, 180, 90) }, +}) +ACF.SetCustomAttachments("models/engines/flywheelclutchs.mdl", { + { Name = "input", Pos = Vector(), Ang = Angle(0, 0, 90) }, + { Name = "driveshaftR", Pos = Vector(0, 3), Ang = Angle(0, 180, 90) }, + { Name = "driveshaftL", Pos = Vector(0, 3), Ang = Angle(0, 180, 90) }, +}) +ACF.SetCustomAttachments("models/engines/flywheelclutcht.mdl", { + { Name = "input", Pos = Vector(), Ang = Angle(0, 0, 90) }, + { Name = "driveshaftR", Pos = Vector(0, 2), Ang = Angle(0, 180, 90) }, + { Name = "driveshaftL", Pos = Vector(0, 2), Ang = Angle(0, 180, 90) }, +}) diff --git a/lua/acf/shared/gearboxes/cvt.lua b/lua/acf/shared/gearboxes/cvt.lua index 4cf92b1cd..626c50329 100644 --- a/lua/acf/shared/gearboxes/cvt.lua +++ b/lua/acf/shared/gearboxes/cvt.lua @@ -66,8 +66,8 @@ ACF.RegisterGearboxClass("CVT", { local Text = "Reverse Gear: %s\nTarget: %s - %s RPM" local Gears = Gearbox.Gears local Reverse = math.Round(Gears[2], 2) - local Min = math.Round(Gearbox.MinRPM, 0) - local Max = math.Round(Gearbox.MaxRPM, 0) + local Min = math.Round(Gearbox.MinRPM) + local Max = math.Round(Gearbox.MaxRPM) return Text:format(Reverse, Min, Max) end, @@ -223,3 +223,19 @@ do -- Straight-through Gearboxes MaxTorque = math.floor(GearCVTLT * StTB), }) end + +ACF.SetCustomAttachments("models/engines/t5large.mdl", { + { Name = "input", Pos = Vector(), Ang = Angle(0, 0, 90) }, + { Name = "driveshaftR", Pos = Vector(0, 30), Ang = Angle(0, -180, 90) }, + { Name = "driveshaftL", Pos = Vector(0, 30), Ang = Angle(0, -180, 90) }, +}) +ACF.SetCustomAttachments("models/engines/t5med.mdl", { + { Name = "input", Pos = Vector(), Ang = Angle(0, 0, 90) }, + { Name = "driveshaftR", Pos = Vector(0, 25), Ang = Angle(0, -180, 90) }, + { Name = "driveshaftL", Pos = Vector(0, 25), Ang = Angle(0, -180, 90) }, +}) +ACF.SetCustomAttachments("models/engines/t5small.mdl", { + { Name = "input", Pos = Vector(), Ang = Angle(0, 0, 90) }, + { Name = "driveshaftR", Pos = Vector(0, 20), Ang = Angle(0, -180, 90) }, + { Name = "driveshaftL", Pos = Vector(0, 20), Ang = Angle(0, -180, 90) }, +}) diff --git a/lua/acf/shared/gearboxes/differential.lua b/lua/acf/shared/gearboxes/differential.lua index de89fe2a7..f5c575dd2 100644 --- a/lua/acf/shared/gearboxes/differential.lua +++ b/lua/acf/shared/gearboxes/differential.lua @@ -135,3 +135,34 @@ do -- Transaxial Dual Clutch Gearboxes DualClutch = true, }) end + +ACF.SetCustomAttachments("models/engines/transaxial_l.mdl", { + { Name = "driveshaftR", Pos = Vector(0, 20, 8), Ang = Angle(0, 90, 90) }, + { Name = "driveshaftL", Pos = Vector(0, -20, 8), Ang = Angle(0, -90, 90) }, + { Name = "input", Pos = Vector(20, 0, 8), Ang = Angle(0, 0, 90) }, +}) +ACF.SetCustomAttachments("models/engines/transaxial_m.mdl", { + { Name = "driveshaftR", Pos = Vector(0, 12, 4.8), Ang = Angle(0, 90, 90) }, + { Name = "driveshaftL", Pos = Vector(0, -12, 4.8), Ang = Angle(0, -90, 90) }, + { Name = "input", Pos = Vector(12, 0, 4.8), Ang = Angle(0, 0, 90) }, +}) +ACF.SetCustomAttachments("models/engines/transaxial_s.mdl", { + { Name = "driveshaftR", Pos = Vector(0, 8, 3.2), Ang = Angle(0, 90, 90) }, + { Name = "driveshaftL", Pos = Vector(0, -8, 3.2), Ang = Angle(0, -90, 90) }, + { Name = "input", Pos = Vector(8, 0, 3.2), Ang = Angle(0, 0, 90) }, +}) +ACF.SetCustomAttachments("models/engines/linear_l.mdl", { + { Name = "driveshaftR", Pos = Vector(0, 20, 8), Ang = Angle(0, 90, 90) }, + { Name = "driveshaftL", Pos = Vector(0, -24, 8), Ang = Angle(0, -90, 90) }, + { Name = "input", Pos = Vector(0, 4, 29), Ang = Angle(0, -90, 90) }, +}) +ACF.SetCustomAttachments("models/engines/linear_m.mdl", { + { Name = "driveshaftR", Pos = Vector(0, 12, 4.8), Ang = Angle(0, 90, 90) }, + { Name = "driveshaftL", Pos = Vector(0, -14.4, 4.8), Ang = Angle(0, -90, 90) }, + { Name = "input", Pos = Vector(0, 2.4, 17.4), Ang = Angle(0, -90, 90) }, +}) +ACF.SetCustomAttachments("models/engines/linear_s.mdl", { + { Name = "driveshaftR", Pos = Vector(0, 8, 3.2), Ang = Angle(0, 90, 90) }, + { Name = "driveshaftL", Pos = Vector(0, -9.6, 3.2), Ang = Angle(0, -90, 90) }, + { Name = "input", Pos = Vector(0, 1.6, 11.6), Ang = Angle(0, -90, 90) }, +}) diff --git a/lua/acf/shared/weapons/cannon.lua b/lua/acf/shared/weapons/cannon.lua index ac3158c53..9de9887f5 100644 --- a/lua/acf/shared/weapons/cannon.lua +++ b/lua/acf/shared/weapons/cannon.lua @@ -91,8 +91,8 @@ ACF.RegisterWeapon("140mmC", "C", { }) ACF.SetCustomAttachment("models/tankgun/tankgun_37mm.mdl", "muzzle", Vector(55.77), Angle(0, 0, 90)) -ACF.SetCustomAttachment("models/tankgun/tankgun_50mm.mdl", "muzzle", Vector(75.36, -0.01, 0), Angle(0, 0, 90)) -ACF.SetCustomAttachment("models/tankgun/tankgun_75mm.mdl", "muzzle", Vector(113.04, -0.01, 0), Angle(0, 0, 90)) -ACF.SetCustomAttachment("models/tankgun/tankgun_100mm.mdl", "muzzle", Vector(150.72, -0.01, 0), Angle(0, 0, 90)) -ACF.SetCustomAttachment("models/tankgun/tankgun_120mm.mdl", "muzzle", Vector(180.85, -0.02, 0), Angle(0, 0, 90)) -ACF.SetCustomAttachment("models/tankgun/tankgun_140mm.mdl", "muzzle", Vector(210.99, -0.02, 0), Angle(0, 0, 90)) +ACF.SetCustomAttachment("models/tankgun/tankgun_50mm.mdl", "muzzle", Vector(75.36, -0.01), Angle(0, 0, 90)) +ACF.SetCustomAttachment("models/tankgun/tankgun_75mm.mdl", "muzzle", Vector(113.04, -0.01), Angle(0, 0, 90)) +ACF.SetCustomAttachment("models/tankgun/tankgun_100mm.mdl", "muzzle", Vector(150.72, -0.01), Angle(0, 0, 90)) +ACF.SetCustomAttachment("models/tankgun/tankgun_120mm.mdl", "muzzle", Vector(180.85, -0.02), Angle(0, 0, 90)) +ACF.SetCustomAttachment("models/tankgun/tankgun_140mm.mdl", "muzzle", Vector(210.99, -0.02), Angle(0, 0, 90)) diff --git a/lua/acf/shared/weapons/heavymachinegun.lua b/lua/acf/shared/weapons/heavymachinegun.lua index ef57625c9..296ec43b1 100644 --- a/lua/acf/shared/weapons/heavymachinegun.lua +++ b/lua/acf/shared/weapons/heavymachinegun.lua @@ -80,16 +80,16 @@ ACF.RegisterWeapon("40mmHMG", "HMG", { }) ACF.SetCustomAttachments("models/machinegun/machinegun_20mm_compact.mdl", { - { Name = "muzzle", Pos = Vector(30.93, -0.02, 0), Ang = Angle(0, 0, 90) }, - { Name = "muzzle2", Pos = Vector(69.93, -0.15, 0), Ang = Angle(0, 0, 90) }, + { Name = "muzzle", Pos = Vector(30.93, -0.02), Ang = Angle(0, 0, 90) }, + { Name = "muzzle2", Pos = Vector(69.93, -0.15), Ang = Angle(0, 0, 90) }, }) ACF.SetCustomAttachments("models/machinegun/machinegun_30mm_compact.mdl", { - { Name = "muzzle", Pos = Vector(41.76, -0.03, 0), Ang = Angle(0, 0, 90) }, - { Name = "muzzle2", Pos = Vector(94.41, -0.2, 0), Ang = Angle(0, 0, 90) }, + { Name = "muzzle", Pos = Vector(41.76, -0.03), Ang = Angle(0, 0, 90) }, + { Name = "muzzle2", Pos = Vector(94.41, -0.2), Ang = Angle(0, 0, 90) }, }) ACF.SetCustomAttachments("models/machinegun/machinegun_40mm_compact.mdl", { - { Name = "muzzle", Pos = Vector(51.04, -0.03, 0), Ang = Angle(0, 0, 90) }, - { Name = "muzzle2", Pos = Vector(115.39, -0.25, 0), Ang = Angle(0, 0, 90) }, + { Name = "muzzle", Pos = Vector(51.04, -0.03), Ang = Angle(0, 0, 90) }, + { Name = "muzzle2", Pos = Vector(115.39, -0.25), Ang = Angle(0, 0, 90) }, }) From cd6eb8ed110420e1ff7b637af1405acbd68bbc3c Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sun, 13 Dec 2020 03:21:43 -0300 Subject: [PATCH 213/279] Improved tool data vars functions - ACF.ReadData/ACF.ReadRaw will now properly return the converted value instead of the default value if the first happens to be false. - Fixed serverside ACF.ReadData/ACF.ReadRaw always returning the default value. - ACF.ReadNumber and ACF.ReadString will now use ACF.CheckFunction and ACF.CheckString respectively. - The OnToolDataUpdate hook will now be also called serverside, the only difference being the first argument being the player instead of the key. The other two arguments are still given. --- lua/acf/base/util/cl_util.lua | 8 +++++--- lua/acf/base/util/sv_util.lua | 12 ++++++++---- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/lua/acf/base/util/cl_util.lua b/lua/acf/base/util/cl_util.lua index 9a2a44605..8c8e1736f 100644 --- a/lua/acf/base/util/cl_util.lua +++ b/lua/acf/base/util/cl_util.lua @@ -88,7 +88,9 @@ do -- Tool data functions local Value = ToolData[Key] - return Value ~= nil and Value or Default + if Value ~= nil then return Value end + + return Default end function ACF.ReadBool(Key, Default) @@ -98,13 +100,13 @@ do -- Tool data functions function ACF.ReadNumber(Key, Default) local Value = ReadData(Key, Default) - return Value ~= nil and tonumber(Value) or 0 -- tonumber can't handle nil values + return ACF.CheckNumber(Value, 0) end function ACF.ReadString(Key) local Value = ReadData(Key, Default) - return Value ~= nil and tostring(Value) or "" -- tostring can't handle nil values + return ACF.CheckString(Value, "") end ACF.ReadData = ReadData diff --git a/lua/acf/base/util/sv_util.lua b/lua/acf/base/util/sv_util.lua index db9aa48d9..e6949a11d 100644 --- a/lua/acf/base/util/sv_util.lua +++ b/lua/acf/base/util/sv_util.lua @@ -72,6 +72,8 @@ do -- Tool data functions local Value = net.ReadType() ToolData[Player][Key] = Value + + hook.Run("OnToolDataUpdate", Player, Key, Value) end) hook.Add("PlayerInitialSpawn", "ACF Tool Data", function(Player) @@ -102,9 +104,11 @@ do -- Tool data functions if not ToolData[Player] then return end if Key == nil then return end - local Value = ToolData[Key] + local Value = ToolData[Player][Key] + + if Value ~= nil then return Value end - return Value ~= nil and Value or Default + return Default end function ACF.ReadBool(Player, Key, Default) @@ -114,13 +118,13 @@ do -- Tool data functions function ACF.ReadNumber(Player, Key, Default) local Value = ReadData(Player, Key, Default) - return Value ~= nil and tonumber(Value) or 0 -- tonumber can't handle nil values + return ACF.CheckNumber(Value, 0) end function ACF.ReadString(Player, Key, Default) local Value = ReadData(Player, Key, Default) - return Value ~= nil and tostring(Value) or "" -- tostring can't handle nil values + return ACF.CheckString(Value, "") end ACF.ReadData = ReadData From 367aedff1f33004687806ed72a53f641d13c0af9 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sun, 13 Dec 2020 03:25:07 -0300 Subject: [PATCH 214/279] Improved ACF Tool functions - ACF Tools that are using the ACF.LoadToolFunctions function will now properly retain the stage and operation between player deaths and weapon drops. Fixes #150. - ACF.LoadToolFunctions will now set the tool category based on the value of the acf_tool_category convar. --- lua/acf/base/acf_globals.lua | 2 +- lua/acf/base/sh_tool_functions.lua | 113 +++++++++++++--------- lua/weapons/gmod_tool/stools/acf_menu.lua | 5 +- lua/weapons/gmod_tool/stools/acfcopy.lua | 5 +- 4 files changed, 74 insertions(+), 51 deletions(-) diff --git a/lua/acf/base/acf_globals.lua b/lua/acf/base/acf_globals.lua index 590babbd5..0e6ba5d86 100644 --- a/lua/acf/base/acf_globals.lua +++ b/lua/acf/base/acf_globals.lua @@ -200,7 +200,7 @@ elseif CLIENT then --------------------------------------------- -- Custom Tool Category --------------------- - ACF.CustomToolCategory = CreateClientConVar("acf_tool_category", 0, true, false) + ACF.CustomToolCategory = CreateClientConVar("acf_tool_category", 0, true, false, "If enabled, ACF tools will be put inside their own category.", 0, 1) if ACF.CustomToolCategory:GetBool() then language.Add("spawnmenu.tools.acf", "ACF") diff --git a/lua/acf/base/sh_tool_functions.lua b/lua/acf/base/sh_tool_functions.lua index de19ecea1..5e8796434 100644 --- a/lua/acf/base/sh_tool_functions.lua +++ b/lua/acf/base/sh_tool_functions.lua @@ -138,8 +138,22 @@ do -- Tool Information Registration function end do -- Tool Functions Loader + local Category = GetConVar("acf_tool_category") + if SERVER then util.AddNetworkString("ACF_ToolNetVars") + + hook.Add("PlayerCanPickupWeapon", "ACF Tools", function(Player, Weapon) + if Weapon:GetClass() ~= "gmod_tool" then return end + + for Name in pairs(Tools) do + local Tool = Player:GetTool(Name) + + if Tool then + Tool:RestoreMode() + end + end + end) else net.Receive("ACF_ToolNetVars", function() local ToolName = net.ReadString() @@ -212,6 +226,8 @@ do -- Tool Functions Loader end if CLIENT then + Tool.Category = Category:GetBool() and "ACF" or "Construction" + if Data.Information then Tool.Information = {} @@ -251,70 +267,81 @@ do -- Tool Functions Loader self:SetOperation(Op.Index) end + function Tool:RestoreMode() + local ToolMode = ACF.ReadString(self:GetOwner(), "ToolMode:" .. self.Mode) + + if ToolMode then + local Stage, Op = unpack(string.Explode(":", ToolMode), 1, 2) + + self:SetMode(Stage, Op) + end + end + function Tool:LeftClick(Trace) - local OnLeftClick = self.OpData.OnLeftClick + if self.OpData then + local OnLeftClick = self.OpData.OnLeftClick - if OnLeftClick then - return OnLeftClick(self, Trace) + if OnLeftClick then + return OnLeftClick(self, Trace) + end end return false end function Tool:RightClick(Trace) - local OnRightClick = self.OpData.OnRightClick + if self.OpData then + local OnRightClick = self.OpData.OnRightClick - if OnRightClick then - return OnRightClick(self, Trace) + if OnRightClick then + return OnRightClick(self, Trace) + end end return false end function Tool:Reload(Trace) - local OnReload = self.OpData.OnReload + if self.OpData then + local OnReload = self.OpData.OnReload - if OnReload then - return OnReload(self, Trace) + if OnReload then + return OnReload(self, Trace) + end end return false end function Tool:Deploy() - local OnDeploy = self.OpData.OnDeploy + self:RestoreMode() - if self.LastStage then - self:SetStage(self.LastStage) - self:SetOperation(self.LastOp) + if self.OpData then + local OnDeploy = self.OpData.OnDeploy - self.LastStage = nil - self.LastOp = nil - end - - if OnDeploy then - OnDeploy(self) + if OnDeploy then + OnDeploy(self) + end end end function Tool:Holster() - local OnHolster = self.OpData.OnHolster - - if OnHolster then - OnHolster(self) - end + if self.OpData then + local OnHolster = self.OpData.OnHolster - if not self.LastStage then - self.LastStage = self.Stage - self.LastOp = self.Operation + if OnHolster then + OnHolster(self) + end end end function Tool:Think() - local OnThink = self.OpData.OnThink + if self.OpData then + local OnThink = self.OpData.OnThink - if OnThink then - OnThink(self) + if OnThink then + OnThink(self) + end end end end @@ -323,32 +350,30 @@ end do -- Clientside Tool interaction if SERVER then - util.AddNetworkString("ACF_ToolMode") + hook.Add("OnToolDataUpdate", "ACF ToolMode", function(Player, Key, Value) + local Header, Name = unpack(string.Explode(":", Key), 1, 2) - net.Receive("ACF_ToolMode", function(_, Player) - local ToolName = net.ReadString() - local StageName = net.ReadString() - local OpName = net.ReadString() - local Tool = Player:GetTool(ToolName) + if Header ~= "ToolMode" then return end + + local Tool = Player:GetTool(Name) if not Tool then return end if not Tool.SetMode then return end - Tool:SetMode(StageName, OpName) + local Stage, Op = unpack(string.Explode(":", Value), 1, 2) + + Tool:SetMode(Stage, Op) end) else + local Key = "ToolMode:%s" + local Value = "%s:%s" + function ACF.SetToolMode(Tool, Stage, Op) if not isstring(Tool) then return end if not isstring(Stage) then return end if not isstring(Op) then return end - timer.Simple(0, function() -- Yeah. - net.Start("ACF_ToolMode") - net.WriteString(Tool) - net.WriteString(Stage) - net.WriteString(Op) - net.SendToServer() - end) + ACF.WriteValue(Key:format(Tool), Value:format(Stage, Op)) end end end diff --git a/lua/weapons/gmod_tool/stools/acf_menu.lua b/lua/weapons/gmod_tool/stools/acf_menu.lua index a595aa4a8..2072ec5b3 100644 --- a/lua/weapons/gmod_tool/stools/acf_menu.lua +++ b/lua/weapons/gmod_tool/stools/acf_menu.lua @@ -1,8 +1,7 @@ -TOOL.Name = "ACF Menu Test" -TOOL.Category = "Construction" - ACF.LoadToolFunctions(TOOL) +TOOL.Name = "ACF Menu" + if CLIENT then local DrawBoxes = GetConVar("acf_drawboxes") diff --git a/lua/weapons/gmod_tool/stools/acfcopy.lua b/lua/weapons/gmod_tool/stools/acfcopy.lua index 06670a401..08783aba7 100644 --- a/lua/weapons/gmod_tool/stools/acfcopy.lua +++ b/lua/weapons/gmod_tool/stools/acfcopy.lua @@ -1,8 +1,7 @@ -TOOL.Name = "ACF Copy Tool" -TOOL.Category = "Construction" - ACF.LoadToolFunctions(TOOL) +TOOL.Name = "ACF Copy Tool" + if CLIENT then language.Add("Tool.acfcopy.name", "Armored Combat Framework") language.Add("Tool.acfcopy.desc", "Copy information from one ACF entity to another") From d8c99873b3e2522d876d6f09e348063de6c3d3da Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sun, 13 Dec 2020 03:59:20 -0300 Subject: [PATCH 215/279] Fixed scalable entities not respecting AD2 parent pasting - Fixed scalable entities not respecting the advdupe2_paste_parents convar value, leading to them always getting parented when pasted. --- lua/entities/base_scalable/init.lua | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lua/entities/base_scalable/init.lua b/lua/entities/base_scalable/init.lua index 4d600fdee..5686a2adb 100644 --- a/lua/entities/base_scalable/init.lua +++ b/lua/entities/base_scalable/init.lua @@ -164,11 +164,12 @@ do -- AdvDupe2 duped parented ammo workaround hook.Add("AdvDupe_FinishPasting", "ACF Parented Scalable Ent Fix", function(DupeInfo) DupeInfo = unpack(DupeInfo) - local Entities = DupeInfo.CreatedEntities + local CanParent = tobool(DupeInfo.Player:GetInfo("advdupe2_paste_parents")) + local Entities = DupeInfo.CreatedEntities for _, Entity in pairs(Entities) do if Entity.IsScalable and Entity.ParentEnt then - Entity:SetParent(Entity.ParentEnt) + if CanParent then Entity:SetParent(Entity.ParentEnt) end Entity.ParentEnt = nil end From 0cc83a452ee72d4baf91142966424cd697254d81 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sun, 13 Dec 2020 17:01:16 -0300 Subject: [PATCH 216/279] Added basic support for scalable weaponry - Adapted ACF.RoundBaseGunpowder to support scalable weapon definitions. - ACF.GetClassGroup will now return the group table if the given Name is the name of a class that also happens to be scalable. --- lua/acf/base/sh_classes.lua | 17 +++++++++---- lua/acf/base/sh_round_functions.lua | 39 +++++++++++++++++++++-------- 2 files changed, 41 insertions(+), 15 deletions(-) diff --git a/lua/acf/base/sh_classes.lua b/lua/acf/base/sh_classes.lua index 03c093a81..c03234da2 100644 --- a/lua/acf/base/sh_classes.lua +++ b/lua/acf/base/sh_classes.lua @@ -98,13 +98,20 @@ do -- Basic class registration functions return Class end - function ACF.GetClassGroup(Destiny, Class) - if not Destiny then return end - if not Class then return end + function ACF.GetClassGroup(Destiny, Name) + if not istable(Destiny) then return end + if not Name then return end - local Data = Groups[Destiny] + local Data = Groups[Destiny] + local Class = Data and Data[Name] + + if Class then return Class end + + local Group = Destiny[Name] + + if not Group then return end - return Data and Data[Class] + return Group.IsScalable and Group end end diff --git a/lua/acf/base/sh_round_functions.lua b/lua/acf/base/sh_round_functions.lua index 51f986173..5dcd38608 100644 --- a/lua/acf/base/sh_round_functions.lua +++ b/lua/acf/base/sh_round_functions.lua @@ -1,24 +1,43 @@ +local ACF = ACF local Classes = ACF.Classes -local GetClassGroup = ACF.GetClassGroup -function ACF.RoundBaseGunpowder(ToolData, Data) +local function GetWeaponSpecs(ToolData) local Source = Classes[ToolData.Destiny] - local Class = Source and GetClassGroup(Source, ToolData.Weapon) - local Weapon = Class and Class.Lookup[ToolData.Weapon] - local GUIData = {} + local Class = Source and ACF.GetClassGroup(Source, ToolData.Weapon) + + if not Class then return end + + if not Class.IsScalable then + local Weapon = Class.Lookup[ToolData.Weapon] + + if not Weapon then return end + + local RoundData = Weapon.Round - if not Weapon then return Data, GUIData end + return Weapon.Caliber, RoundData.MaxLength, RoundData.PropMass + end + + local Bounds = Class.Caliber + local Caliber = math.Clamp(ToolData.Caliber or 0, Bounds.Min, Bounds.Max) + local Scale = Caliber / Class.BaseCaliber + + return Caliber, Class.BaseLength * Scale, Class.BaseProp * Scale +end + +function ACF.RoundBaseGunpowder(ToolData, Data) + local Caliber, MaxLength, PropMass = GetWeaponSpecs(ToolData) + local GUIData = {} - local RoundData = Weapon.Round + if not Caliber then return Data, GUIData end - Data.Caliber = Weapon.Caliber * 0.1 -- Bullet caliber will have to stay in cm + Data.Caliber = Caliber * 0.1 -- Bullet caliber will have to stay in cm Data.FrArea = 3.1416 * (Data.Caliber * 0.5) ^ 2 - GUIData.MaxRoundLength = math.Round(RoundData.MaxLength * (Data.LengthAdj or 1), 2) + GUIData.MaxRoundLength = math.Round(MaxLength * (Data.LengthAdj or 1), 2) GUIData.MinPropLength = 0.01 GUIData.MinProjLength = math.Round(Data.Caliber * 1.5, 2) - local DesiredProp = math.Round(RoundData.PropMass * 1000 / ACF.PDensity / Data.FrArea, 2) + local DesiredProp = math.Round(PropMass * 1000 / ACF.PDensity / Data.FrArea, 2) local AllowedProp = GUIData.MaxRoundLength - GUIData.MinProjLength GUIData.MaxPropLength = math.min(DesiredProp, AllowedProp) From 80fe606a12dfb9567d9bbc361f099a0dccd0fbf0 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sun, 13 Dec 2020 18:09:58 -0300 Subject: [PATCH 217/279] Added acf_base_simple and acf_base_scalable entities - Added acf_base_simple and acf_base_scalable entities. They'll hold a few common functions that are used along most, if not all, ACF entities. - Updated most final ACF entities to use these bases accordingly. --- lua/entities/acf_ammo/cl_init.lua | 16 +-- lua/entities/acf_ammo/init.lua | 45 ------- lua/entities/acf_ammo/shared.lua | 3 +- lua/entities/acf_base_scalable/cl_init.lua | 26 ++++ lua/entities/acf_base_scalable/init.lua | 137 +++++++++++++++++++++ lua/entities/acf_base_scalable/shared.lua | 6 + lua/entities/acf_base_simple/cl_init.lua | 26 ++++ lua/entities/acf_base_simple/init.lua | 137 +++++++++++++++++++++ lua/entities/acf_base_simple/shared.lua | 6 + lua/entities/acf_engine/cl_init.lua | 18 --- lua/entities/acf_engine/init.lua | 41 ------ lua/entities/acf_engine/shared.lua | 3 +- lua/entities/acf_fueltank/cl_init.lua | 20 +-- lua/entities/acf_fueltank/init.lua | 41 ------ lua/entities/acf_fueltank/shared.lua | 3 +- lua/entities/acf_gearbox/cl_init.lua | 18 --- lua/entities/acf_gearbox/init.lua | 41 ------ lua/entities/acf_gearbox/shared.lua | 3 +- lua/entities/acf_gun/cl_init.lua | 30 ++--- lua/entities/acf_gun/init.lua | 86 ------------- lua/entities/acf_gun/shared.lua | 7 +- 21 files changed, 362 insertions(+), 351 deletions(-) create mode 100644 lua/entities/acf_base_scalable/cl_init.lua create mode 100644 lua/entities/acf_base_scalable/init.lua create mode 100644 lua/entities/acf_base_scalable/shared.lua create mode 100644 lua/entities/acf_base_simple/cl_init.lua create mode 100644 lua/entities/acf_base_simple/init.lua create mode 100644 lua/entities/acf_base_simple/shared.lua diff --git a/lua/entities/acf_ammo/cl_init.lua b/lua/entities/acf_ammo/cl_init.lua index e5bdddf6e..02e40dfd6 100644 --- a/lua/entities/acf_ammo/cl_init.lua +++ b/lua/entities/acf_ammo/cl_init.lua @@ -1,3 +1,5 @@ +DEFINE_BASECLASS("acf_base_scalable") -- Required to get the local BaseClass + include("shared.lua") language.Add("Cleanup_acf_ammo", "ACF Ammo Crates") @@ -5,7 +7,6 @@ language.Add("Cleaned_acf_ammo", "Cleaned up all ACF Ammo Crates") language.Add("SBoxLimit__acf_ammo", "You've reached the ACF Ammo Crates limit!") local MaxRounds = GetConVar("acf_maxroundsdisplay") -local HideInfo = ACF.HideInfoBubble local Refills = {} local Queued = {} @@ -61,7 +62,7 @@ function ENT:Initialize() UpdateAmmoCount(self) end, "Ammo Crate " .. self:EntIndex()) - self.BaseClass.Initialize(self) + BaseClass.Initialize(self) end function ENT:RequestAmmoData() @@ -93,17 +94,6 @@ function ENT:OnFullUpdate() net.SendToServer() end -function ENT:Draw() - self:DoNormalDraw(false, HideInfo()) - - Wire_Render(self) - - if self.GetBeamLength and (not self.GetShowBeam or self:GetShowBeam()) then - -- Every SENT that has GetBeamLength should draw a tracer. Some of them have the GetShowBeam boolean - Wire_DrawTracerBeam(self, 1, self.GetBeamHighlight and self:GetBeamHighlight() or false) - end -end - function ENT:OnRemove() Refills[self] = nil diff --git a/lua/entities/acf_ammo/init.lua b/lua/entities/acf_ammo/init.lua index 2d5513a95..9440eea0f 100644 --- a/lua/entities/acf_ammo/init.lua +++ b/lua/entities/acf_ammo/init.lua @@ -654,40 +654,7 @@ do -- ACF Activation and Damage ----------------- end end --------------------------------------------- -do -- Entity Link/Unlink ------------------------ - local ClassLink = ACF.GetClassLink - local ClassUnlink = ACF.GetClassUnlink - - function ENT:Link(Target) - if not IsValid(Target) then return false, "Attempted to link an invalid entity." end - if self == Target then return false, "Can't link a crate to itself." end - - local Function = ClassLink(self:GetClass(), Target:GetClass()) - - if Function then - return Function(self, Target) - end - - return false, "Crates can't be linked to '" .. Target:GetClass() .. "'." - end - - function ENT:Unlink(Target) - if not IsValid(Target) then return false, "Attempted to unlink an invalid entity." end - if self == Target then return false, "Can't unlink a crate from itself." end - - local Function = ClassUnlink(self:GetClass(), Target:GetClass()) - - if Function then - return Function(self, Target) - end - - return false, "Crates can't be unlinked from '" .. Target:GetClass() .. "'." - end -end --------------------------------------------- - do -- Entity Inputs ----------------------------- - local Inputs = ACF.GetInputActions("acf_ammo") - WireLib.AddInputAlias("Active", "Load") WireLib.AddOutputAlias("Munitions", "Ammo") @@ -696,18 +663,6 @@ do -- Entity Inputs ----------------------------- WireLib.TriggerOutput(Entity, "Loading", Entity:CanConsume() and 1 or 0) end) - - function ENT:TriggerInput(Name, Value) - if self.Disabled then return end -- Ignore input if disabled - - local Action = Inputs[Name] - - if Action then - Action(self, Value) - - self:UpdateOverlay() - end - end end --------------------------------------------- do -- Entity Overlay ---------------------------- diff --git a/lua/entities/acf_ammo/shared.lua b/lua/entities/acf_ammo/shared.lua index 2f162e321..c2f5a22ee 100644 --- a/lua/entities/acf_ammo/shared.lua +++ b/lua/entities/acf_ammo/shared.lua @@ -1,7 +1,8 @@ -DEFINE_BASECLASS("base_scalable_mconvex") +DEFINE_BASECLASS("acf_base_scalable") ENT.PrintName = "ACF Ammo Crate" ENT.WireDebugName = "ACF Ammo Crate" +ENT.PluralName = "ACF Ammo Crates" ENT.IsAmmoCrate = true cleanup.Register("acf_ammo") diff --git a/lua/entities/acf_base_scalable/cl_init.lua b/lua/entities/acf_base_scalable/cl_init.lua new file mode 100644 index 000000000..17077083a --- /dev/null +++ b/lua/entities/acf_base_scalable/cl_init.lua @@ -0,0 +1,26 @@ +DEFINE_BASECLASS("base_scalable_mconvex") -- Required to get the local BaseClass + +include("shared.lua") + +local HideInfo = ACF.HideInfoBubble + +function ENT:Initialize(...) + BaseClass.Initialize(self, ...) + + self:Update() +end + +function ENT:Update() +end + +-- Copied from base_wire_entity: DoNormalDraw's notip arg isn't accessible from ENT:Draw defined there. +function ENT:Draw() + self:DoNormalDraw(false, HideInfo()) + + Wire_Render(self) + + if self.GetBeamLength and (not self.GetShowBeam or self:GetShowBeam()) then + -- Every SENT that has GetBeamLength should draw a tracer. Some of them have the GetShowBeam boolean + Wire_DrawTracerBeam(self, 1, self.GetBeamHighlight and self:GetBeamHighlight() or false) + end +end \ No newline at end of file diff --git a/lua/entities/acf_base_scalable/init.lua b/lua/entities/acf_base_scalable/init.lua new file mode 100644 index 000000000..4a78cf274 --- /dev/null +++ b/lua/entities/acf_base_scalable/init.lua @@ -0,0 +1,137 @@ +AddCSLuaFile("cl_init.lua") +AddCSLuaFile("shared.lua") + +include("shared.lua") + +local ACF = ACF + +-- You should overwrite these +function ENT:Enable() end +function ENT:Disable() end +function ENT:UpdateOverlay() end + +do -- Entity linking and unlinking -------------- + local LinkText = "%s can't be linked to %s." + local UnlinkText = "%s can't be unlinked from %s." + + function ENT:Link(Target) + if not IsValid(Target) then return false, "Attempted to link an invalid entity." end + if self == Target then return false, "Can't link an entity to itself." end + + local Class = Target:GetClass() + local Function = ACF.GetClassLink(self:GetClass(), Class) + + if Function then + return Function(self, Target) + elseif self.DefaultLink then + return self:DefaultLink(Target) + end + + return false, LinkText:format(self.PluralName, Target.PluralName or Class) + end + + function ENT:Unlink(Target) + if not IsValid(Target) then return false, "Attempted to unlink an invalid entity." end + if self == Target then return false, "Can't unlink an entity from itself." end + + local Class = Target:GetClass() + local Function = ACF.GetClassUnlink(self:GetClass(), Class) + + if Function then + return Function(self, Target) + elseif self.DefaultUnlink then + return self:DefaultUnlink(Target) + end + + return false, UnlinkText:format(self.PluralName, Target.PluralName or Class) + end +end --------------------------------------------- + +do -- Entity inputs ----------------------------- + local function SetupInputActions(Entity) + Entity.InputActions = ACF.GetInputActions(Entity:GetClass()) + end + + local function FindInputName(Entity, Name, Actions) + if not Entity.InputAliases then return Name end + + local Aliases = Entity.InputAliases + local Checked = { [Name] = true } + + repeat + if Actions[Name] then + return Name + end + + Checked[Name] = true + + Name = Aliases[Name] or Name + until + Checked[Name] + + + return Name + end + + function ENT:TriggerInput(Name, Value) + if self.Disabled then return end -- Ignore input if disabled + if not self.InputActions then SetupInputActions(self) end + + local Actions = self.InputActions + local RealName = FindInputName(self, Name, Actions) + local Action = Actions[RealName] + + if Action then + Action(self, Value) + + self:UpdateOverlay() + end + end +end --------------------------------------------- + +do -- Entity user ------------------------------- + -- TODO: Add a function to register more user sources + local WireTable = { + gmod_wire_adv_pod = true, + gmod_wire_joystick = true, + gmod_wire_expression2 = true, + gmod_wire_joystick_multi = true, + gmod_wire_pod = function(_, Input) + if IsValid(Input.Pod) then + return Input.Pod:GetDriver() + end + end, + gmod_wire_keyboard = function(_, Input) + if Input.ply then + return Input.ply + end + end, + } + + local function FindUser(Entity, Input, Checked) + local Function = WireTable[Input:GetClass()] + + return Function and Function(Entity, Input, Checked or {}) + end + + WireTable.gmod_wire_adv_pod = WireTable.gmod_wire_pod + WireTable.gmod_wire_joystick = WireTable.gmod_wire_pod + WireTable.gmod_wire_joystick_multi = WireTable.gmod_wire_pod + WireTable.gmod_wire_expression2 = function(This, Input, Checked) + for _, V in pairs(Input.Inputs) do + if IsValid(V.Src) and not Checked[V.Src] and WireTable[V.Src:GetClass()] then + Checked[V.Src] = true -- We don't want to start an infinite loop + + return FindUser(This, V.Src, Checked) + end + end + end + + function ENT:GetUser(Input) + if not IsValid(Input) then return self.Owner end + + local User = FindUser(self, Input) + + return IsValid(User) and User or self.Owner + end +end --------------------------------------------- diff --git a/lua/entities/acf_base_scalable/shared.lua b/lua/entities/acf_base_scalable/shared.lua new file mode 100644 index 000000000..dbcf1357d --- /dev/null +++ b/lua/entities/acf_base_scalable/shared.lua @@ -0,0 +1,6 @@ +DEFINE_BASECLASS("base_scalable_mconvex") + +ENT.PrintName = "Scalable ACF Base Entity" +ENT.WireDebugName = "Scalable ACF Base Entity" +ENT.PluralName = "Scalable ACF Base Entities" +ENT.IsACFEntity = true \ No newline at end of file diff --git a/lua/entities/acf_base_simple/cl_init.lua b/lua/entities/acf_base_simple/cl_init.lua new file mode 100644 index 000000000..e9f36b206 --- /dev/null +++ b/lua/entities/acf_base_simple/cl_init.lua @@ -0,0 +1,26 @@ +DEFINE_BASECLASS("base_wire_entity") -- Required to get the local BaseClass + +include("shared.lua") + +local HideInfo = ACF.HideInfoBubble + +function ENT:Initialize(...) + BaseClass.Initialize(self, ...) + + self:Update() +end + +function ENT:Update() +end + +-- Copied from base_wire_entity: DoNormalDraw's notip arg isn't accessible from ENT:Draw defined there. +function ENT:Draw() + self:DoNormalDraw(false, HideInfo()) + + Wire_Render(self) + + if self.GetBeamLength and (not self.GetShowBeam or self:GetShowBeam()) then + -- Every SENT that has GetBeamLength should draw a tracer. Some of them have the GetShowBeam boolean + Wire_DrawTracerBeam(self, 1, self.GetBeamHighlight and self:GetBeamHighlight() or false) + end +end diff --git a/lua/entities/acf_base_simple/init.lua b/lua/entities/acf_base_simple/init.lua new file mode 100644 index 000000000..4a78cf274 --- /dev/null +++ b/lua/entities/acf_base_simple/init.lua @@ -0,0 +1,137 @@ +AddCSLuaFile("cl_init.lua") +AddCSLuaFile("shared.lua") + +include("shared.lua") + +local ACF = ACF + +-- You should overwrite these +function ENT:Enable() end +function ENT:Disable() end +function ENT:UpdateOverlay() end + +do -- Entity linking and unlinking -------------- + local LinkText = "%s can't be linked to %s." + local UnlinkText = "%s can't be unlinked from %s." + + function ENT:Link(Target) + if not IsValid(Target) then return false, "Attempted to link an invalid entity." end + if self == Target then return false, "Can't link an entity to itself." end + + local Class = Target:GetClass() + local Function = ACF.GetClassLink(self:GetClass(), Class) + + if Function then + return Function(self, Target) + elseif self.DefaultLink then + return self:DefaultLink(Target) + end + + return false, LinkText:format(self.PluralName, Target.PluralName or Class) + end + + function ENT:Unlink(Target) + if not IsValid(Target) then return false, "Attempted to unlink an invalid entity." end + if self == Target then return false, "Can't unlink an entity from itself." end + + local Class = Target:GetClass() + local Function = ACF.GetClassUnlink(self:GetClass(), Class) + + if Function then + return Function(self, Target) + elseif self.DefaultUnlink then + return self:DefaultUnlink(Target) + end + + return false, UnlinkText:format(self.PluralName, Target.PluralName or Class) + end +end --------------------------------------------- + +do -- Entity inputs ----------------------------- + local function SetupInputActions(Entity) + Entity.InputActions = ACF.GetInputActions(Entity:GetClass()) + end + + local function FindInputName(Entity, Name, Actions) + if not Entity.InputAliases then return Name end + + local Aliases = Entity.InputAliases + local Checked = { [Name] = true } + + repeat + if Actions[Name] then + return Name + end + + Checked[Name] = true + + Name = Aliases[Name] or Name + until + Checked[Name] + + + return Name + end + + function ENT:TriggerInput(Name, Value) + if self.Disabled then return end -- Ignore input if disabled + if not self.InputActions then SetupInputActions(self) end + + local Actions = self.InputActions + local RealName = FindInputName(self, Name, Actions) + local Action = Actions[RealName] + + if Action then + Action(self, Value) + + self:UpdateOverlay() + end + end +end --------------------------------------------- + +do -- Entity user ------------------------------- + -- TODO: Add a function to register more user sources + local WireTable = { + gmod_wire_adv_pod = true, + gmod_wire_joystick = true, + gmod_wire_expression2 = true, + gmod_wire_joystick_multi = true, + gmod_wire_pod = function(_, Input) + if IsValid(Input.Pod) then + return Input.Pod:GetDriver() + end + end, + gmod_wire_keyboard = function(_, Input) + if Input.ply then + return Input.ply + end + end, + } + + local function FindUser(Entity, Input, Checked) + local Function = WireTable[Input:GetClass()] + + return Function and Function(Entity, Input, Checked or {}) + end + + WireTable.gmod_wire_adv_pod = WireTable.gmod_wire_pod + WireTable.gmod_wire_joystick = WireTable.gmod_wire_pod + WireTable.gmod_wire_joystick_multi = WireTable.gmod_wire_pod + WireTable.gmod_wire_expression2 = function(This, Input, Checked) + for _, V in pairs(Input.Inputs) do + if IsValid(V.Src) and not Checked[V.Src] and WireTable[V.Src:GetClass()] then + Checked[V.Src] = true -- We don't want to start an infinite loop + + return FindUser(This, V.Src, Checked) + end + end + end + + function ENT:GetUser(Input) + if not IsValid(Input) then return self.Owner end + + local User = FindUser(self, Input) + + return IsValid(User) and User or self.Owner + end +end --------------------------------------------- diff --git a/lua/entities/acf_base_simple/shared.lua b/lua/entities/acf_base_simple/shared.lua new file mode 100644 index 000000000..7dbeb6874 --- /dev/null +++ b/lua/entities/acf_base_simple/shared.lua @@ -0,0 +1,6 @@ +DEFINE_BASECLASS("base_wire_entity") + +ENT.PrintName = "Simple ACF Base Entity" +ENT.WireDebugName = "Simple ACF Base Entity" +ENT.PluralName = "Simple ACF Base Entities" +ENT.IsACFEntity = true diff --git a/lua/entities/acf_engine/cl_init.lua b/lua/entities/acf_engine/cl_init.lua index 0d4a82fa3..1b41f89ac 100644 --- a/lua/entities/acf_engine/cl_init.lua +++ b/lua/entities/acf_engine/cl_init.lua @@ -1,27 +1,9 @@ include("shared.lua") -local HideInfo = ACF.HideInfoBubble - language.Add("Cleanup_acf_engine", "ACF Engines") language.Add("Cleaned_acf_engine", "Cleaned up all ACF Engines") language.Add("SBoxLimit__acf_engine", "You've reached the ACF Engines limit!") -function ENT:Initialize() - self:Update() -end - function ENT:Update() self.HitBoxes = ACF.HitBoxes[self:GetModel()] end - --- copied from base_wire_entity: DoNormalDraw's notip arg isn't accessible from ENT:Draw defined there. -function ENT:Draw() - self:DoNormalDraw(false, HideInfo()) - - Wire_Render(self) - - if self.GetBeamLength and (not self.GetShowBeam or self:GetShowBeam()) then - -- Every SENT that has GetBeamLength should draw a tracer. Some of them have the GetShowBeam boolean - Wire_DrawTracerBeam(self, 1, self.GetBeamHighlight and self:GetBeamHighlight() or false) - end -end diff --git a/lua/entities/acf_engine/init.lua b/lua/entities/acf_engine/init.lua index 161d45ce0..3a4ac761e 100644 --- a/lua/entities/acf_engine/init.lua +++ b/lua/entities/acf_engine/init.lua @@ -102,11 +102,8 @@ end --===============================================================================================-- local CheckLegal = ACF_CheckLegal -local ClassLink = ACF.GetClassLink -local ClassUnlink = ACF.GetClassUnlink local Engines = ACF.Classes.Engines local EngineTypes = ACF.Classes.EngineTypes -local Inputs = ACF.GetInputActions("acf_engine") local UnlinkSound = "physics/metal/metal_box_impact_bullet%s.wav" local Round = math.Round local max = math.max @@ -547,18 +544,6 @@ ACF.AddInputAction("acf_engine", "Active", function(Entity, Value) SetActive(Entity, tobool(Value)) end) -function ENT:TriggerInput(Name, Value) - if self.Disabled then return end - - local Action = Inputs[Name] - - if Action then - Action(self, Value) - - self:UpdateOverlay() - end -end - function ENT:ACF_Activate() --Density of steel = 7.8g cm3 so 7.8kg for a 1mx1m plate 1m thick local PhysObj = self.ACF.PhysObj @@ -737,32 +722,6 @@ function ENT:CalcRPM() end) end -function ENT:Link(Target) - if not IsValid(Target) then return false, "Attempted to link an invalid entity." end - if self == Target then return false, "Can't link an engine to itself." end - - local Function = ClassLink(self:GetClass(), Target:GetClass()) - - if Function then - return Function(self, Target) - end - - return false, "Engines can't be linked to '" .. Target:GetClass() .. "'." -end - -function ENT:Unlink(Target) - if not IsValid(Target) then return false, "Attempted to unlink an invalid entity." end - if self == Target then return false, "Can't unlink an engine from itself." end - - local Function = ClassUnlink(self:GetClass(), Target:GetClass()) - - if Function then - return Function(self, Target) - end - - return false, "Engines can't be unlinked from '" .. Target:GetClass() .. "'." -end - function ENT:PreEntityCopy() if next(self.Gearboxes) then local Gearboxes = {} diff --git a/lua/entities/acf_engine/shared.lua b/lua/entities/acf_engine/shared.lua index 19cfd17af..51de6b963 100644 --- a/lua/entities/acf_engine/shared.lua +++ b/lua/entities/acf_engine/shared.lua @@ -1,7 +1,8 @@ -DEFINE_BASECLASS("base_wire_entity") +DEFINE_BASECLASS("acf_base_simple") ENT.PrintName = "ACF Engine" ENT.WireDebugName = "ACF Engine" +ENT.PluralName = "ACF Engines" ENT.IsEngine = true cleanup.Register("acf_engine") diff --git a/lua/entities/acf_fueltank/cl_init.lua b/lua/entities/acf_fueltank/cl_init.lua index a9d8ad9d1..f83220761 100644 --- a/lua/entities/acf_fueltank/cl_init.lua +++ b/lua/entities/acf_fueltank/cl_init.lua @@ -1,34 +1,16 @@ include("shared.lua") -local HideInfo = ACF.HideInfoBubble - language.Add("Cleanup_acf_fueltank", "ACF Fuel Tanks") language.Add("Cleaned_acf_fueltank", "Cleaned up all ACF Fuel Tanks") language.Add("SBoxLimit__acf_fueltank", "You've reached the ACF Fuel Tanks limit!") -function ENT:Initialize() - self:Update() -end - function ENT:Update() self.HitBoxes = { Main = { Pos = self:OBBCenter(), Scale = (self:OBBMaxs() - self:OBBMins()) - Vector(2, 2, 2), - Angle = Angle(0, 0, 0), + Angle = Angle(), Sensitive = false } } end - --- copied from base_wire_entity: DoNormalDraw's notip arg isn't accessible from ENT:Draw defined there. -function ENT:Draw() - self:DoNormalDraw(false, HideInfo()) - - Wire_Render(self) - - if self.GetBeamLength and (not self.GetShowBeam or self:GetShowBeam()) then - -- Every SENT that has GetBeamLength should draw a tracer. Some of them have the GetShowBeam boolean - Wire_DrawTracerBeam(self, 1, self.GetBeamHighlight and self:GetBeamHighlight() or false) - end -end diff --git a/lua/entities/acf_fueltank/init.lua b/lua/entities/acf_fueltank/init.lua index 41d7ca13c..f36103534 100644 --- a/lua/entities/acf_fueltank/init.lua +++ b/lua/entities/acf_fueltank/init.lua @@ -8,12 +8,9 @@ include("shared.lua") --===============================================================================================-- local CheckLegal = ACF_CheckLegal -local ClassLink = ACF.GetClassLink -local ClassUnlink = ACF.GetClassUnlink local FuelTanks = ACF.Classes.FuelTanks local FuelTypes = ACF.Classes.FuelTypes local ActiveTanks = ACF.FuelTanks -local Inputs = ACF.GetInputActions("acf_fueltank") local RefillDist = ACF.RefillDistance * ACF.RefillDistance local TimerCreate = timer.Create local TimerExists = timer.Exists @@ -343,32 +340,6 @@ function ENT:Disable() WireLib.TriggerOutput(self, "Activated", 0) end -function ENT:Link(Target) - if not IsValid(Target) then return false, "Attempted to link an invalid entity." end - if self == Target then return false, "Can't link a fuel tank to itself." end - - local Function = ClassLink(self:GetClass(), Target:GetClass()) - - if Function then - return Function(self, Target) - end - - return false, "Fuel tanks can't be linked to '" .. Target:GetClass() .. "'." -end - -function ENT:Unlink(Target) - if not IsValid(Target) then return false, "Attempted to unlink an invalid entity." end - if self == Target then return false, "Can't unlink a fuel tank from itself." end - - local Function = ClassUnlink(self:GetClass(), Target:GetClass()) - - if Function then - return Function(self, Target) - end - - return false, "Fuel tanks can't be unlinked from '" .. Target:GetClass() .. "'." -end - do -- Mass Update local function UpdateMass(Entity) local Fuel = Entity.FuelType == "Electric" and Entity.Liters or Entity.Fuel @@ -463,18 +434,6 @@ ACF.AddInputAction("acf_fueltank", "Refuel Duty", function(Entity, Value) Entity.SupplyFuel = tobool(Value) or nil end) -function ENT:TriggerInput(Name, Value) - if self.Disabled then return end - - local Action = Inputs[Name] - - if Action then - Action(self, Value) - - self:UpdateOverlay() - end -end - function ENT:CanConsume() if self.Disabled then return false end if not self.Active then return false end diff --git a/lua/entities/acf_fueltank/shared.lua b/lua/entities/acf_fueltank/shared.lua index 37b646ffd..42d3e1d18 100644 --- a/lua/entities/acf_fueltank/shared.lua +++ b/lua/entities/acf_fueltank/shared.lua @@ -1,7 +1,8 @@ -DEFINE_BASECLASS("base_wire_entity") +DEFINE_BASECLASS("acf_base_simple") ENT.PrintName = "ACF Fuel Tank" ENT.WireDebugName = "ACF Fuel Tank" +ENT.PluralName = "ACF Fuel Tanks" ENT.IsFuelTank = true cleanup.Register("acf_fueltank") diff --git a/lua/entities/acf_gearbox/cl_init.lua b/lua/entities/acf_gearbox/cl_init.lua index 195cbd5ba..1de0c1e1c 100644 --- a/lua/entities/acf_gearbox/cl_init.lua +++ b/lua/entities/acf_gearbox/cl_init.lua @@ -1,27 +1,9 @@ include("shared.lua") -local HideInfo = ACF.HideInfoBubble - language.Add("Cleanup_acf_gearbox", "ACF Gearboxes") language.Add("Cleaned_acf_gearbox", "Cleaned up all ACF Gearboxes") language.Add("SBoxLimit__acf_gearbox", "You've reached the ACF Gearboxes limit!") -function ENT:Initialize() - self:Update() -end - function ENT:Update() self.HitBoxes = ACF.HitBoxes[self:GetModel()] end - --- copied from base_wire_entity: DoNormalDraw's notip arg isn't accessible from ENT:Draw defined there. -function ENT:Draw() - self:DoNormalDraw(false, HideInfo()) - - Wire_Render(self) - - if self.GetBeamLength and (not self.GetShowBeam or self:GetShowBeam()) then - -- Every SENT that has GetBeamLength should draw a tracer. Some of them have the GetShowBeam boolean - Wire_DrawTracerBeam(self, 1, self.GetBeamHighlight and self:GetBeamHighlight() or false) - end -end diff --git a/lua/entities/acf_gearbox/init.lua b/lua/entities/acf_gearbox/init.lua index 22b4f8c60..963dc45ea 100644 --- a/lua/entities/acf_gearbox/init.lua +++ b/lua/entities/acf_gearbox/init.lua @@ -150,10 +150,7 @@ ACF.RegisterClassUnlink("acf_gearbox", "acf_gearbox", UnlinkGearbox) ACF.RegisterClassUnlink("acf_gearbox", "tire", UnlinkWheel) local CheckLegal = ACF_CheckLegal -local ClassLink = ACF.GetClassLink -local ClassUnlink = ACF.GetClassUnlink local Gearboxes = ACF.Classes.Gearboxes -local Inputs = ACF.GetInputActions("acf_gearbox") local Clamp = math.Clamp local HookRun = hook.Run @@ -770,18 +767,6 @@ ACF.AddInputAction("acf_gearbox", "Shift Speed Scale", function(Entity, Value) Entity.ShiftScale = Clamp(Value, 0.1, 1.5) end) -function ENT:TriggerInput(Name, Value) - if self.Disabled then return end - - local Action = Inputs[Name] - - if Action then - Action(self, Value) - - self:UpdateOverlay() - end -end - -- Handles gearing for automatic gearboxes. 0 = Neutral, 1 = Drive, 2 = Reverse function ENT:ChangeDrive(Value) Value = Clamp(math.floor(Value), 0, 2) @@ -962,32 +947,6 @@ function ENT:Act(Torque, DeltaTime, MassRatio) self.LastActive = ACF.CurTime end -function ENT:Link(Target) - if not IsValid(Target) then return false, "Attempted to link an invalid entity." end - if self == Target then return false, "Can't link a gearbox to itself." end - - local Function = ClassLink(self:GetClass(), Target:GetClass()) - - if Function then - return Function(self, Target) - end - - return false, "Gearboxes can't be linked to '" .. Target:GetClass() .. "'." -end - -function ENT:Unlink(Target) - if not IsValid(Target) then return false, "Attempted to unlink an invalid entity." end - if self == Target then return false, "Can't unlink a gearbox from itself." end - - local Function = ClassUnlink(self:GetClass(), Target:GetClass()) - - if Function then - return Function(self, Target) - end - - return false, "Gearboxes can't be unlinked from '" .. Target:GetClass() .. "'." -end - function ENT:PreEntityCopy() if next(self.Wheels) then local Wheels = {} diff --git a/lua/entities/acf_gearbox/shared.lua b/lua/entities/acf_gearbox/shared.lua index ba05fc25e..a8d0d4aae 100644 --- a/lua/entities/acf_gearbox/shared.lua +++ b/lua/entities/acf_gearbox/shared.lua @@ -1,7 +1,8 @@ -DEFINE_BASECLASS("base_wire_entity") +DEFINE_BASECLASS("acf_base_simple") ENT.PrintName = "ACF Gearbox" ENT.WireDebugName = "ACF Gearbox" +ENT.PluralName = "ACF Gearboxes" ENT.IsGearbox = true cleanup.Register("acf_gearbox") diff --git a/lua/entities/acf_gun/cl_init.lua b/lua/entities/acf_gun/cl_init.lua index f681dd4b6..cd4305e5b 100644 --- a/lua/entities/acf_gun/cl_init.lua +++ b/lua/entities/acf_gun/cl_init.lua @@ -1,6 +1,6 @@ -include("shared.lua") +DEFINE_BASECLASS("acf_base_simple") -- Required to get the local BaseClass -local HideInfo = ACF.HideInfoBubble +include("shared.lua") language.Add("Cleanup_acf_gun", "ACF Weapons") language.Add("Cleaned_acf_gun", "Cleaned up all ACF Weapons") @@ -9,7 +9,7 @@ language.Add("SBoxLimit__acf_gun", "You've reached the ACF Weapons limit!") language.Add("Cleaned_acf_smokelauncher", "Cleaned up all ACF Smoke Launchers") language.Add("SBoxLimit__acf_smokelauncher", "You've reached the ACF Smoke Launcher limit!") -function ENT:Initialize() +function ENT:Initialize(...) self.LastFire = 0 self.Reload = 0 self.CloseTime = 0 @@ -18,35 +18,21 @@ function ENT:Initialize() self.FireAnim = self:LookupSequence("shoot") self.CloseAnim = self:LookupSequence("load") - self:Update() - - self.BaseClass.Initialize(self) + BaseClass.Initialize(self, ...) end function ENT:Update() self.HitBoxes = ACF.HitBoxes[self:GetModel()] end --- copied from base_wire_entity: DoNormalDraw's notip arg isn't accessible from ENT:Draw defined there. -function ENT:Draw() - self:DoNormalDraw(false, HideInfo()) - - Wire_Render(self) - - if self.GetBeamLength and (not self.GetShowBeam or self:GetShowBeam()) then - -- Every SENT that has GetBeamLength should draw a tracer. Some of them have the GetShowBeam boolean - Wire_DrawTracerBeam(self, 1, self.GetBeamHighlight and self:GetBeamHighlight() or false) - end -end - function ENT:Think() - self.BaseClass.Think(self) + BaseClass.Think(self) - local SinceFire = CurTime() - self.LastFire + local SinceFire = ACF.CurTime - self.LastFire self:SetCycle(SinceFire * self.Rate / self.RateScale) - if CurTime() > self.LastFire + self.CloseTime and self.CloseAnim then + if ACF.CurTime > self.LastFire + self.CloseTime and self.CloseAnim then self:ResetSequence(self.CloseAnim) self:SetCycle((SinceFire - self.CloseTime) * self.Rate / self.RateScale) self.Rate = 1 / (self.Reload - self.CloseTime) -- Base anim time is 1s, rate is in 1/10 of a second @@ -73,6 +59,6 @@ function ENT:Animate(ReloadTime, LoadOnly) end self:SetPlaybackRate(self.Rate) - self.LastFire = CurTime() + self.LastFire = ACF.CurTime self.Reload = ReloadTime end diff --git a/lua/entities/acf_gun/init.lua b/lua/entities/acf_gun/init.lua index 9f472dbef..39d107734 100644 --- a/lua/entities/acf_gun/init.lua +++ b/lua/entities/acf_gun/init.lua @@ -13,7 +13,6 @@ local Shove = ACF.KEShove local Overpressure = ACF.Overpressure local Weapons = ACF.Classes.Weapons local AmmoTypes = ACF.Classes.AmmoTypes -local Inputs = ACF.GetInputActions("acf_gun") local TraceRes = {} -- Output for traces local TraceData = {start = true, endpos = true, filter = true, mask = MASK_SOLID, output = TraceRes} local Trace = util.TraceLine @@ -284,9 +283,6 @@ end --------------------------------------------- do -- Metamethods -------------------------------- do -- Inputs/Outputs/Linking ---------------- - local ClassLink = ACF.GetClassLink - local ClassUnlink = ACF.GetClassUnlink - WireLib.AddOutputAlias("AmmoCount", "Total Ammo") WireLib.AddOutputAlias("Muzzle Weight", "Projectile Mass") @@ -337,50 +333,6 @@ do -- Metamethods -------------------------------- return false, "This weapon is not linked to this crate." end) - local WireTable = { - gmod_wire_adv_pod = true, - gmod_wire_joystick = true, - gmod_wire_expression2 = true, - gmod_wire_joystick_multi = true, - gmod_wire_pod = function(_, Input) - if IsValid(Input.Pod) then - return Input.Pod:GetDriver() - end - end, - gmod_wire_keyboard = function(_, Input) - if Input.ply then - return Input.ply - end - end, - } - - local function FindUser(Entity, Input, Checked) - local Function = WireTable[Input:GetClass()] - - return Function and Function(Entity, Input, Checked or {}) - end - - WireTable.gmod_wire_adv_pod = WireTable.gmod_wire_pod - WireTable.gmod_wire_joystick = WireTable.gmod_wire_pod - WireTable.gmod_wire_joystick_multi = WireTable.gmod_wire_pod - WireTable.gmod_wire_expression2 = function(This, Input, Checked) - for _, V in pairs(Input.Inputs) do - if IsValid(V.Src) and not Checked[V.Src] and WireTable[V.Src:GetClass()] then - Checked[V.Src] = true -- We don't want to start an infinite loop - - return FindUser(This, V.Src, Checked) - end - end - end - - function ENT:GetUser(Input) - if not IsValid(Input) then return self.Owner end - - local User = FindUser(self, Input) - - return IsValid(User) and User or self.Owner - end - ACF.AddInputAction("acf_gun", "Fire", function(Entity, Value) local Bool = tobool(Value) @@ -410,44 +362,6 @@ do -- Metamethods -------------------------------- ACF.AddInputAction("acf_gun", "Fuze", function(Entity, Value) Entity.SetFuze = tobool(Value) and math.abs(Value) end) - - function ENT:TriggerInput(Name, Value) - if self.Disabled then return end - - local Action = Inputs[Name] - - if Action then - Action(self, Value) - - self:UpdateOverlay() - end - end - - function ENT:Link(Target) - if not IsValid(Target) then return false, "Attempted to link an invalid entity." end - if self == Target then return false, "Can't link a weapon to itself." end - - local Function = ClassLink(self:GetClass(), Target:GetClass()) - - if Function then - return Function(self, Target) - end - - return false, "Guns can't be linked to '" .. Target:GetClass() .. "'." - end - - function ENT:Unlink(Target) - if not IsValid(Target) then return false, "Attempted to unlink an invalid entity." end - if self == Target then return false, "Can't unlink a weapon from itself." end - - local Function = ClassUnlink(self:GetClass(), Target:GetClass()) - - if Function then - return Function(self, Target) - end - - return false, "Guns can't be unlinked from '" .. Target:GetClass() .. "'." - end end ----------------------------------------- do -- Shooting ------------------------------ diff --git a/lua/entities/acf_gun/shared.lua b/lua/entities/acf_gun/shared.lua index 1c309d426..071fd82cd 100644 --- a/lua/entities/acf_gun/shared.lua +++ b/lua/entities/acf_gun/shared.lua @@ -1,7 +1,8 @@ -DEFINE_BASECLASS("base_wire_entity") +DEFINE_BASECLASS("acf_base_simple") -ENT.PrintName = "ACF Gun" -ENT.WireDebugName = "ACF Gun" +ENT.PrintName = "ACF Weapon" +ENT.WireDebugName = "ACF Weapon" +ENT.PluralName = "ACF Weapons" ENT.IsWeapon = true cleanup.Register("acf_gun") From 2e6e5830c93e94a91bfb8e08252f70c634a481c4 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Mon, 14 Dec 2020 02:57:42 -0300 Subject: [PATCH 218/279] Updated double Active trigger input on E2/SFEx - Updated e:acfActive(n) E2 function and ENT:acfSetActive() SFEx function to not call the Load input on entities, since this will be dealt by the TriggerInput function itself. --- lua/entities/gmod_wire_expression2/core/custom/acffunctions.lua | 2 -- lua/starfall/libs_sv/acffunctions.lua | 2 -- 2 files changed, 4 deletions(-) diff --git a/lua/entities/gmod_wire_expression2/core/custom/acffunctions.lua b/lua/entities/gmod_wire_expression2/core/custom/acffunctions.lua index 257a0eccf..5a7a97914 100644 --- a/lua/entities/gmod_wire_expression2/core/custom/acffunctions.lua +++ b/lua/entities/gmod_wire_expression2/core/custom/acffunctions.lua @@ -202,8 +202,6 @@ e2function void entity:acfActive(number On) if not IsACFEntity(this) then return end if not isOwner(self, this) then return end - -- Both have the same function on different entities - this:TriggerInput("Load", On) this:TriggerInput("Active", On) end diff --git a/lua/starfall/libs_sv/acffunctions.lua b/lua/starfall/libs_sv/acffunctions.lua index 7e933cc16..7c2516479 100644 --- a/lua/starfall/libs_sv/acffunctions.lua +++ b/lua/starfall/libs_sv/acffunctions.lua @@ -854,8 +854,6 @@ function ents_methods:acfSetActive(on) CheckPerms(instance, This, "entities.acf") - -- Both have the same function on different entities - This:TriggerInput("Load", on) This:TriggerInput("Active", on) end From 5e374da2d738db3503f21bede357089dc70b0b4c Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Wed, 16 Dec 2020 04:34:17 -0300 Subject: [PATCH 219/279] Renamed tool data vars to client data vars - Tool data vars have been renamed to client data vars, due to the old name being misleading to all the purposes they can be given. - ACF.GetToolData has been renamed to ACF.GetAllClientData, along with receiving an option argument which, if set, will make it so the function returns the real client data values instead of a copy of them. - Renamed ACF.ReadBool to ACF.GetClientBool. - Renamed ACF.ReadNumber to ACF.GetClientNumber. - Renamed ACF.ReadString to ACF.GetClientString. - Renamed ACF.ReadData to ACF.GetClientData. - Renamed ACF.ReadRaw to ACF.GetClientRaw. - Renamed ACF.WriteValue to ACF.SetClientData. - Renamed OnToolDataUpdate hook to ACF_OnClientDataUpdate. It'll also receive the local player as the first argument on the clientside. - Removed unused ACF.AmmoTypes table from globals. --- lua/acf/base/acf_globals.lua | 3 +- lua/acf/base/data_vars/cl_data_vars.lua | 276 ++++++++++++++++++ lua/acf/base/data_vars/sv_data_vars.lua | 88 ++++++ lua/acf/base/sh_tool_functions.lua | 6 +- lua/acf/base/util/cl_util.lua | 259 ---------------- lua/acf/base/util/sv_util.lua | 73 ----- lua/acf/client/cl_ammo_menu.lua | 26 +- lua/acf/client/cl_spawn_menu.lua | 2 +- lua/acf/client/menu_items/components_menu.lua | 8 +- lua/acf/client/menu_items/engines_menu.lua | 12 +- lua/acf/client/menu_items/gearboxes_menu.lua | 48 +-- lua/acf/client/menu_items/sensors_menu.lua | 8 +- lua/acf/client/menu_items/weapons_menu.lua | 10 +- lua/acf/shared/ammo_types/aphe.lua | 2 +- lua/acf/shared/ammo_types/fl.lua | 4 +- lua/acf/shared/ammo_types/heat.lua | 4 +- lua/acf/shared/ammo_types/hp.lua | 2 +- lua/acf/shared/ammo_types/smoke.lua | 4 +- lua/acf/shared/tool_operations/acf_menu.lua | 13 +- 19 files changed, 440 insertions(+), 408 deletions(-) create mode 100644 lua/acf/base/data_vars/cl_data_vars.lua create mode 100644 lua/acf/base/data_vars/sv_data_vars.lua diff --git a/lua/acf/base/acf_globals.lua b/lua/acf/base/acf_globals.lua index 0e6ba5d86..f79df3aec 100644 --- a/lua/acf/base/acf_globals.lua +++ b/lua/acf/base/acf_globals.lua @@ -1,9 +1,10 @@ do -- ACF global vars - ACF.AmmoTypes = ACF.AmmoTypes or {} ACF.AmmoCrates = ACF.AmmoCrates or {} ACF.Classes = ACF.Classes or {} ACF.FuelTanks = ACF.FuelTanks or {} ACF.Repositories = ACF.Repositories or {} + ACF.ClientData = ACF.ClientData or {} + ACF.ServerData = ACF.ServerData or {} -- Misc ACF.Year = 1945 diff --git a/lua/acf/base/data_vars/cl_data_vars.lua b/lua/acf/base/data_vars/cl_data_vars.lua new file mode 100644 index 000000000..f8d318d2c --- /dev/null +++ b/lua/acf/base/data_vars/cl_data_vars.lua @@ -0,0 +1,276 @@ +local ACF = ACF +local Client = ACF.ClientData +local Server = ACF.ServerData +local Queued = { Client = {}, Server = {} } +local LastSent = { Client = {}, Server = {} } + +local function PrepareQueue(Type, Values, Result) + local Queue = Queued[Type] + + if not next(Queue) then return end + + local Sent = LastSent[Type] + local Data = {} + + for K in pairs(Queue) do + local Value = Values[K] + + if Value ~= Sent[K] then + Data[K] = Value + end + + Queue[K] = nil + end + + Result[Type] = Data +end + +local function SendQueued() + local Result = {} + + PrepareQueue("Client", Client, Result) + PrepareQueue("Server", Server, Result) + + if next(Result) then + local JSON = util.TableToJSON(Result) + + net.Start("ACF_DataVarNetwork") + net.WriteString(JSON) + net.SendToServer() + end +end + +local function NetworkData(Key, IsServer) + local Type = IsServer and "Server" or "Client" + local Destiny = Queued[Type] + + if Destiny[Key] then return end -- Already queued + + Destiny[Key] = true + + -- Avoiding net message spam by sending all the events of a tick at once + if timer.Exists("ACF Network Data Vars") then return end + + timer.Create("ACF Network Data Vars", 0, 1, SendQueued) +end + +do -- Client data retrieval functions + local function GetData(Key, Default) + if Key == nil then return Default end + + local Value = Client[Key] + + if Value ~= nil then return Value end + + return Default + end + + function ACF.GetAllClientData(NoCopy) + if NoCopy then return Client end + + local Result = {} + + for K, V in pairs(Client) do + Result[K] = V + end + + return Result + end + + function ACF.GetClientBool(Key, Default) + return tobool(GetData(Key, Default)) + end + + function ACF.GetClientNumber(Key, Default) + local Value = GetData(Key, Default) + + return ACF.CheckNumber(Value, 0) + end + + function ACF.GetClientString(Key, Default) + local Value = GetData(Key, Default) + + return ACF.CheckString(Value, "") + end + + ACF.GetClientData = GetData + ACF.GetClientRaw = GetData +end + +do -- Write function + function ACF.SetClientData(Key, Value) + if not isstring(Key) then return end + + Value = Value or false + + if Client[Key] ~= Value then + Client[Key] = Value + + hook.Run("ACF_OnClientDataUpdate", LocalPlayer(), Key, Value) + + NetworkData(Key) + end + end +end + +do -- Panel functions + local PANEL = FindMetaTable("Panel") + local Trackers = {} + local Setters = {} + local Variables = { + Trackers = {}, + Setters = {}, + } + + local function AddVariable(Panel, Key, Target) + local Data = Target[Key] + + if not Data then + Target[Key] = { + [Panel] = true + } + else + Data[Panel] = true + end + end + + local function AddTracker(Panel, Key) + local Data = Trackers[Panel] + + if not Data then + Trackers[Panel] = { + [Key] = true + } + else + Data[Key] = true + end + + AddVariable(Panel, Key, Variables.Trackers) + end + + local function AddSetter(Panel, Key) + local Data = Setters[Panel] + + if not Data then + Setters[Panel] = { + [Key] = true + } + else + Data[Key] = true + end + + AddVariable(Panel, Key, Variables.Setters) + end + + local function ClearVariables(Panel) + if Trackers[Panel] then + for K in pairs(Trackers[Panel]) do + Variables.Trackers[K][Panel] = nil + end + + Trackers[Panel] = nil + end + + if Setters[Panel] then + for K in pairs(Setters[Panel]) do + Variables.Setters[K][Panel] = nil + end + + Setters[Panel] = nil + end + end + + local function LoadFunctions(Panel) + if not Panel.LegacyRemove then + Panel.LegacyRemove = Panel.Remove + + function Panel:Remove() + ClearVariables(self) + + self:LegacyRemove() + end + end + + if Panel.Hijack and Panel.Hijack ~= Panel.PrevHijack then + if Panel.PrevHijack then + Panel[Panel.PrevHijack] = Panel.OldSetFunc + end + + Panel.PrevHijack = Panel.Hijack + Panel.OldSetFunc = Panel[Panel.Hijack] + + function Panel:NewSetFunc(Value) + if self.DataVar then + ACF.SetClientData(self.DataVar, Value) + return + end + + self:OldSetFunc(Value) + end + + Panel[Panel.Hijack] = Panel.NewSetFunc + end + end + + function PANEL:SetDataVar(Key, Function) + if not Key then return end + + self.DataVar = Key + self.Hijack = Function or self.Hijack or "SetValue" + + AddSetter(self, Key) + LoadFunctions(self) + + if not Client[Key] then + ACF.SetClientData(Key, self:GetValue()) + end + end + + function PANEL:TrackDataVar(Key, Function) + self.Hijack = Function or self.Hijack or "SetValue" + + AddTracker(self, Key) + LoadFunctions(self) + end + + function PANEL:SetValueFunction(Function) + if not isfunction(Function) then return end + + LoadFunctions(self) + + self.ValueFunction = Function + + if self.Hijack then + self:NewSetFunc(self:ValueFunction()) + end + end + + hook.Add("ACF_OnClientDataUpdate", "ACF Update Panel Values", function(_, Key, Value) + local TrackerPanels = Variables.Trackers[Key] + local SetterPanels = Variables.Setters[Key] + + -- First we'll process the panels that set the value of this key + if SetterPanels then + for Panel in pairs(SetterPanels) do + if not Panel.OldSetFunc then continue end + + local NewValue = Value + + if Panel.ValueFunction then + NewValue = Panel:ValueFunction() + end + + Panel:OldSetFunc(NewValue) + end + end + + -- Then we'll process the panels that just keep track of this value + if TrackerPanels then + for Panel in pairs(TrackerPanels) do + if not Panel.ValueFunction then continue end + + Panel:OldSetFunc(Panel:ValueFunction(true)) + end + end + end) +end diff --git a/lua/acf/base/data_vars/sv_data_vars.lua b/lua/acf/base/data_vars/sv_data_vars.lua new file mode 100644 index 000000000..200574811 --- /dev/null +++ b/lua/acf/base/data_vars/sv_data_vars.lua @@ -0,0 +1,88 @@ +local ACF = ACF +local Client = ACF.ClientData + +do -- Data syncronization + util.AddNetworkString("ACF_DataVarNetwork") + + local function ProcessData(Player, Type, Values, Received) + local Data = Received[Type] + + if not Data then return end + + local Hook = "ACF_On" .. Type .. "DataUpdate" + + for K, V in pairs(Data) do + Values[K] = V + Data[K] = nil + + hook.Run(Hook, Player, K, V) + end + end + + net.Receive("ACF_DataVarNetwork", function(_, Player) + local Received = util.JSONToTable(net.ReadString()) + + if IsValid(Player) then + ProcessData(Player, "Client", Client[Player], Received) + end + end) + + hook.Add("PlayerInitialSpawn", "ACF Client Data", function(Player) + Client[Player] = {} + end) + + hook.Add("PlayerDisconnected", "ACF Client Data", function(Player) + Client[Player] = nil + end) +end + +do -- Read functions + local function GetData(Player, Key, Default) + if not IsValid(Player) then return Default end + if Key == nil then return Default end + + local Data = Client[Player] + local Value = Data and Data[Key] + + if Value ~= nil then return Value end + + return Default + end + + function ACF.GetAllClientData(Player, NoCopy) + if not IsValid(Player) then return {} end + + local Data = Client[Player] + + if NoCopy then return Data or {} end + + local Result = {} + + if Data then + for K, V in pairs(Data) do + Result[K] = V + end + end + + return Result + end + + function ACF.GetClientBool(Player, Key, Default) + return tobool(GetData(Player, Key, Default)) + end + + function ACF.GetClientNumber(Player, Key, Default) + local Value = GetData(Player, Key, Default) + + return ACF.CheckNumber(Value, 0) + end + + function ACF.GetClientString(Player, Key, Default) + local Value = GetData(Player, Key, Default) + + return ACF.CheckString(Value, "") + end + + ACF.GetClientData = GetData + ACF.GetClientRaw = GetData +end diff --git a/lua/acf/base/sh_tool_functions.lua b/lua/acf/base/sh_tool_functions.lua index 5e8796434..b9db0e5e8 100644 --- a/lua/acf/base/sh_tool_functions.lua +++ b/lua/acf/base/sh_tool_functions.lua @@ -268,7 +268,7 @@ do -- Tool Functions Loader end function Tool:RestoreMode() - local ToolMode = ACF.ReadString(self:GetOwner(), "ToolMode:" .. self.Mode) + local ToolMode = ACF.GetClientString(self:GetOwner(), "ToolMode:" .. self.Mode) if ToolMode then local Stage, Op = unpack(string.Explode(":", ToolMode), 1, 2) @@ -350,7 +350,7 @@ end do -- Clientside Tool interaction if SERVER then - hook.Add("OnToolDataUpdate", "ACF ToolMode", function(Player, Key, Value) + hook.Add("ACF_OnClientDataUpdate", "ACF ToolMode", function(Player, Key, Value) local Header, Name = unpack(string.Explode(":", Key), 1, 2) if Header ~= "ToolMode" then return end @@ -373,7 +373,7 @@ do -- Clientside Tool interaction if not isstring(Stage) then return end if not isstring(Op) then return end - ACF.WriteValue(Key:format(Tool), Value:format(Stage, Op)) + ACF.SetClientData(Key:format(Tool), Value:format(Stage, Op)) end end end diff --git a/lua/acf/base/util/cl_util.lua b/lua/acf/base/util/cl_util.lua index 8c8e1736f..9a9d6d7ea 100644 --- a/lua/acf/base/util/cl_util.lua +++ b/lua/acf/base/util/cl_util.lua @@ -69,265 +69,6 @@ do -- Custom fonts }) end -do -- Tool data functions - local ToolData = {} - - do -- Read functions - function ACF.GetToolData() - local Result = {} - - for K, V in pairs(ToolData) do - Result[K] = V - end - - return Result - end - - local function ReadData(Key, Default) - if Key == nil then return end - - local Value = ToolData[Key] - - if Value ~= nil then return Value end - - return Default - end - - function ACF.ReadBool(Key, Default) - return tobool(ReadData(Key, Default)) - end - - function ACF.ReadNumber(Key, Default) - local Value = ReadData(Key, Default) - - return ACF.CheckNumber(Value, 0) - end - - function ACF.ReadString(Key) - local Value = ReadData(Key, Default) - - return ACF.CheckString(Value, "") - end - - ACF.ReadData = ReadData - ACF.ReadRaw = ReadData - end - - do -- Write function - local LastSent = {} - - function ACF.WriteValue(Key, Value) - if not isstring(Key) then return end - if ToolData[Key] == Value then return end - - ToolData[Key] = Value - - hook.Run("OnToolDataUpdate", Key, Value) - - -- TODO: Replace with a queue system similar to the one used by the scalable base - -- Allowing one network message per key per tick - if timer.Exists("ACF WriteValue " .. Key) then return end - - timer.Create("ACF WriteValue " .. Key, 0, 1, function() - local NewValue = ToolData[Key] - - -- Preventing network message spam if value hasn't really changed - if LastSent[Key] == NewValue then return end - - LastSent[Key] = NewValue - - net.Start("ACF_ToolData") - net.WriteString(Key) - net.WriteType(NewValue) - net.SendToServer() - end) - end - end - - do -- Panel functions - local PANEL = FindMetaTable("Panel") - local Trackers = {} - local Setters = {} - local Variables = { - Trackers = {}, - Setters = {}, - } - - local function AddVariable(Panel, Key, Target) - local Data = Variables[Target] - local VData = Data[Key] - - if not VData then - Data[Key] = { - [Panel] = true - } - else - VData[Panel] = true - end - end - - local function AddTracker(Panel, Key) - local Data = Trackers[Panel] - - if not Data then - Trackers[Panel] = { - [Key] = true - } - else - Data[Key] = true - end - - AddVariable(Panel, Key, "Trackers") - end - - local function AddSetter(Panel, Key) - local Data = Setters[Panel] - - if not Data then - Setters[Panel] = { - [Key] = true - } - else - Data[Key] = true - end - - AddVariable(Panel, Key, "Setters") - end - - local function ClearVariables(Panel) - if Trackers[Panel] then - for K in pairs(Trackers[Panel]) do - Variables.Trackers[K][Panel] = nil - end - - Trackers[Panel] = nil - end - - if Setters[Panel] then - for K in pairs(Setters[Panel]) do - Variables.Setters[K][Panel] = nil - end - - Setters[Panel] = nil - end - end - - local function LoadFunctions(Panel) - if not Panel.LegacyRemove then - Panel.LegacyRemove = Panel.Remove - - function Panel:Remove() - ClearVariables(self) - - self:LegacyRemove() - end - end - - if Panel.Hijack and Panel.Hijack ~= Panel.PrevHijack then - if Panel.PrevHijack then - Panel[Panel.PrevHijack] = Panel.OldSetFunc - end - - Panel.PrevHijack = Panel.Hijack - Panel.OldSetFunc = Panel[Panel.Hijack] - - function Panel:NewSetFunc(Value) - if self.DataVar then - ACF.WriteValue(self.DataVar, Value) - return - end - - self:OldSetFunc(Value) - end - - Panel[Panel.Hijack] = Panel.NewSetFunc - end - end - - function PANEL:SetDataVar(Key, Function) - if not Key then return end - - self.DataVar = Key - self.Hijack = Function or self.Hijack or "SetValue" - - AddSetter(self, Key) - LoadFunctions(self) - - if not ToolData[Key] then - ACF.WriteValue(Key, self:GetValue()) - end - end - - function PANEL:TrackDataVar(Key, Function) - self.Hijack = Function or self.Hijack or "SetValue" - - AddTracker(self, Key) - LoadFunctions(self) - end - - function PANEL:SetValueFunction(Function) - if not isfunction(Function) then return end - - LoadFunctions(self) - - self.ValueFunction = Function - - if self.Hijack then - self:NewSetFunc(self:ValueFunction()) - end - end - - function PANEL:ClearDataVars() - if self.LegacyRemove then - self.Remove = self.LegacyRemove - self.LegacyRemove = nil - end - - if self.Hijack then - self[self.Hijack] = self.OldSetFunc - self.OldSetFunc = nil - self.NewSetFunc = nil - self.PrevHijack = nil - self.Hijack = nil - end - - self.ValueFunction = nil - self.DataVar = nil - - ClearVariables(self) - end - - hook.Add("OnToolDataUpdate", "ACF Update Panel Values", function(Key, Value) - local TrackerPanels = Variables.Trackers[Key] - local SetterPanels = Variables.Setters[Key] - - -- First we'll process the panels that set the value of this key - if SetterPanels then - for Panel in pairs(SetterPanels) do - if not Panel.OldSetFunc then continue end - - local NewValue = Value - - if Panel.ValueFunction then - NewValue = Panel:ValueFunction() - end - - Panel:OldSetFunc(NewValue) - end - end - - -- Then we'll process the panels that just keep track of this value - if TrackerPanels then - for Panel in pairs(TrackerPanels) do - if not Panel.ValueFunction then continue end - - Panel:OldSetFunc(Panel:ValueFunction(true)) - end - end - end) - end -end - do -- Clientside visclip check local function CheckClip(Entity, Clip, Center, Pos) if Clip.physics then return false end -- Physical clips will be ignored, we can't hit them anyway diff --git a/lua/acf/base/util/sv_util.lua b/lua/acf/base/util/sv_util.lua index e6949a11d..b5ea83b0e 100644 --- a/lua/acf/base/util/sv_util.lua +++ b/lua/acf/base/util/sv_util.lua @@ -59,79 +59,6 @@ do -- Clientside message delivery end end -do -- Tool data functions - local ToolData = {} - - do -- Data syncronization - util.AddNetworkString("ACF_ToolData") - - net.Receive("ACF_ToolData", function(_, Player) - if not IsValid(Player) then return end - - local Key = net.ReadString() - local Value = net.ReadType() - - ToolData[Player][Key] = Value - - hook.Run("OnToolDataUpdate", Player, Key, Value) - end) - - hook.Add("PlayerInitialSpawn", "ACF Tool Data", function(Player) - ToolData[Player] = {} - end) - - hook.Add("PlayerDisconnected", "ACF Tool Data", function(Player) - ToolData[Player] = nil - end) - end - - do -- Read functions - function ACF.GetToolData(Player) - if not IsValid(Player) then return {} end - if not ToolData[Player] then return {} end - - local Result = {} - - for K, V in pairs(ToolData[Player]) do - Result[K] = V - end - - return Result - end - - local function ReadData(Player, Key, Default) - if not IsValid(Player) then return end - if not ToolData[Player] then return end - if Key == nil then return end - - local Value = ToolData[Player][Key] - - if Value ~= nil then return Value end - - return Default - end - - function ACF.ReadBool(Player, Key, Default) - return tobool(ReadData(Player, Key, Default)) - end - - function ACF.ReadNumber(Player, Key, Default) - local Value = ReadData(Player, Key, Default) - - return ACF.CheckNumber(Value, 0) - end - - function ACF.ReadString(Player, Key, Default) - local Value = ReadData(Player, Key, Default) - - return ACF.CheckString(Value, "") - end - - ACF.ReadData = ReadData - ACF.ReadRaw = ReadData - end -end - do -- Entity saving and restoring local Constraints = duplicator.ConstraintType local Saved = {} diff --git a/lua/acf/client/cl_ammo_menu.lua b/lua/acf/client/cl_ammo_menu.lua index cbab3d810..f9b0fd10c 100644 --- a/lua/acf/client/cl_ammo_menu.lua +++ b/lua/acf/client/cl_ammo_menu.lua @@ -61,7 +61,7 @@ local function AddControls(Base, Settings, ToolData) local Projectile = Base:AddSlider("Projectile Length", 0, BulletData.MaxRoundLength, 2) Projectile:SetDataVar("Projectile", "OnValueChanged") Projectile:SetValueFunction(function(Panel, IsTracked) - ToolData.Projectile = ACF.ReadNumber("Projectile") + ToolData.Projectile = ACF.GetClientNumber("Projectile") if not IsTracked then BulletData.Priority = "Projectile" @@ -69,7 +69,7 @@ local function AddControls(Base, Settings, ToolData) Ammo:UpdateRoundData(ToolData, BulletData) - ACF.WriteValue("Propellant", BulletData.PropLength) + ACF.SetClientData("Propellant", BulletData.PropLength) Panel:SetValue(BulletData.ProjLength) @@ -79,7 +79,7 @@ local function AddControls(Base, Settings, ToolData) local Propellant = Base:AddSlider("Propellant Length", 0, BulletData.MaxRoundLength, 2) Propellant:SetDataVar("Propellant", "OnValueChanged") Propellant:SetValueFunction(function(Panel, IsTracked) - ToolData.Propellant = ACF.ReadNumber("Propellant") + ToolData.Propellant = ACF.GetClientNumber("Propellant") if not IsTracked then BulletData.Priority = "Propellant" @@ -87,7 +87,7 @@ local function AddControls(Base, Settings, ToolData) Ammo:UpdateRoundData(ToolData, BulletData) - ACF.WriteValue("Projectile", BulletData.ProjLength) + ACF.SetClientData("Projectile", BulletData.ProjLength) Panel:SetValue(BulletData.PropLength) @@ -105,12 +105,12 @@ local function AddControls(Base, Settings, ToolData) local Tracer = Base:AddCheckBox("Tracer") Tracer:SetDataVar("Tracer", "OnChange") Tracer:SetValueFunction(function(Panel) - ToolData.Tracer = ACF.ReadBool("Tracer") + ToolData.Tracer = ACF.GetClientBool("Tracer") Ammo:UpdateRoundData(ToolData, BulletData) - ACF.WriteValue("Projectile", BulletData.ProjLength) - ACF.WriteValue("Propellant", BulletData.PropLength) + ACF.SetClientData("Projectile", BulletData.ProjLength) + ACF.SetClientData("Propellant", BulletData.PropLength) Panel:SetText("Tracer : " .. BulletData.Tracer .. " cm") Panel:SetValue(ToolData.Tracer) @@ -118,7 +118,7 @@ local function AddControls(Base, Settings, ToolData) return ToolData.Tracer end) else - ACF.WriteValue("Tracer", false) -- Disabling the tracer, as it takes up spaces on ammo. + ACF.SetClientData("Tracer", false) -- Disabling the tracer, as it takes up spaces on ammo. end end @@ -139,7 +139,7 @@ end function ACF.UpdateAmmoMenu(Menu, Settings) if not Ammo then return end - local ToolData = ACF.GetToolData() + local ToolData = ACF.GetAllClientData() local Base = Menu.AmmoBase BulletData = Ammo:ClientConvert(ToolData) @@ -173,7 +173,7 @@ function ACF.CreateAmmoMenu(Menu, Settings) local SizeX = Menu:AddSlider("Crate Width", 6, 96, 2) SizeX:SetDataVar("CrateSizeX", "OnValueChanged") SizeX:SetValueFunction(function(Panel) - local Value = ACF.ReadNumber("CrateSizeX") + local Value = ACF.GetClientNumber("CrateSizeX") Panel:SetValue(Value) @@ -183,7 +183,7 @@ function ACF.CreateAmmoMenu(Menu, Settings) local SizeY = Menu:AddSlider("Crate Height", 6, 96, 2) SizeY:SetDataVar("CrateSizeY", "OnValueChanged") SizeY:SetValueFunction(function(Panel) - local Value = ACF.ReadNumber("CrateSizeY") + local Value = ACF.GetClientNumber("CrateSizeY") Panel:SetValue(Value) @@ -193,7 +193,7 @@ function ACF.CreateAmmoMenu(Menu, Settings) local SizeZ = Menu:AddSlider("Crate Depth", 6, 96, 2) SizeZ:SetDataVar("CrateSizeZ", "OnValueChanged") SizeZ:SetValueFunction(function(Panel) - local Value = ACF.ReadNumber("CrateSizeZ") + local Value = ACF.GetClientNumber("CrateSizeZ") Panel:SetValue(Value) @@ -215,7 +215,7 @@ function ACF.CreateAmmoMenu(Menu, Settings) Ammo = Data - ACF.WriteValue("AmmoType", Data.ID) + ACF.SetClientData("AmmoType", Data.ID) Desc:SetText(Data.Description) diff --git a/lua/acf/client/cl_spawn_menu.lua b/lua/acf/client/cl_spawn_menu.lua index 9bee0e38e..df005cbfd 100644 --- a/lua/acf/client/cl_spawn_menu.lua +++ b/lua/acf/client/cl_spawn_menu.lua @@ -204,7 +204,7 @@ do -- ACF Menu context panel self.Selected = Node ACF.SetToolMode("acf_menu", "Main", "Idle") - ACF.WriteValue("Destiny") + ACF.SetClientData("Destiny") Menu:ClearTemporal() Menu:StartTemporal() diff --git a/lua/acf/client/menu_items/components_menu.lua b/lua/acf/client/menu_items/components_menu.lua index 7b48f7446..632410059 100644 --- a/lua/acf/client/menu_items/components_menu.lua +++ b/lua/acf/client/menu_items/components_menu.lua @@ -2,8 +2,8 @@ local ACF = ACF local Components = ACF.Classes.Components local function CreateMenu(Menu) - ACF.WriteValue("PrimaryClass", "N/A") - ACF.WriteValue("SecondaryClass", "N/A") + ACF.SetClientData("PrimaryClass", "N/A") + ACF.SetClientData("SecondaryClass", "N/A") ACF.SetToolMode("acf_menu", "Main", "Spawner") @@ -29,7 +29,7 @@ local function CreateMenu(Menu) self.ListData.Index = Index self.Selected = Data - ACF.WriteValue("ComponentClass", Data.ID) + ACF.SetClientData("ComponentClass", Data.ID) ACF.LoadSortedList(ComponentList, Data.Items, "ID") end @@ -43,7 +43,7 @@ local function CreateMenu(Menu) local Preview = Data.Preview local ClassData = ComponentClass.Selected - ACF.WriteValue("Component", Data.ID) + ACF.SetClientData("Component", Data.ID) ComponentName:SetText(Data.Name) ComponentDesc:SetText(Data.Description or "No description provided.") diff --git a/lua/acf/client/menu_items/engines_menu.lua b/lua/acf/client/menu_items/engines_menu.lua index 90b167955..9ac6a5e91 100644 --- a/lua/acf/client/menu_items/engines_menu.lua +++ b/lua/acf/client/menu_items/engines_menu.lua @@ -79,8 +79,8 @@ local function CreateMenu(Menu) local FuelPreview = FuelBase:AddModelPreview() local FuelInfo = FuelBase:AddLabel() - ACF.WriteValue("PrimaryClass", "acf_engine") - ACF.WriteValue("SecondaryClass", "acf_fueltank") + ACF.SetClientData("PrimaryClass", "acf_engine") + ACF.SetClientData("SecondaryClass", "acf_fueltank") ACF.SetToolMode("acf_menu", "Main", "Spawner") @@ -90,7 +90,7 @@ local function CreateMenu(Menu) self.ListData.Index = Index self.Selected = Data - ACF.WriteValue("EngineClass", Data.ID) + ACF.SetClientData("EngineClass", Data.ID) ACF.LoadSortedList(EngineList, Data.Items, "Mass") end @@ -105,7 +105,7 @@ local function CreateMenu(Menu) local ClassData = EngineClass.Selected local ClassDesc = ClassData.Description - ACF.WriteValue("Engine", Data.ID) + ACF.SetClientData("Engine", Data.ID) EngineName:SetText(Data.Name) EngineDesc:SetText((ClassDesc and (ClassDesc .. "\n\n") or "") .. Data.Description) @@ -142,7 +142,7 @@ local function CreateMenu(Menu) self.Description = (ClassDesc and (ClassDesc .. "\n\n") or "") .. Data.Description - ACF.WriteValue("FuelTank", Data.ID) + ACF.SetClientData("FuelTank", Data.ID) FuelPreview:SetModel(Data.Model) FuelPreview:SetCamPos(Preview and Preview.Offset or Vector(45, 60, 45)) @@ -159,7 +159,7 @@ local function CreateMenu(Menu) self.ListData.Index = Index self.Selected = Data - ACF.WriteValue("FuelType", Data.ID) + ACF.SetClientData("FuelType", Data.ID) self:UpdateFuelText() end diff --git a/lua/acf/client/menu_items/gearboxes_menu.lua b/lua/acf/client/menu_items/gearboxes_menu.lua index 20463fcbe..ef13e37a3 100644 --- a/lua/acf/client/menu_items/gearboxes_menu.lua +++ b/lua/acf/client/menu_items/gearboxes_menu.lua @@ -12,8 +12,8 @@ local function CreateMenu(Menu) local GearboxDesc = Base:AddLabel() local GearboxPreview = Base:AddModelPreview() - ACF.WriteValue("PrimaryClass", "acf_gearbox") - ACF.WriteValue("SecondaryClass", "N/A") + ACF.SetClientData("PrimaryClass", "acf_gearbox") + ACF.SetClientData("SecondaryClass", "N/A") ACF.SetToolMode("acf_menu", "Main", "Spawner") @@ -23,7 +23,7 @@ local function CreateMenu(Menu) self.ListData.Index = Index self.Selected = Data - ACF.WriteValue("GearboxClass", Data.ID) + ACF.SetClientData("GearboxClass", Data.ID) ACF.LoadSortedList(GearboxList, Data.Items, "ID") end @@ -37,7 +37,7 @@ local function CreateMenu(Menu) local Preview = Data.Preview local ClassData = GearboxClass.Selected - ACF.WriteValue("Gearbox", Data.ID) + ACF.SetClientData("Gearbox", Data.ID) GearboxName:SetText(Data.Name) GearboxDesc:SetText(Data.Description) @@ -97,12 +97,12 @@ do -- Default Menus ValuesData[Variable] = Default end - ACF.WriteValue(Variable, Default) + ACF.SetClientData(Variable, Default) local Control = GearBase:AddSlider("Gear " .. I, -1, 1, 2) Control:SetDataVar(Variable, "OnValueChanged") Control:SetValueFunction(function(Panel) - local Value = math.Round(ACF.ReadNumber(Variable), 2) + local Value = math.Round(ACF.GetClientNumber(Variable), 2) ValuesData[Variable] = Value @@ -116,12 +116,12 @@ do -- Default Menus ValuesData.FinalDrive = 1 end - ACF.WriteValue("FinalDrive", ValuesData.FinalDrive) + ACF.SetClientData("FinalDrive", ValuesData.FinalDrive) local FinalDrive = GearBase:AddSlider("Final Drive", -1, 1, 2) FinalDrive:SetDataVar("FinalDrive", "OnValueChanged") FinalDrive:SetValueFunction(function(Panel) - local Value = math.Round(ACF.ReadNumber("FinalDrive"), 2) + local Value = math.Round(ACF.GetClientNumber("FinalDrive"), 2) ValuesData.FinalDrive = Value @@ -187,7 +187,7 @@ do -- Default Menus local ValuesData = Values[Class.ID] - ACF.WriteValue("Gear1", 0.01) + ACF.SetClientData("Gear1", 0.01) for _, GearData in ipairs(CVTData) do local Variable = GearData.Variable @@ -199,12 +199,12 @@ do -- Default Menus ValuesData[Variable] = Default end - ACF.WriteValue(Variable, Default) + ACF.SetClientData(Variable, Default) local Control = GearBase:AddSlider(GearData.Name, GearData.Min, GearData.Max, GearData.Decimals) Control:SetDataVar(Variable, "OnValueChanged") Control:SetValueFunction(function(Panel) - local Value = math.Round(ACF.ReadNumber(Variable), GearData.Decimals) + local Value = math.Round(ACF.GetClientNumber(Variable), GearData.Decimals) ValuesData[Variable] = Value @@ -289,7 +289,7 @@ do -- Default Menus GearBase:AddLabel("Upshift Speed Unit :") - ACF.WriteValue("ShiftUnit", UnitMult) + ACF.SetClientData("ShiftUnit", UnitMult) local Unit = GearBase:AddComboBox() Unit:AddChoice("KPH", 10.936) @@ -303,12 +303,12 @@ do -- Default Menus for I = 1, Gears.Max do local Var = "Shift" .. I - local Old = ACF.ReadNumber(Var) + local Old = ACF.GetClientNumber(Var) - ACF.WriteValue(Var, Old * Delta) + ACF.SetClientData(Var, Old * Delta) end - ACF.WriteValue("ShiftUnit", Mult) + ACF.SetClientData("ShiftUnit", Mult) UnitMult = Mult end @@ -323,12 +323,12 @@ do -- Default Menus ValuesData[GearVar] = DefGear end - ACF.WriteValue(GearVar, DefGear) + ACF.SetClientData(GearVar, DefGear) local Gear = GearBase:AddSlider("Gear " .. I, -1, 1, 2) Gear:SetDataVar(GearVar, "OnValueChanged") Gear:SetValueFunction(function(Panel) - local Value = math.Round(ACF.ReadNumber(GearVar), 2) + local Value = math.Round(ACF.GetClientNumber(GearVar), 2) ValuesData[GearVar] = Value @@ -346,13 +346,13 @@ do -- Default Menus ValuesData[ShiftVar] = DefShift end - ACF.WriteValue(ShiftVar, DefShift) + ACF.SetClientData(ShiftVar, DefShift) local Shift = GearBase:AddNumberWang("Gear " .. I .. " Upshift Speed", 0, 9999, 2) Shift:HideWang() Shift:SetDataVar(ShiftVar, "OnValueChanged") Shift:SetValueFunction(function(Panel) - local Value = math.Round(ACF.ReadNumber(ShiftVar), 2) + local Value = math.Round(ACF.GetClientNumber(ShiftVar), 2) ValuesData[ShiftVar] = Value @@ -372,12 +372,12 @@ do -- Default Menus ValuesData[Variable] = Default end - ACF.WriteValue(Variable, Default) + ACF.SetClientData(Variable, Default) local Control = GearBase:AddSlider(GearData.Name, GearData.Min, GearData.Max, GearData.Decimals) Control:SetDataVar(Variable, "OnValueChanged") Control:SetValueFunction(function(Panel) - local Value = math.Round(ACF.ReadNumber(Variable), GearData.Decimals) + local Value = math.Round(ACF.GetClientNumber(Variable), GearData.Decimals) ValuesData[Variable] = Value @@ -403,13 +403,13 @@ do -- Default Menus ValuesData[Variable] = Default end - ACF.WriteValue(Variable, Default) + ACF.SetClientData(Variable, Default) local Panel = GenBase:AddNumberWang(PanelData.Name, PanelData.Min, PanelData.Max, PanelData.Decimals) Panel:HideWang() Panel:SetDataVar(Variable, "OnValueChanged") Panel:SetValueFunction(function() - local Value = math.Round(ACF.ReadNumber(Variable), PanelData.Decimals) + local Value = math.Round(ACF.GetClientNumber(Variable), PanelData.Decimals) ValuesData[Variable] = Value @@ -435,7 +435,7 @@ do -- Default Menus for I = 1, Gears.Max do local Gear = ValuesData["Gear" .. I] - ACF.WriteValue("Shift" .. I, Gear * Multiplier) + ACF.SetClientData("Shift" .. I, Gear * Multiplier) end end end diff --git a/lua/acf/client/menu_items/sensors_menu.lua b/lua/acf/client/menu_items/sensors_menu.lua index 028768a90..ec654edeb 100644 --- a/lua/acf/client/menu_items/sensors_menu.lua +++ b/lua/acf/client/menu_items/sensors_menu.lua @@ -2,8 +2,8 @@ local ACF = ACF local Sensors = ACF.Classes.Sensors local function CreateMenu(Menu) - ACF.WriteValue("PrimaryClass", "N/A") - ACF.WriteValue("SecondaryClass", "N/A") + ACF.SetClientData("PrimaryClass", "N/A") + ACF.SetClientData("SecondaryClass", "N/A") ACF.SetToolMode("acf_menu", "Main", "Spawner") @@ -29,7 +29,7 @@ local function CreateMenu(Menu) self.ListData.Index = Index self.Selected = Data - ACF.WriteValue("SensorClass", Data.ID) + ACF.SetClientData("SensorClass", Data.ID) ACF.LoadSortedList(SensorList, Data.Items, "ID") end @@ -43,7 +43,7 @@ local function CreateMenu(Menu) local Preview = Data.Preview local ClassData = SensorClass.Selected - ACF.WriteValue("Sensor", Data.ID) + ACF.SetClientData("Sensor", Data.ID) SensorName:SetText(Data.Name) SensorDesc:SetText(Data.Description or "No description provided.") diff --git a/lua/acf/client/menu_items/weapons_menu.lua b/lua/acf/client/menu_items/weapons_menu.lua index d8ec7bed4..38a1de5c1 100644 --- a/lua/acf/client/menu_items/weapons_menu.lua +++ b/lua/acf/client/menu_items/weapons_menu.lua @@ -18,8 +18,8 @@ local function CreateMenu(Menu) local AmmoList = ACF.CreateAmmoMenu(Menu) - ACF.WriteValue("PrimaryClass", "acf_gun") - ACF.WriteValue("SecondaryClass", "acf_ammo") + ACF.SetClientData("PrimaryClass", "acf_gun") + ACF.SetClientData("SecondaryClass", "acf_ammo") ACF.SetToolMode("acf_menu", "Main", "Spawner") @@ -44,7 +44,7 @@ local function CreateMenu(Menu) self.ListData.Index = Index self.Selected = Data - ACF.WriteValue("WeaponClass", Data.ID) + ACF.SetClientData("WeaponClass", Data.ID) ClassDesc:SetText(Data.Description) @@ -61,8 +61,8 @@ local function CreateMenu(Menu) local Preview = Data.Preview - ACF.WriteValue("Weapon", Data.ID) - ACF.WriteValue("Destiny", Data.Destiny or "Weapons") + ACF.SetClientData("Weapon", Data.ID) + ACF.SetClientData("Destiny", Data.Destiny or "Weapons") EntName:SetText(Data.Name) EntData:SetText(UpdateEntityData()) diff --git a/lua/acf/shared/ammo_types/aphe.lua b/lua/acf/shared/ammo_types/aphe.lua index cbeb3d771..b1d292bb3 100644 --- a/lua/acf/shared/ammo_types/aphe.lua +++ b/lua/acf/shared/ammo_types/aphe.lua @@ -133,7 +133,7 @@ else FillerMass:SetDataVar("FillerMass", "OnValueChanged") FillerMass:TrackDataVar("Projectile") FillerMass:SetValueFunction(function(Panel) - ToolData.FillerMass = math.Round(ACF.ReadNumber("FillerMass"), 2) + ToolData.FillerMass = math.Round(ACF.GetClientNumber("FillerMass"), 2) self:UpdateRoundData(ToolData, BulletData) diff --git a/lua/acf/shared/ammo_types/fl.lua b/lua/acf/shared/ammo_types/fl.lua index e64f1867b..c3311d58a 100644 --- a/lua/acf/shared/ammo_types/fl.lua +++ b/lua/acf/shared/ammo_types/fl.lua @@ -184,7 +184,7 @@ else local Flechettes = Base:AddSlider("Flechette Amount", BulletData.MinFlechettes, BulletData.MaxFlechettes) Flechettes:SetDataVar("Flechettes", "OnValueChanged") Flechettes:SetValueFunction(function(Panel) - ToolData.Flechettes = math.floor(ACF.ReadNumber("Flechettes")) + ToolData.Flechettes = math.floor(ACF.GetClientNumber("Flechettes")) Ammo:UpdateRoundData(ToolData, BulletData) @@ -196,7 +196,7 @@ else local Spread = Base:AddSlider("Flechette Spread", BulletData.MinSpread, BulletData.MaxSpread, 2) Spread:SetDataVar("Spread", "OnValueChanged") Spread:SetValueFunction(function(Panel) - ToolData.Spread = ACF.ReadNumber("Spread") + ToolData.Spread = ACF.GetClientNumber("Spread") Ammo:UpdateRoundData(ToolData, BulletData) diff --git a/lua/acf/shared/ammo_types/heat.lua b/lua/acf/shared/ammo_types/heat.lua index 5d2372ffa..b745672da 100644 --- a/lua/acf/shared/ammo_types/heat.lua +++ b/lua/acf/shared/ammo_types/heat.lua @@ -310,7 +310,7 @@ else LinerAngle:SetDataVar("LinerAngle", "OnValueChanged") LinerAngle:TrackDataVar("Projectile") LinerAngle:SetValueFunction(function(Panel) - ToolData.LinerAngle = math.Round(ACF.ReadNumber("LinerAngle"), 2) + ToolData.LinerAngle = math.Round(ACF.GetClientNumber("LinerAngle"), 2) self:UpdateRoundData(ToolData, BulletData) @@ -325,7 +325,7 @@ else FillerMass:TrackDataVar("Projectile") FillerMass:TrackDataVar("LinerAngle") FillerMass:SetValueFunction(function(Panel) - ToolData.FillerMass = math.Round(ACF.ReadNumber("FillerMass"), 2) + ToolData.FillerMass = math.Round(ACF.GetClientNumber("FillerMass"), 2) self:UpdateRoundData(ToolData, BulletData) diff --git a/lua/acf/shared/ammo_types/hp.lua b/lua/acf/shared/ammo_types/hp.lua index 94e0407d7..69829b3b0 100644 --- a/lua/acf/shared/ammo_types/hp.lua +++ b/lua/acf/shared/ammo_types/hp.lua @@ -109,7 +109,7 @@ else HollowCavity:SetDataVar("HollowCavity", "OnValueChanged") HollowCavity:TrackDataVar("Projectile") HollowCavity:SetValueFunction(function(Panel) - ToolData.HollowCavity = math.Round(ACF.ReadNumber("HollowCavity"), 2) + ToolData.HollowCavity = math.Round(ACF.GetClientNumber("HollowCavity"), 2) self:UpdateRoundData(ToolData, BulletData) diff --git a/lua/acf/shared/ammo_types/smoke.lua b/lua/acf/shared/ammo_types/smoke.lua index 44e8ae3aa..461b742c7 100644 --- a/lua/acf/shared/ammo_types/smoke.lua +++ b/lua/acf/shared/ammo_types/smoke.lua @@ -194,7 +194,7 @@ else SmokeFiller:TrackDataVar("Projectile") SmokeFiller:TrackDataVar("WPFiller") SmokeFiller:SetValueFunction(function(Panel, IsTracked) - ToolData.SmokeFiller = math.Round(ACF.ReadNumber("SmokeFiller"), 2) + ToolData.SmokeFiller = math.Round(ACF.GetClientNumber("SmokeFiller"), 2) if not IsTracked then BulletData.FillerPriority = "Smoke" @@ -213,7 +213,7 @@ else WPFiller:TrackDataVar("SmokeFiller") WPFiller:TrackDataVar("Projectile") WPFiller:SetValueFunction(function(Panel, IsTracked) - ToolData.WPFiller = math.Round(ACF.ReadNumber("WPFiller"), 2) + ToolData.WPFiller = math.Round(ACF.GetClientNumber("WPFiller"), 2) if not IsTracked then BulletData.FillerPriority = "WP" diff --git a/lua/acf/shared/tool_operations/acf_menu.lua b/lua/acf/shared/tool_operations/acf_menu.lua index 1df30107e..9f11ed2dc 100644 --- a/lua/acf/shared/tool_operations/acf_menu.lua +++ b/lua/acf/shared/tool_operations/acf_menu.lua @@ -1,5 +1,4 @@ -local GetToolData = ACF.GetToolData -local SendMessage = ACF.SendMessage +local ACF = ACF local Entities = {} local function GetPlayerEnts(Player) @@ -64,7 +63,7 @@ do -- Spawner operation if CanUpdate(Player, Entity, ClassName) then local Result, Message = Entity:Update(Data) - SendMessage(Player, Result and "Info" or "Error", Message) + ACF.SendMessage(Player, Result and "Info" or "Error", Message) return true end @@ -87,14 +86,14 @@ do -- Spawner operation if Trace.HitSky then return false end local Player = Tool:GetOwner() - local Data = GetToolData(Player) + local Data = ACF.GetAllClientData(Player) local ClassName = Data.PrimaryClass return SpawnEntity(Player, ClassName, Trace, Data) end, OnRightClick = function(Tool, Trace) local Player = Tool:GetOwner() - local Data = GetToolData(Player) + local Data = ACF.GetAllClientData(Player) local ClassName = Data.SecondaryClass if not Player:KeyDown(IN_SPEED) and SpawnEntity(Player, ClassName, Trace, Data) then @@ -155,11 +154,11 @@ do -- Linker operation if Done > 0 then local Status = (Unlink and "unlinked " or "linked ") .. Done .. " out of " .. Total - SendMessage(Player, "Info", "Successfully ", Status, " entities to ", tostring(Entity), ".") + ACF.SendMessage(Player, "Info", "Successfully ", Status, " entities to ", tostring(Entity), ".") else local Status = Total .. " entities could be " .. (Unlink and "unlinked" or "linked") - SendMessage(Player, "Error", "None of the ", Status, " to ", tostring(Entity), ".") + ACF.SendMessage(Player, "Error", "None of the ", Status, " to ", tostring(Entity), ".") end end From c47b73946497cb3d0b4debde07f02a81436a3bf9 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Wed, 16 Dec 2020 16:38:39 -0300 Subject: [PATCH 220/279] Added server data vars - Added server data vars, which will be synchronized between the server and every connected client at all given times. - Added shared server data getters, similar to their client data counterparts. - Added shared ACF.SetServerData function. The clientside version will make sure the player can mess with server data vars before even attempting to change its value. - Added shared ACF.CanSetServerData function. It'll return true if the given player can mess with server data vars. --- lua/acf/base/data_vars/cl_data_vars.lua | 58 ++++++++++- lua/acf/base/data_vars/sh_data_vars.lua | 54 ++++++++++ lua/acf/base/data_vars/sv_data_vars.lua | 133 +++++++++++++++++++++--- 3 files changed, 230 insertions(+), 15 deletions(-) create mode 100644 lua/acf/base/data_vars/sh_data_vars.lua diff --git a/lua/acf/base/data_vars/cl_data_vars.lua b/lua/acf/base/data_vars/cl_data_vars.lua index f8d318d2c..bab1ec53d 100644 --- a/lua/acf/base/data_vars/cl_data_vars.lua +++ b/lua/acf/base/data_vars/cl_data_vars.lua @@ -54,7 +54,41 @@ local function NetworkData(Key, IsServer) timer.Create("ACF Network Data Vars", 0, 1, SendQueued) end -do -- Client data retrieval functions +do -- Server data var syncronization + local function ProcessData(Values, Received) + if not Received then return end + + for K, V in pairs(Received) do + if Values[K] ~= V then + Values[K] = V + + hook.Run("ACF_OnServerDataUpdate", nil, K, V) + end + + Received[K] = nil + end + end + + net.Receive("ACF_DataVarNetwork", function(_, Player) + local Received = util.JSONToTable(net.ReadString()) + + if IsValid(Player) then return end -- NOTE: Can this even happen? + + ProcessData(Server, Received) + end) + + -- We'll request the server data vars as soon as the player starts moving + hook.Add("CreateMove", "ACF Request Data Vars", function(Move) + if Move:GetButtons() == 0 then return end + + net.Start("ACF_RequestDataVars") + net.SendToServer() + + hook.Remove("CreateMove", "ACF Request Data Vars") + end) +end + +do -- Client data getter functions local function GetData(Key, Default) if Key == nil then return Default end @@ -97,7 +131,7 @@ do -- Client data retrieval functions ACF.GetClientRaw = GetData end -do -- Write function +do -- Client data setter function function ACF.SetClientData(Key, Value) if not isstring(Key) then return end @@ -113,6 +147,26 @@ do -- Write function end end +do -- Server data setter function + function ACF.SetServerData(Key, Value) + if not isstring(Key) then return end + + local Player = LocalPlayer() + + if not ACF.CanSetServerData(Player) then return end + + Value = Value or false + + if Server[Key] ~= Value then + Server[Key] = Value + + hook.Run("ACF_OnServerDataUpdate", Player, Key, Value) + + NetworkData(Key, true) + end + end +end + do -- Panel functions local PANEL = FindMetaTable("Panel") local Trackers = {} diff --git a/lua/acf/base/data_vars/sh_data_vars.lua b/lua/acf/base/data_vars/sh_data_vars.lua new file mode 100644 index 000000000..b90d71c7c --- /dev/null +++ b/lua/acf/base/data_vars/sh_data_vars.lua @@ -0,0 +1,54 @@ +local ACF = ACF +local Server = ACF.ServerData + +function ACF.CanSetServerData(Player) + if not IsValid(Player) then return true end -- No player, probably the server + if Player:IsSuperAdmin() then return true end + + local AllowAdmin = ACF.GetServerBool("ServerDataAllowAdmin") + + return AllowAdmin and Player:IsAdmin() +end + +do -- Server data getter functions + local function GetData(Key, Default) + if Key == nil then return Default end + + local Value = Server[Key] + + if Value ~= nil then return Value end + + return Default + end + + function ACF.GetAllServerData(NoCopy) + if NoCopy then return Server end + + local Result = {} + + for K, V in pairs(Server) do + Result[K] = V + end + + return Result + end + + function ACF.GetServerBool(Key, Default) + return tobool(GetData(Key, Default)) + end + + function ACF.GetServerNumber(Key, Default) + local Value = GetData(Key, Default) + + return ACF.CheckNumber(Value, 0) + end + + function ACF.GetServerString(Key, Default) + local Value = GetData(Key, Default) + + return ACF.CheckString(Value, "") + end + + ACF.GetServerData = GetData + ACF.GetServerRaw = GetData +end \ No newline at end of file diff --git a/lua/acf/base/data_vars/sv_data_vars.lua b/lua/acf/base/data_vars/sv_data_vars.lua index 200574811..d1b08d258 100644 --- a/lua/acf/base/data_vars/sv_data_vars.lua +++ b/lua/acf/base/data_vars/sv_data_vars.lua @@ -1,8 +1,66 @@ local ACF = ACF local Client = ACF.ClientData +local Server = ACF.ServerData +local Queued = {} + +local function PrepareQueue(Type, Values) + local Queue = Queued[Type] + + if not next(Queue) then return end + + local Data = {} + + for K in pairs(Queue) do + Data[K] = Values[K] + Queue[K] = nil + end + + return util.TableToJSON(Data) +end + +local function SendQueued() + local Broadcast = Queued.Broadcast + + if Broadcast then + net.Start("ACF_DataVarNetwork") + net.WriteString(PrepareQueue("Broadcast", Server)) + net.Broadcast() + + Queued.Broadcast = nil + end + + for Player in pairs(Queued) do + net.Start("ACF_DataVarNetwork") + net.WriteString(PrepareQueue(Player, Server)) + net.Send(Player) + + Queued[Player] = nil + end +end + +local function NetworkData(Key, Player) + local Type = IsValid(Player) and Player or "Broadcast" + local Destiny = Queued[Type] + + if Destiny and Destiny[Key] then return end -- Already queued + + if not Destiny then + Queued[Type] = { + [Key] = true + } + else + Destiny[Key] = true + end + + -- Avoiding net message spam by sending all the events of a tick at once + if timer.Exists("ACF Network Data Vars") then return end + + timer.Create("ACF Network Data Vars", 0, 1, SendQueued) +end do -- Data syncronization util.AddNetworkString("ACF_DataVarNetwork") + util.AddNetworkString("ACF_RequestDataVars") local function ProcessData(Player, Type, Values, Received) local Data = Received[Type] @@ -12,31 +70,65 @@ do -- Data syncronization local Hook = "ACF_On" .. Type .. "DataUpdate" for K, V in pairs(Data) do - Values[K] = V - Data[K] = nil + if Values[K] ~= V then + Values[K] = V + + hook.Run(Hook, Player, K, V) + end - hook.Run(Hook, Player, K, V) + Data[K] = nil end end net.Receive("ACF_DataVarNetwork", function(_, Player) local Received = util.JSONToTable(net.ReadString()) - if IsValid(Player) then - ProcessData(Player, "Client", Client[Player], Received) + if not IsValid(Player) then return end -- NOTE: Can this even happen? + + ProcessData(Player, "Client", Client[Player], Received) + + -- There's a check on the clientside for this, but we won't trust it + if ACF.CanSetServerData(Player) then + ProcessData(Player, "Server", Server, Received) + else + local Data = Received.Server + + if not Data then return end + + -- This player shouldn't be updating these values + -- So we'll just force him to update with the correct stuff + for Key in pairs(Data) do + NetworkData(Key, Player) + end + end + end) + + net.Receive("ACF_RequestDataVars", function(_, Player) + -- Server data var syncronization + for Key in pairs(Server) do + NetworkData(Key, Player) end end) - hook.Add("PlayerInitialSpawn", "ACF Client Data", function(Player) + hook.Add("PlayerInitialSpawn", "ACF Data Var Syncronization", function(Player) Client[Player] = {} end) - hook.Add("PlayerDisconnected", "ACF Client Data", function(Player) + hook.Add("PlayerDisconnected", "ACF Data Var Syncronization", function(Player) Client[Player] = nil + Queued[Player] = nil + end) + + hook.Add("ACF_OnServerDataUpdate", "ACF Network Server Data", function(Player, Key) + for K in pairs(Client) do + if Player ~= K then + NetworkData(Key, K) + end + end end) end -do -- Read functions +do -- Client data getter functions local function GetData(Player, Key, Default) if not IsValid(Player) then return Default end if Key == nil then return Default end @@ -54,14 +146,13 @@ do -- Read functions local Data = Client[Player] - if NoCopy then return Data or {} end + if not Data then return {} end + if NoCopy then return Data end local Result = {} - if Data then - for K, V in pairs(Data) do - Result[K] = V - end + for K, V in pairs(Data) do + Result[K] = V end return Result @@ -86,3 +177,19 @@ do -- Read functions ACF.GetClientData = GetData ACF.GetClientRaw = GetData end + +do -- Server data setter function + function ACF.SetServerData(Key, Value) + if not isstring(Key) then return end + + Value = Value or false + + if Server[Key] ~= Value then + Server[Key] = Value + + hook.Run("ACF_OnServerDataUpdate", nil, Key, Value) + + NetworkData(Key) + end + end +end From 1ecc33c53232de1f97a203af66dd5d0d7cb51a5f Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sat, 19 Dec 2020 08:42:01 -0300 Subject: [PATCH 221/279] Improved DataVar panel functions - Updated data var panel functions to support both server and client data. Naming conventions were changed. - Updated every case of panel functions being used on ACF to comply with the latest changes. --- lua/acf/base/data_vars/cl_data_vars.lua | 268 ++++++++++++------- lua/acf/base/data_vars/sh_data_vars.lua | 5 +- lua/acf/base/data_vars/sv_data_vars.lua | 4 +- lua/acf/client/cl_ammo_menu.lua | 44 ++- lua/acf/client/menu_items/gearboxes_menu.lua | 42 +-- lua/acf/client/menu_items/weapons_menu.lua | 37 ++- lua/acf/shared/ammo_types/ap.lua | 12 +- lua/acf/shared/ammo_types/aphe.lua | 30 ++- lua/acf/shared/ammo_types/fl.lua | 28 +- lua/acf/shared/ammo_types/he.lua | 12 +- lua/acf/shared/ammo_types/heat.lua | 58 ++-- lua/acf/shared/ammo_types/hp.lua | 34 +-- lua/acf/shared/ammo_types/smoke.lua | 52 ++-- 13 files changed, 347 insertions(+), 279 deletions(-) diff --git a/lua/acf/base/data_vars/cl_data_vars.lua b/lua/acf/base/data_vars/cl_data_vars.lua index bab1ec53d..9fd9cc315 100644 --- a/lua/acf/base/data_vars/cl_data_vars.lua +++ b/lua/acf/base/data_vars/cl_data_vars.lua @@ -132,12 +132,12 @@ do -- Client data getter functions end do -- Client data setter function - function ACF.SetClientData(Key, Value) + function ACF.SetClientData(Key, Value, Forced) if not isstring(Key) then return end Value = Value or false - if Client[Key] ~= Value then + if Forced or Client[Key] ~= Value then Client[Key] = Value hook.Run("ACF_OnClientDataUpdate", LocalPlayer(), Key, Value) @@ -148,7 +148,7 @@ do -- Client data setter function end do -- Server data setter function - function ACF.SetServerData(Key, Value) + function ACF.SetServerData(Key, Value, Forced) if not isstring(Key) then return end local Player = LocalPlayer() @@ -157,7 +157,7 @@ do -- Server data setter function Value = Value or false - if Server[Key] ~= Value then + if Forced or Server[Key] ~= Value then Server[Key] = Value hook.Run("ACF_OnServerDataUpdate", Player, Key, Value) @@ -168,163 +168,227 @@ do -- Server data setter function end do -- Panel functions - local PANEL = FindMetaTable("Panel") - local Trackers = {} - local Setters = {} - local Variables = { - Trackers = {}, - Setters = {}, + ACF.DataPanels = ACF.DataPanels or { + Server = {}, + Client = {}, + Panels = {}, } - local function AddVariable(Panel, Key, Target) - local Data = Target[Key] + local PanelMeta = FindMetaTable("Panel") + local DataPanels = ACF.DataPanels - if not Data then - Target[Key] = { - [Panel] = true - } - else - Data[Panel] = true + local function GetSubtable(Table, Key) + local Result = Table[Key] + + if not Result then + Result = {} + Table[Key] = Result end + + return Result end - local function AddTracker(Panel, Key) - local Data = Trackers[Panel] + local function StoreData(Destiny, Key, Type, Value, Store) + local BaseData = GetSubtable(DataPanels[Destiny], Key) + local TypeData = GetSubtable(BaseData, Type) - if not Data then - Trackers[Panel] = { - [Key] = true - } - else - Data[Key] = true - end + TypeData[Value] = Store or true + end + + local function ClearFromType(Data, Type, Panel) + local Saved = Data[Type] - AddVariable(Panel, Key, Variables.Trackers) + if not Saved then return end + + for Name, Mode in pairs(Saved) do + DataPanels[Type][Name][Mode][Panel] = nil -- Weed lmao + end end - local function AddSetter(Panel, Key) - local Data = Setters[Panel] + local function ClearData(Panel) + local Panels = DataPanels.Panels + local Data = Panels[Panel] - if not Data then - Setters[Panel] = { - [Key] = true - } - else - Data[Key] = true + -- Apparently this can be called twice + if Data then + ClearFromType(Data, "Server", Panel) + ClearFromType(Data, "Client", Panel) end - AddVariable(Panel, Key, Variables.Setters) + Panels[Panel] = nil end - local function ClearVariables(Panel) - if Trackers[Panel] then - for K in pairs(Trackers[Panel]) do - Variables.Trackers[K][Panel] = nil + local function HijackThink(Panel) + local OldThink = Panel.Think + local Player = LocalPlayer() + + Panel.Enabled = Panel:IsEnabled() + + function Panel:Think(...) + if self.ServerVar then + local Enabled = ACF.CanSetServerData(Player) + + if self.Enabled ~= Enabled then + self.Enabled = Enabled + + self:SetEnabled(Enabled) + end end - Trackers[Panel] = nil + if OldThink then + return OldThink(self, ...) + end end + end - if Setters[Panel] then - for K in pairs(Setters[Panel]) do - Variables.Setters[K][Panel] = nil - end + local function HijackRemove(Panel) + local OldRemove = Panel.Remove + + function Panel:Remove(...) + ClearData(self) - Setters[Panel] = nil + return OldRemove(self, ...) end end - local function LoadFunctions(Panel) - if not Panel.LegacyRemove then - Panel.LegacyRemove = Panel.Remove + local function HijackFunctions(Panel, SetFunction) + if Panel.Hijacked then return end + + local Setter = Panel[SetFunction] and SetFunction or "SetValue" - function Panel:Remove() - ClearVariables(self) + Panel.OldSet = Panel[Setter] + Panel.Hijacked = true - self:LegacyRemove() + Panel[Setter] = function(This, Value, Forced) + local ServerVar = This.ServerVar + local ClientVar = This.ClientVar + + if not (ServerVar or ClientVar) then + if This.SetCustomValue then + Value = This:SetCustomValue(nil, nil, Value) or Value + end + + return This:OldSet(Value) + end + + if ServerVar then + ACF.SetServerData(ServerVar, Value, Forced) end - end - if Panel.Hijack and Panel.Hijack ~= Panel.PrevHijack then - if Panel.PrevHijack then - Panel[Panel.PrevHijack] = Panel.OldSetFunc + if ClientVar then + ACF.SetClientData(ClientVar, Value, Forced) end + end - Panel.PrevHijack = Panel.Hijack - Panel.OldSetFunc = Panel[Panel.Hijack] + Panel.Setter = Panel[Setter] - function Panel:NewSetFunc(Value) - if self.DataVar then - ACF.SetClientData(self.DataVar, Value) - return + -- We'll give a basic GetCustomValue function by default + -- I'll only work with setter panels though + if not Panel.GetCustomValue then + function Panel:GetCustomValue(Value) + if self.ClientVar then + return ACF.GetClientData(self.ClientVar, Value) end - self:OldSetFunc(Value) - end + if self.ServerVar then + return ACF.GetServerData(self.ServerVar, Value) + end - Panel[Panel.Hijack] = Panel.NewSetFunc + return Value + end end + + HijackThink(Panel) + HijackRemove(Panel) end - function PANEL:SetDataVar(Key, Function) - if not Key then return end + local function UpdatePanels(Panels, Type, Key, Value, IsTracked) + if not Panels then return end - self.DataVar = Key - self.Hijack = Function or self.Hijack or "SetValue" + for Panel in pairs(Panels) do + local Result = Value - AddSetter(self, Key) - LoadFunctions(self) + if Panel.SetCustomValue then + Result = Panel:SetCustomValue(Type, Key, Value, IsTracked) + end - if not Client[Key] then - ACF.SetClientData(Key, self:GetValue()) + if Result ~= nil then + Panel:OldSet(Result) + end end end - function PANEL:TrackDataVar(Key, Function) - self.Hijack = Function or self.Hijack or "SetValue" + function PanelMeta:DefineSetter(Function) + if not isfunction(Function) then return end + + self.SetCustomValue = Function - AddTracker(self, Key) - LoadFunctions(self) + self:RefreshValue() end - function PANEL:SetValueFunction(Function) + function PanelMeta:DefineGetter(Function) if not isfunction(Function) then return end - LoadFunctions(self) + self.GetCustomValue = Function - self.ValueFunction = Function + self:RefreshValue() + end + + function PanelMeta:RefreshValue(Value) + if self.GetCustomValue then + Value = self:GetCustomValue(Value) + end - if self.Hijack then - self:NewSetFunc(self:ValueFunction()) + if Value ~= nil then + self:Setter(Value, true) end end - hook.Add("ACF_OnClientDataUpdate", "ACF Update Panel Values", function(_, Key, Value) - local TrackerPanels = Variables.Trackers[Key] - local SetterPanels = Variables.Setters[Key] + --- Generates the following functions: + -- Panel:SetClientData(Key, Setter) + -- Panel:TrackClientData(Key, Setter) + -- Panel:SetServerData(Key, Setter) + -- Panel:TrackServerData(Key, Setter) - -- First we'll process the panels that set the value of this key - if SetterPanels then - for Panel in pairs(SetterPanels) do - if not Panel.OldSetFunc then continue end + for Type in pairs(Queued) do + PanelMeta["Set" .. Type .. "Data"] = function(Panel, Key, Setter) + if not ACF.CheckString(Key) then return end - local NewValue = Value + local Variables = ACF[Type .. "Data"] + local SetFunction = ACF["Set" .. Type .. "Data"] - if Panel.ValueFunction then - NewValue = Panel:ValueFunction() - end + StoreData("Panels", Panel, Type, Key, "Setter") + StoreData(Type, Key, "Setter", Panel) + + HijackFunctions(Panel, Setter or "SetValue") + + Panel[Type .. "Var"] = Key - Panel:OldSetFunc(NewValue) + if Variables[Key] == nil then + SetFunction(Key, Panel:GetValue()) end + + Panel:RefreshValue() end - -- Then we'll process the panels that just keep track of this value - if TrackerPanels then - for Panel in pairs(TrackerPanels) do - if not Panel.ValueFunction then continue end + PanelMeta["Track" .. Type .. "Data"] = function(Panel, Key, Setter) + if not ACF.CheckString(Key) then return end - Panel:OldSetFunc(Panel:ValueFunction(true)) - end + StoreData("Panels", Panel, Type, Key, "Tracker") + StoreData(Type, Key, "Tracker", Panel) + + HijackFunctions(Panel, Setter or "SetValue") + + Panel:RefreshValue() end - end) + + hook.Add("ACF_On" .. Type .. "DataUpdate", "ACF Update Panel Values", function(_, Key, Value) + local Data = DataPanels[Type][Key] + + if not Data then return end -- This variable is not being set or tracked by panels + + UpdatePanels(Data.Setter, Type, Key, Value, IsTracked) + UpdatePanels(Data.Tracker, Type, Key, Value, IsTracked) + end) + end end diff --git a/lua/acf/base/data_vars/sh_data_vars.lua b/lua/acf/base/data_vars/sh_data_vars.lua index b90d71c7c..98174f330 100644 --- a/lua/acf/base/data_vars/sh_data_vars.lua +++ b/lua/acf/base/data_vars/sh_data_vars.lua @@ -1,5 +1,4 @@ -local ACF = ACF -local Server = ACF.ServerData +local ACF = ACF function ACF.CanSetServerData(Player) if not IsValid(Player) then return true end -- No player, probably the server @@ -11,6 +10,8 @@ function ACF.CanSetServerData(Player) end do -- Server data getter functions + local Server = ACF.ServerData + local function GetData(Key, Default) if Key == nil then return Default end diff --git a/lua/acf/base/data_vars/sv_data_vars.lua b/lua/acf/base/data_vars/sv_data_vars.lua index d1b08d258..c04293e04 100644 --- a/lua/acf/base/data_vars/sv_data_vars.lua +++ b/lua/acf/base/data_vars/sv_data_vars.lua @@ -179,12 +179,12 @@ do -- Client data getter functions end do -- Server data setter function - function ACF.SetServerData(Key, Value) + function ACF.SetServerData(Key, Value, Forced) if not isstring(Key) then return end Value = Value or false - if Server[Key] ~= Value then + if Forced or Server[Key] ~= Value then Server[Key] = Value hook.Run("ACF_OnServerDataUpdate", nil, Key, Value) diff --git a/lua/acf/client/cl_ammo_menu.lua b/lua/acf/client/cl_ammo_menu.lua index f9b0fd10c..11cdf15d8 100644 --- a/lua/acf/client/cl_ammo_menu.lua +++ b/lua/acf/client/cl_ammo_menu.lua @@ -47,10 +47,10 @@ local function AddControls(Base, Settings, ToolData) if Settings.SuppressControls then return end local RoundLength = Base:AddLabel() - RoundLength:TrackDataVar("Projectile", "SetText") - RoundLength:TrackDataVar("Propellant") - RoundLength:TrackDataVar("Tracer") - RoundLength:SetValueFunction(function() + RoundLength:TrackClientData("Projectile", "SetText", "GetText") + RoundLength:TrackClientData("Propellant") + RoundLength:TrackClientData("Tracer") + RoundLength:DefineSetter(function() local Text = "Round Length: %s / %s cm" local CurLength = BulletData.ProjLength + BulletData.PropLength + BulletData.Tracer local MaxLength = BulletData.MaxRoundLength @@ -59,9 +59,9 @@ local function AddControls(Base, Settings, ToolData) end) local Projectile = Base:AddSlider("Projectile Length", 0, BulletData.MaxRoundLength, 2) - Projectile:SetDataVar("Projectile", "OnValueChanged") - Projectile:SetValueFunction(function(Panel, IsTracked) - ToolData.Projectile = ACF.GetClientNumber("Projectile") + Projectile:SetClientData("Projectile", "OnValueChanged") + Projectile:DefineSetter(function(Panel, _, _, Value, IsTracked) + ToolData.Projectile = Value if not IsTracked then BulletData.Priority = "Projectile" @@ -77,9 +77,9 @@ local function AddControls(Base, Settings, ToolData) end) local Propellant = Base:AddSlider("Propellant Length", 0, BulletData.MaxRoundLength, 2) - Propellant:SetDataVar("Propellant", "OnValueChanged") - Propellant:SetValueFunction(function(Panel, IsTracked) - ToolData.Propellant = ACF.GetClientNumber("Propellant") + Propellant:SetClientData("Propellant", "OnValueChanged") + Propellant:DefineSetter(function(Panel, _, _, Value, IsTracked) + ToolData.Propellant = Value if not IsTracked then BulletData.Priority = "Propellant" @@ -103,9 +103,9 @@ local function AddControls(Base, Settings, ToolData) -- We'll create the tracer checkbox after all the other controls if not Settings.SuppressTracer then local Tracer = Base:AddCheckBox("Tracer") - Tracer:SetDataVar("Tracer", "OnChange") - Tracer:SetValueFunction(function(Panel) - ToolData.Tracer = ACF.GetClientBool("Tracer") + Tracer:SetClientData("Tracer", "OnChange") + Tracer:DefineSetter(function(Panel, _, _, Value) + ToolData.Tracer = Value Ammo:UpdateRoundData(ToolData, BulletData) @@ -171,30 +171,24 @@ function ACF.CreateAmmoMenu(Menu, Settings) local List = Menu:AddComboBox() local SizeX = Menu:AddSlider("Crate Width", 6, 96, 2) - SizeX:SetDataVar("CrateSizeX", "OnValueChanged") - SizeX:SetValueFunction(function(Panel) - local Value = ACF.GetClientNumber("CrateSizeX") - + SizeX:SetClientData("CrateSizeX", "OnValueChanged") + SizeX:DefineSetter(function(Panel, _, _, Value) Panel:SetValue(Value) return Value end) local SizeY = Menu:AddSlider("Crate Height", 6, 96, 2) - SizeY:SetDataVar("CrateSizeY", "OnValueChanged") - SizeY:SetValueFunction(function(Panel) - local Value = ACF.GetClientNumber("CrateSizeY") - + SizeY:SetClientData("CrateSizeY", "OnValueChanged") + SizeY:DefineSetter(function(Panel, _, _, Value) Panel:SetValue(Value) return Value end) local SizeZ = Menu:AddSlider("Crate Depth", 6, 96, 2) - SizeZ:SetDataVar("CrateSizeZ", "OnValueChanged") - SizeZ:SetValueFunction(function(Panel) - local Value = ACF.GetClientNumber("CrateSizeZ") - + SizeZ:SetClientData("CrateSizeZ", "OnValueChanged") + SizeZ:DefineSetter(function(Panel, _, _, Value) Panel:SetValue(Value) return Value diff --git a/lua/acf/client/menu_items/gearboxes_menu.lua b/lua/acf/client/menu_items/gearboxes_menu.lua index ef13e37a3..d3cb903ff 100644 --- a/lua/acf/client/menu_items/gearboxes_menu.lua +++ b/lua/acf/client/menu_items/gearboxes_menu.lua @@ -100,9 +100,9 @@ do -- Default Menus ACF.SetClientData(Variable, Default) local Control = GearBase:AddSlider("Gear " .. I, -1, 1, 2) - Control:SetDataVar(Variable, "OnValueChanged") - Control:SetValueFunction(function(Panel) - local Value = math.Round(ACF.GetClientNumber(Variable), 2) + Control:SetClientData(Variable, "OnValueChanged") + Control:DefineSetter(function(Panel, _, _, Value) + Value = math.Round(Value, 2) ValuesData[Variable] = Value @@ -119,9 +119,9 @@ do -- Default Menus ACF.SetClientData("FinalDrive", ValuesData.FinalDrive) local FinalDrive = GearBase:AddSlider("Final Drive", -1, 1, 2) - FinalDrive:SetDataVar("FinalDrive", "OnValueChanged") - FinalDrive:SetValueFunction(function(Panel) - local Value = math.Round(ACF.GetClientNumber("FinalDrive"), 2) + FinalDrive:SetClientData("FinalDrive", "OnValueChanged") + FinalDrive:DefineSetter(function(Panel, _, _, Value) + Value = math.Round(Value, 2) ValuesData.FinalDrive = Value @@ -202,9 +202,9 @@ do -- Default Menus ACF.SetClientData(Variable, Default) local Control = GearBase:AddSlider(GearData.Name, GearData.Min, GearData.Max, GearData.Decimals) - Control:SetDataVar(Variable, "OnValueChanged") - Control:SetValueFunction(function(Panel) - local Value = math.Round(ACF.GetClientNumber(Variable), GearData.Decimals) + Control:SetClientData(Variable, "OnValueChanged") + Control:DefineSetter(function(Panel, _, _, Value) + Value = math.Round(Value, GearData.Decimals) ValuesData[Variable] = Value @@ -326,9 +326,9 @@ do -- Default Menus ACF.SetClientData(GearVar, DefGear) local Gear = GearBase:AddSlider("Gear " .. I, -1, 1, 2) - Gear:SetDataVar(GearVar, "OnValueChanged") - Gear:SetValueFunction(function(Panel) - local Value = math.Round(ACF.GetClientNumber(GearVar), 2) + Gear:SetClientData(GearVar, "OnValueChanged") + Gear:DefineSetter(function(Panel, _, _, Value) + Value = math.Round(Value, 2) ValuesData[GearVar] = Value @@ -350,9 +350,9 @@ do -- Default Menus local Shift = GearBase:AddNumberWang("Gear " .. I .. " Upshift Speed", 0, 9999, 2) Shift:HideWang() - Shift:SetDataVar(ShiftVar, "OnValueChanged") - Shift:SetValueFunction(function(Panel) - local Value = math.Round(ACF.GetClientNumber(ShiftVar), 2) + Shift:SetClientData(ShiftVar, "OnValueChanged") + Shift:DefineSetter(function(Panel, _, _, Value) + Value = math.Round(Value, 2) ValuesData[ShiftVar] = Value @@ -375,9 +375,9 @@ do -- Default Menus ACF.SetClientData(Variable, Default) local Control = GearBase:AddSlider(GearData.Name, GearData.Min, GearData.Max, GearData.Decimals) - Control:SetDataVar(Variable, "OnValueChanged") - Control:SetValueFunction(function(Panel) - local Value = math.Round(ACF.GetClientNumber(Variable), GearData.Decimals) + Control:SetClientData(Variable, "OnValueChanged") + Control:DefineSetter(function(Panel, _, _, Value) + Value = math.Round(Value, GearData.Decimals) ValuesData[Variable] = Value @@ -407,9 +407,9 @@ do -- Default Menus local Panel = GenBase:AddNumberWang(PanelData.Name, PanelData.Min, PanelData.Max, PanelData.Decimals) Panel:HideWang() - Panel:SetDataVar(Variable, "OnValueChanged") - Panel:SetValueFunction(function() - local Value = math.Round(ACF.GetClientNumber(Variable), PanelData.Decimals) + Panel:SetClientData(Variable, "OnValueChanged") + Panel:DefineSetter(function(_, _, _, Value) + Value = math.Round(Value, PanelData.Decimals) ValuesData[Variable] = Value diff --git a/lua/acf/client/menu_items/weapons_menu.lua b/lua/acf/client/menu_items/weapons_menu.lua index 38a1de5c1..cad9bbfbf 100644 --- a/lua/acf/client/menu_items/weapons_menu.lua +++ b/lua/acf/client/menu_items/weapons_menu.lua @@ -23,21 +23,6 @@ local function CreateMenu(Menu) ACF.SetToolMode("acf_menu", "Main", "Spawner") - local function UpdateEntityData() - local Class = ClassList.Selected - local Data = EntList.Selected - - if not Class then return "" end - if not Data then return "" end - - local AmmoData = ACF.GetCurrentAmmoData() - local ReloadTime = AmmoData and (ACF.BaseReload + (AmmoData.ProjMass + AmmoData.PropMass) * ACF.MassToTime) or 60 - local Firerate = Data.Cyclic or 60 / ReloadTime - local Magazine = Data.MagSize and MagText:format(Data.MagSize, Data.MagReload) or "" - - return EntText:format(Data.Mass, math.Round(Firerate, 2), Class.Spread * 100, Magazine) - end - function ClassList:OnSelect(Index, _, Data) if self.Selected == Data then return end @@ -65,7 +50,6 @@ local function CreateMenu(Menu) ACF.SetClientData("Destiny", Data.Destiny or "Weapons") EntName:SetText(Data.Name) - EntData:SetText(UpdateEntityData()) EntPreview:SetModel(Data.Model) EntPreview:SetCamPos(Preview and Preview.Offset or Vector(45, 60, 45)) @@ -76,10 +60,23 @@ local function CreateMenu(Menu) ACF.UpdateAmmoMenu(Menu) end - EntData:TrackDataVar("Projectile", "SetText") - EntData:TrackDataVar("Propellant") - EntData:TrackDataVar("Tracer") - EntData:SetValueFunction(UpdateEntityData) + EntData:TrackClientData("Projectile", "SetText") + EntData:TrackClientData("Propellant") + EntData:TrackClientData("Tracer") + EntData:DefineSetter(function() + local Class = ClassList.Selected + local Data = EntList.Selected + + if not Class then return "" end + if not Data then return "" end + + local AmmoData = ACF.GetCurrentAmmoData() + local ReloadTime = AmmoData and (ACF.BaseReload + (AmmoData.ProjMass + AmmoData.PropMass) * ACF.MassToTime) or 60 + local Firerate = Data.Cyclic or 60 / ReloadTime + local Magazine = Data.MagSize and MagText:format(Data.MagSize, Data.MagReload) or "" + + return EntText:format(Data.Mass, math.Round(Firerate, 2), Class.Spread * 100, Magazine) + end) ACF.LoadSortedList(ClassList, Weapons, "Name") end diff --git a/lua/acf/shared/ammo_types/ap.lua b/lua/acf/shared/ammo_types/ap.lua index 60eff0973..febda14d2 100644 --- a/lua/acf/shared/ammo_types/ap.lua +++ b/lua/acf/shared/ammo_types/ap.lua @@ -218,9 +218,9 @@ else function Ammo:AddAmmoInformation(Base, ToolData, BulletData) local RoundStats = Base:AddLabel() - RoundStats:TrackDataVar("Projectile", "SetText") - RoundStats:TrackDataVar("Propellant") - RoundStats:SetValueFunction(function() + RoundStats:TrackClientData("Projectile", "SetText") + RoundStats:TrackClientData("Propellant") + RoundStats:DefineSetter(function() self:UpdateRoundData(ToolData, BulletData) local Text = "Muzzle Velocity : %s m/s\nProjectile Mass : %s\nPropellant Mass : %s" @@ -232,9 +232,9 @@ else end) local PenStats = Base:AddLabel() - PenStats:TrackDataVar("Projectile", "SetText") - PenStats:TrackDataVar("Propellant") - PenStats:SetValueFunction(function() + PenStats:TrackClientData("Projectile", "SetText") + PenStats:TrackClientData("Propellant") + PenStats:DefineSetter(function() self:UpdateRoundData(ToolData, BulletData) local Text = "Penetration : %s mm RHA\nAt 300m : %s mm RHA @ %s m/s\nAt 800m : %s mm RHA @ %s m/s" diff --git a/lua/acf/shared/ammo_types/aphe.lua b/lua/acf/shared/ammo_types/aphe.lua index b1d292bb3..a33cce93a 100644 --- a/lua/acf/shared/ammo_types/aphe.lua +++ b/lua/acf/shared/ammo_types/aphe.lua @@ -130,10 +130,12 @@ else function Ammo:AddAmmoControls(Base, ToolData, BulletData) local FillerMass = Base:AddSlider("Filler Volume", 0, BulletData.MaxFillerVol, 2) - FillerMass:SetDataVar("FillerMass", "OnValueChanged") - FillerMass:TrackDataVar("Projectile") - FillerMass:SetValueFunction(function(Panel) - ToolData.FillerMass = math.Round(ACF.GetClientNumber("FillerMass"), 2) + FillerMass:SetClientData("FillerMass", "OnValueChanged") + FillerMass:TrackClientData("Projectile") + FillerMass:DefineSetter(function(Panel, _, Key, Value) + if Key == "FillerMass" then + ToolData.FillerMass = math.Round(Value, 2) + end self:UpdateRoundData(ToolData, BulletData) @@ -146,10 +148,10 @@ else function Ammo:AddAmmoInformation(Base, ToolData, BulletData) local RoundStats = Base:AddLabel() - RoundStats:TrackDataVar("Projectile", "SetText") - RoundStats:TrackDataVar("Propellant") - RoundStats:TrackDataVar("FillerMass") - RoundStats:SetValueFunction(function() + RoundStats:TrackClientData("Projectile", "SetText") + RoundStats:TrackClientData("Propellant") + RoundStats:TrackClientData("FillerMass") + RoundStats:DefineSetter(function() self:UpdateRoundData(ToolData, BulletData) local Text = "Muzzle Velocity : %s m/s\nProjectile Mass : %s\nPropellant Mass : %s\nExplosive Mass : %s" @@ -162,8 +164,8 @@ else end) local FillerStats = Base:AddLabel() - FillerStats:TrackDataVar("FillerMass", "SetText") - FillerStats:SetValueFunction(function() + FillerStats:TrackClientData("FillerMass", "SetText") + FillerStats:DefineSetter(function() self:UpdateRoundData(ToolData, BulletData) local Text = "Blast Radius : %s m\nFragments : %s\nFragment Mass : %s\nFragment Velocity : %s m/s" @@ -175,10 +177,10 @@ else end) local PenStats = Base:AddLabel() - PenStats:TrackDataVar("Projectile", "SetText") - PenStats:TrackDataVar("Propellant") - PenStats:TrackDataVar("FillerMass") - PenStats:SetValueFunction(function() + PenStats:TrackClientData("Projectile", "SetText") + PenStats:TrackClientData("Propellant") + PenStats:TrackClientData("FillerMass") + PenStats:DefineSetter(function() self:UpdateRoundData(ToolData, BulletData) local Text = "Penetration : %s mm RHA\nAt 300m : %s mm RHA @ %s m/s\nAt 800m : %s mm RHA @ %s m/s" diff --git a/lua/acf/shared/ammo_types/fl.lua b/lua/acf/shared/ammo_types/fl.lua index c3311d58a..32f065945 100644 --- a/lua/acf/shared/ammo_types/fl.lua +++ b/lua/acf/shared/ammo_types/fl.lua @@ -182,9 +182,9 @@ else function Ammo:AddAmmoControls(Base, ToolData, BulletData) local Flechettes = Base:AddSlider("Flechette Amount", BulletData.MinFlechettes, BulletData.MaxFlechettes) - Flechettes:SetDataVar("Flechettes", "OnValueChanged") - Flechettes:SetValueFunction(function(Panel) - ToolData.Flechettes = math.floor(ACF.GetClientNumber("Flechettes")) + Flechettes:SetClientData("Flechettes", "OnValueChanged") + Flechettes:DefineSetter(function(Panel, _, _, Value) + ToolData.Flechettes = math.floor(Value) Ammo:UpdateRoundData(ToolData, BulletData) @@ -194,9 +194,9 @@ else end) local Spread = Base:AddSlider("Flechette Spread", BulletData.MinSpread, BulletData.MaxSpread, 2) - Spread:SetDataVar("Spread", "OnValueChanged") - Spread:SetValueFunction(function(Panel) - ToolData.Spread = ACF.GetClientNumber("Spread") + Spread:SetClientData("Spread", "OnValueChanged") + Spread:DefineSetter(function(Panel, _, _, Value) + ToolData.Spread = Value Ammo:UpdateRoundData(ToolData, BulletData) @@ -208,10 +208,10 @@ else function Ammo:AddAmmoInformation(Menu, ToolData, BulletData) local RoundStats = Menu:AddLabel() - RoundStats:TrackDataVar("Projectile", "SetText") - RoundStats:TrackDataVar("Propellant") - RoundStats:TrackDataVar("Flechettes") - RoundStats:SetValueFunction(function() + RoundStats:TrackClientData("Projectile", "SetText") + RoundStats:TrackClientData("Propellant") + RoundStats:TrackClientData("Flechettes") + RoundStats:DefineSetter(function() self:UpdateRoundData(ToolData, BulletData) local Text = "Muzzle Velocity : %s m/s\nProjectile Mass : %s\nPropellant Mass : %s\nFlechette Mass : %s" @@ -224,10 +224,10 @@ else end) local PenStats = Menu:AddLabel() - PenStats:TrackDataVar("Projectile", "SetText") - PenStats:TrackDataVar("Propellant") - PenStats:TrackDataVar("Flechettes") - PenStats:SetValueFunction(function() + PenStats:TrackClientData("Projectile", "SetText") + PenStats:TrackClientData("Propellant") + PenStats:TrackClientData("Flechettes") + PenStats:DefineSetter(function() self:UpdateRoundData(ToolData, BulletData) local Text = "Penetration : %s mm RHA\nAt 300m : %s mm RHA @ %s m/s\nAt 800m : %s mm RHA @ %s m/s" diff --git a/lua/acf/shared/ammo_types/he.lua b/lua/acf/shared/ammo_types/he.lua index 2795ecfa6..4e8bbeb80 100644 --- a/lua/acf/shared/ammo_types/he.lua +++ b/lua/acf/shared/ammo_types/he.lua @@ -110,10 +110,10 @@ else function Ammo:AddAmmoInformation(Base, ToolData, BulletData) local RoundStats = Base:AddLabel() - RoundStats:TrackDataVar("Projectile", "SetText") - RoundStats:TrackDataVar("Propellant") - RoundStats:TrackDataVar("FillerMass") - RoundStats:SetValueFunction(function() + RoundStats:TrackClientData("Projectile", "SetText") + RoundStats:TrackClientData("Propellant") + RoundStats:TrackClientData("FillerMass") + RoundStats:DefineSetter(function() self:UpdateRoundData(ToolData, BulletData) local Text = "Muzzle Velocity : %s m/s\nProjectile Mass : %s\nPropellant Mass : %s\nExplosive Mass : %s" @@ -126,8 +126,8 @@ else end) local FillerStats = Base:AddLabel() - FillerStats:TrackDataVar("FillerMass", "SetText") - FillerStats:SetValueFunction(function() + FillerStats:TrackClientData("FillerMass", "SetText") + FillerStats:DefineSetter(function() self:UpdateRoundData(ToolData, BulletData) local Text = "Blast Radius : %s m\nFragments : %s\nFragment Mass : %s\nFragment Velocity : %s m/s" diff --git a/lua/acf/shared/ammo_types/heat.lua b/lua/acf/shared/ammo_types/heat.lua index b745672da..dbcbbab16 100644 --- a/lua/acf/shared/ammo_types/heat.lua +++ b/lua/acf/shared/ammo_types/heat.lua @@ -307,10 +307,12 @@ else function Ammo:AddAmmoControls(Base, ToolData, BulletData) local LinerAngle = Base:AddSlider("Liner Angle", BulletData.MinConeAng, BulletData.MaxConeAng, 2) - LinerAngle:SetDataVar("LinerAngle", "OnValueChanged") - LinerAngle:TrackDataVar("Projectile") - LinerAngle:SetValueFunction(function(Panel) - ToolData.LinerAngle = math.Round(ACF.GetClientNumber("LinerAngle"), 2) + LinerAngle:SetClientData("LinerAngle", "OnValueChanged") + LinerAngle:TrackClientData("Projectile") + LinerAngle:DefineSetter(function(Panel, _, Key, Value) + if Key == "LinerAngle" then + ToolData.LinerAngle = math.Round(Value, 2) + end self:UpdateRoundData(ToolData, BulletData) @@ -321,11 +323,13 @@ else end) local FillerMass = Base:AddSlider("Filler Volume", 0, BulletData.MaxFillerVol, 2) - FillerMass:SetDataVar("FillerMass", "OnValueChanged") - FillerMass:TrackDataVar("Projectile") - FillerMass:TrackDataVar("LinerAngle") - FillerMass:SetValueFunction(function(Panel) - ToolData.FillerMass = math.Round(ACF.GetClientNumber("FillerMass"), 2) + FillerMass:SetClientData("FillerMass", "OnValueChanged") + FillerMass:TrackClientData("Projectile") + FillerMass:TrackClientData("LinerAngle") + FillerMass:DefineSetter(function(Panel, _, Key, Value) + if Key == "FillerMass" then + ToolData.FillerMass = math.Round(Value, 2) + end self:UpdateRoundData(ToolData, BulletData) @@ -338,11 +342,11 @@ else function Ammo:AddAmmoInformation(Base, ToolData, BulletData) local RoundStats = Base:AddLabel() - RoundStats:TrackDataVar("Projectile", "SetText") - RoundStats:TrackDataVar("Propellant") - RoundStats:TrackDataVar("FillerMass") - RoundStats:TrackDataVar("LinerAngle") - RoundStats:SetValueFunction(function() + RoundStats:TrackClientData("Projectile", "SetText") + RoundStats:TrackClientData("Propellant") + RoundStats:TrackClientData("FillerMass") + RoundStats:TrackClientData("LinerAngle") + RoundStats:DefineSetter(function() self:UpdateRoundData(ToolData, BulletData) local Text = "Muzzle Velocity : %s m/s\nProjectile Mass : %s\nPropellant Mass : %s\nExplosive Mass : %s" @@ -355,9 +359,9 @@ else end) local FillerStats = Base:AddLabel() - FillerStats:TrackDataVar("FillerMass", "SetText") - FillerStats:TrackDataVar("LinerAngle") - FillerStats:SetValueFunction(function() + FillerStats:TrackClientData("FillerMass", "SetText") + FillerStats:TrackClientData("LinerAngle") + FillerStats:DefineSetter(function() self:UpdateRoundData(ToolData, BulletData) local Text = "Blast Radius : %s m\nFragments : %s\nFragment Mass : %s\nFragment Velocity : %s m/s" @@ -369,11 +373,11 @@ else end) local Penetrator = Base:AddLabel() - Penetrator:TrackDataVar("Projectile", "SetText") - Penetrator:TrackDataVar("Propellant") - Penetrator:TrackDataVar("FillerMass") - Penetrator:TrackDataVar("LinerAngle") - Penetrator:SetValueFunction(function() + Penetrator:TrackClientData("Projectile", "SetText") + Penetrator:TrackClientData("Propellant") + Penetrator:TrackClientData("FillerMass") + Penetrator:TrackClientData("LinerAngle") + Penetrator:DefineSetter(function() self:UpdateRoundData(ToolData, BulletData) local Text = "Penetrator Caliber : %s mm\nPenetrator Mass : %s\nPenetrator Velocity : %s m/s" @@ -385,11 +389,11 @@ else end) local PenStats = Base:AddLabel() - PenStats:TrackDataVar("Projectile", "SetText") - PenStats:TrackDataVar("Propellant") - PenStats:TrackDataVar("FillerMass") - PenStats:TrackDataVar("LinerAngle") - PenStats:SetValueFunction(function() + PenStats:TrackClientData("Projectile", "SetText") + PenStats:TrackClientData("Propellant") + PenStats:TrackClientData("FillerMass") + PenStats:TrackClientData("LinerAngle") + PenStats:DefineSetter(function() self:UpdateRoundData(ToolData, BulletData) local Text = "Penetration : %s mm RHA\nAt 300m : %s mm RHA @ %s m/s\nAt 800m : %s mm RHA @ %s m/s" diff --git a/lua/acf/shared/ammo_types/hp.lua b/lua/acf/shared/ammo_types/hp.lua index 69829b3b0..8523ebaf1 100644 --- a/lua/acf/shared/ammo_types/hp.lua +++ b/lua/acf/shared/ammo_types/hp.lua @@ -106,10 +106,12 @@ else function Ammo:AddAmmoControls(Base, ToolData, BulletData) local HollowCavity = Base:AddSlider("Cavity Volume", BulletData.MinCavVol, BulletData.MaxCavVol, 2) - HollowCavity:SetDataVar("HollowCavity", "OnValueChanged") - HollowCavity:TrackDataVar("Projectile") - HollowCavity:SetValueFunction(function(Panel) - ToolData.HollowCavity = math.Round(ACF.GetClientNumber("HollowCavity"), 2) + HollowCavity:SetClientData("HollowCavity", "OnValueChanged") + HollowCavity:TrackClientData("Projectile") + HollowCavity:DefineSetter(function(Panel, _, Key, Value) + if Key == "HollowCavity" then + ToolData.HollowCavity = math.Round(Value, 2) + end self:UpdateRoundData(ToolData, BulletData) @@ -122,10 +124,10 @@ else function Ammo:AddAmmoInformation(Base, ToolData, BulletData) local RoundStats = Base:AddLabel() - RoundStats:TrackDataVar("Projectile", "SetText") - RoundStats:TrackDataVar("Propellant") - RoundStats:TrackDataVar("HollowCavity") - RoundStats:SetValueFunction(function() + RoundStats:TrackClientData("Projectile", "SetText") + RoundStats:TrackClientData("Propellant") + RoundStats:TrackClientData("HollowCavity") + RoundStats:DefineSetter(function() self:UpdateRoundData(ToolData, BulletData) local Text = "Muzzle Velocity : %s m/s\nProjectile Mass : %s\nPropellant Mass : %s" @@ -137,10 +139,10 @@ else end) local HollowStats = Base:AddLabel() - HollowStats:TrackDataVar("Projectile", "SetText") - HollowStats:TrackDataVar("Propellant") - HollowStats:TrackDataVar("HollowCavity") - HollowStats:SetValueFunction(function() + HollowStats:TrackClientData("Projectile", "SetText") + HollowStats:TrackClientData("Propellant") + HollowStats:TrackClientData("HollowCavity") + HollowStats:DefineSetter(function() self:UpdateRoundData(ToolData, BulletData) local Text = "Expanded Caliber : %s mm\nTransfered Energy : %s KJ" @@ -151,10 +153,10 @@ else end) local PenStats = Base:AddLabel() - PenStats:TrackDataVar("Projectile", "SetText") - PenStats:TrackDataVar("Propellant") - PenStats:TrackDataVar("HollowCavity") - PenStats:SetValueFunction(function() + PenStats:TrackClientData("Projectile", "SetText") + PenStats:TrackClientData("Propellant") + PenStats:TrackClientData("HollowCavity") + PenStats:DefineSetter(function() self:UpdateRoundData(ToolData, BulletData) local Text = "Penetration : %s mm RHA\nAt 300m : %s mm RHA @ %s m/s\nAt 800m : %s mm RHA @ %s m/s" diff --git a/lua/acf/shared/ammo_types/smoke.lua b/lua/acf/shared/ammo_types/smoke.lua index 461b742c7..c0bbfe649 100644 --- a/lua/acf/shared/ammo_types/smoke.lua +++ b/lua/acf/shared/ammo_types/smoke.lua @@ -190,14 +190,16 @@ else function Ammo:AddAmmoControls(Base, ToolData, BulletData) local SmokeFiller = Base:AddSlider("Smoke Filler", BulletData.MinFillerVol, BulletData.MaxFillerVol, 2) - SmokeFiller:SetDataVar("SmokeFiller", "OnValueChanged") - SmokeFiller:TrackDataVar("Projectile") - SmokeFiller:TrackDataVar("WPFiller") - SmokeFiller:SetValueFunction(function(Panel, IsTracked) - ToolData.SmokeFiller = math.Round(ACF.GetClientNumber("SmokeFiller"), 2) - - if not IsTracked then - BulletData.FillerPriority = "Smoke" + SmokeFiller:SetClientData("SmokeFiller", "OnValueChanged") + SmokeFiller:TrackClientData("Projectile") + SmokeFiller:TrackClientData("WPFiller") + SmokeFiller:DefineSetter(function(Panel, _, Key, Value, IsTracked) + if Key == "SmokeFiller" then + ToolData.SmokeFiller = math.Round(Value, 2) + + if not IsTracked then + BulletData.FillerPriority = "Smoke" + end end self:UpdateRoundData(ToolData, BulletData) @@ -209,14 +211,16 @@ else end) local WPFiller = Base:AddSlider("WP Filler", BulletData.MinFillerVol, BulletData.MaxFillerVol, 2) - WPFiller:SetDataVar("WPFiller", "OnValueChanged") - WPFiller:TrackDataVar("SmokeFiller") - WPFiller:TrackDataVar("Projectile") - WPFiller:SetValueFunction(function(Panel, IsTracked) - ToolData.WPFiller = math.Round(ACF.GetClientNumber("WPFiller"), 2) - - if not IsTracked then - BulletData.FillerPriority = "WP" + WPFiller:SetClientData("WPFiller", "OnValueChanged") + WPFiller:TrackClientData("SmokeFiller") + WPFiller:TrackClientData("Projectile") + WPFiller:DefineSetter(function(Panel, _, Key, Value, IsTracked) + if Key == "WPFiller" then + ToolData.WPFiller = math.Round(Value, 2) + + if not IsTracked then + BulletData.FillerPriority = "WP" + end end self:UpdateRoundData(ToolData, BulletData) @@ -230,11 +234,11 @@ else function Ammo:AddAmmoInformation(Menu, ToolData, Data) local RoundStats = Menu:AddLabel() - RoundStats:TrackDataVar("Projectile", "SetText") - RoundStats:TrackDataVar("Propellant") - RoundStats:TrackDataVar("SmokeFiller") - RoundStats:TrackDataVar("WPFiller") - RoundStats:SetValueFunction(function() + RoundStats:TrackClientData("Projectile", "SetText") + RoundStats:TrackClientData("Propellant") + RoundStats:TrackClientData("SmokeFiller") + RoundStats:TrackClientData("WPFiller") + RoundStats:DefineSetter(function() self:UpdateRoundData(ToolData, Data) local Text = "Muzzle Velocity : %s m/s\nProjectile Mass : %s\nPropellant Mass : %s" @@ -246,9 +250,9 @@ else end) local SmokeStats = Menu:AddLabel() - SmokeStats:TrackDataVar("SmokeFiller", "SetText") - SmokeStats:TrackDataVar("WPFiller") - SmokeStats:SetValueFunction(function() + SmokeStats:TrackClientData("SmokeFiller", "SetText") + SmokeStats:TrackClientData("WPFiller") + SmokeStats:DefineSetter(function() self:UpdateRoundData(ToolData, Data) local SMText, WPText = "", "" From a4b4d1c4a23f90f4dd9c20e07c707f405d1d38c7 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sat, 19 Dec 2020 19:25:16 -0300 Subject: [PATCH 222/279] Added DataVar persistence function - Added clientside ACF.PersistClientData and serverside ACF.PersistServerData function to define whether a data variable should be persisted among restarts. - Added shared ACF.FolderExists function to check if a given folder path exists, optionally giving the option to create it. - Added shared ACF.SaveToJSON function to simplify the process of saving JSON data to a file. - Added shared ACF.LoadFromFile function to help load JSON files into a Lua table. --- lua/acf/base/data_vars/sh_data_vars.lua | 74 ++++++++++++++++++++++++- lua/acf/base/util/sh_util.lua | 39 +++++++++++++ 2 files changed, 112 insertions(+), 1 deletion(-) diff --git a/lua/acf/base/data_vars/sh_data_vars.lua b/lua/acf/base/data_vars/sh_data_vars.lua index 98174f330..feb02ae0e 100644 --- a/lua/acf/base/data_vars/sh_data_vars.lua +++ b/lua/acf/base/data_vars/sh_data_vars.lua @@ -52,4 +52,76 @@ do -- Server data getter functions ACF.GetServerData = GetData ACF.GetServerRaw = GetData -end \ No newline at end of file +end + +do -- Data persisting + ACF.PersistedKeys = ACF.PersistedKeys or {} + ACF.PersistedData = ACF.PersistedData or {} + + local Data = ACF.PersistedData + local Keys = ACF.PersistedKeys + local Realm = SERVER and "Server" or "Client" + local Values = ACF[Realm .. "Data"] + local Folder = "acf/data_vars" + local File = "persisted.json" + + local function LoadData() + local Saved = ACF.LoadFromFile(Folder, File) + + if Saved then + local SetFunction = ACF["Set" .. Realm .. "Data"] + + for Key, Value in pairs(Saved) do + Keys[Key] = true + + if Value ~= "nil" then + SetFunction(Key, Value) + end + end + end + + hook.Remove("Initialize", "ACF Load Persisted Data") + end + + local function StoreData() + local Result = {} + + for Key in pairs(Keys) do + local Value = Data[Key] + + Result[Key] = Either(Value ~= nil, Value, "nil") + end + + ACF.SaveToJSON(Folder, File, Result, true) + end + + local function UpdateData(Key) + if not Keys[Key] then return end + if Values[Key] == nil then return end + + local Value = Values[Key] + + if Data[Key] ~= Value then + Data[Key] = Value + + if timer.Exists("ACF Store Persisted") then return end + + timer.Create("ACF Store Persisted", 1, 1, StoreData) + end + end + + ACF["Persist" .. Realm .. "Data"] = function(Key) + if not ACF.CheckString(Key) then return end + if Keys[Key] then return end -- Already stored + + Keys[Key] = true + + UpdateData(Key) + end + + hook.Add("ACF_On" .. Realm .. "DataUpdate", "ACF Persisted Data", function(_, Key) + UpdateData(Key) + end) + + hook.Add("Initialize", "ACF Load Persisted Data", LoadData) +end diff --git a/lua/acf/base/util/sh_util.lua b/lua/acf/base/util/sh_util.lua index b56430dbf..b181e3695 100644 --- a/lua/acf/base/util/sh_util.lua +++ b/lua/acf/base/util/sh_util.lua @@ -556,3 +556,42 @@ do -- Attachment storage return 0 end end + +do -- File creation + function ACF.FolderExists(Path, Create) + if not ACF.CheckString(Path) then return end + + local Exists = file.Exists(Path, "DATA") + + if not Exists and Create then + file.CreateDir(Path) + + return true + end + + return Exists + end + + function ACF.SaveToJSON(Path, Name, Table, GoodFormat) + if not ACF.CheckString(Path) then return end + if not ACF.CheckString(Name) then return end + if not istable(Table) then return end + + ACF.FolderExists(Path, true) -- Creating the folder if it doesn't exist + + local FullPath = Path .. "/" .. Name + + file.Write(FullPath, util.TableToJSON(Table, GoodFormat)) + end + + function ACF.LoadFromFile(Path, Name) + if not ACF.CheckString(Path) then return end + if not ACF.CheckString(Name) then return end + + local FullPath = Path .. "/" .. Name + + if not file.Exists(FullPath, "DATA") then return end + + return util.JSONToTable(file.Read(FullPath, "DATA")) + end +end From 9090a582701eca442460a75b45d2ff91e9688b17 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sun, 20 Dec 2020 00:59:59 -0300 Subject: [PATCH 223/279] Added default value to persisted data vars - Persisted data vars can now store a default value, which will be set on the second argument of ACF.PersistClientData or ACF.PersistServerData. - Persisted DataVar info will now be saved on a file named stored.json instead of persisted.json. --- lua/acf/base/data_vars/sh_data_vars.lua | 56 +++++++++++++++---------- 1 file changed, 34 insertions(+), 22 deletions(-) diff --git a/lua/acf/base/data_vars/sh_data_vars.lua b/lua/acf/base/data_vars/sh_data_vars.lua index feb02ae0e..406b9b185 100644 --- a/lua/acf/base/data_vars/sh_data_vars.lua +++ b/lua/acf/base/data_vars/sh_data_vars.lua @@ -58,12 +58,13 @@ do -- Data persisting ACF.PersistedKeys = ACF.PersistedKeys or {} ACF.PersistedData = ACF.PersistedData or {} - local Data = ACF.PersistedData - local Keys = ACF.PersistedKeys - local Realm = SERVER and "Server" or "Client" - local Values = ACF[Realm .. "Data"] - local Folder = "acf/data_vars" - local File = "persisted.json" + local Persist = ACF.PersistedData + local Keys = ACF.PersistedKeys + local Realm = SERVER and "Server" or "Client" + local Values = ACF[Realm .. "Data"] + local Folder = "acf/data_vars" + local File = "stored.json" + local Loaded = false local function LoadData() local Saved = ACF.LoadFromFile(Folder, File) @@ -71,50 +72,61 @@ do -- Data persisting if Saved then local SetFunction = ACF["Set" .. Realm .. "Data"] - for Key, Value in pairs(Saved) do - Keys[Key] = true + for Key, Stored in pairs(Saved) do + if Keys[Key] == nil then + Keys[Key] = Stored.Default + end - if Value ~= "nil" then - SetFunction(Key, Value) + if Stored.Value ~= "nil" then + SetFunction(Key, Stored.Value) end end end + Loaded = true + hook.Remove("Initialize", "ACF Load Persisted Data") end local function StoreData() local Result = {} - for Key in pairs(Keys) do - local Value = Data[Key] + for Key, Default in pairs(Keys) do + local Value = Persist[Key] - Result[Key] = Either(Value ~= nil, Value, "nil") + Result[Key] = { + Value = Value, + Default = Default, + } end ACF.SaveToJSON(Folder, File, Result, true) end local function UpdateData(Key) - if not Keys[Key] then return end - if Values[Key] == nil then return end + if Keys[Key] == nil then return end - local Value = Values[Key] + local Default = Keys[Key] + local Value = Either(Values[Key] ~= nil, Values[Key], Default) - if Data[Key] ~= Value then - Data[Key] = Value + if Persist[Key] ~= Value then + Persist[Key] = Value - if timer.Exists("ACF Store Persisted") then return end + if not Loaded or timer.Exists("ACF Store Persisted") then return end timer.Create("ACF Store Persisted", 1, 1, StoreData) end end - ACF["Persist" .. Realm .. "Data"] = function(Key) + --- Generates the following functions: + -- ACF.PersistServerData(Key, Default) - Serverside only + -- ACF.PersistClientData(Key, Default) - Clientside only + + ACF["Persist" .. Realm .. "Data"] = function(Key, Default) if not ACF.CheckString(Key) then return end - if Keys[Key] then return end -- Already stored + if Default == nil then Default = "nil" end - Keys[Key] = true + Keys[Key] = Default UpdateData(Key) end From a91e5a3cfd38750a1167dffe96ef1ed1d828bfcb Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sun, 20 Dec 2020 18:22:00 -0300 Subject: [PATCH 224/279] Partial fix to HEAT round penetration difference - Partially fixed HEAT rounds getting different penetration values than the ones shown on the menu. There's still a difference of about 10% less penetration than the one shown on the menu. --- lua/acf/server/ballistics.lua | 4 ++-- lua/acf/server/damage.lua | 1 - lua/acf/shared/ammo_types/heat.lua | 34 ++++++++++++++++-------------- 3 files changed, 20 insertions(+), 19 deletions(-) diff --git a/lua/acf/server/ballistics.lua b/lua/acf/server/ballistics.lua index a3367e676..b30fbbc8f 100644 --- a/lua/acf/server/ballistics.lua +++ b/lua/acf/server/ballistics.lua @@ -326,9 +326,9 @@ do -- Terminal ballistics -------------------------- end function ACF_RoundImpact(Bullet, Speed, Energy, Target, HitPos, HitNormal, Bone) - local HitAngle = ACF_GetHitAngle(HitNormal , Bullet.Flight) + local HitAngle = ACF_GetHitAngle(HitNormal, Bullet.Flight) - local HitRes = ACF_Damage ( --DAMAGE !! + local HitRes = ACF_Damage( -- DAMAGE!! Target, Energy, Bullet.PenArea, diff --git a/lua/acf/server/damage.lua b/lua/acf/server/damage.lua index b8afec6b4..b2fa05140 100644 --- a/lua/acf/server/damage.lua +++ b/lua/acf/server/damage.lua @@ -20,7 +20,6 @@ local function CalcDamage(Entity, Energy, FrArea, Angle) local maxPenetration = (Energy.Penetration / FrArea) * ACF.KEtoRHA --RHA Penetration local HitRes = {} - -- Projectile caliber. Messy, function signature local caliber = 20 * (FrArea ^ (1 / ACF.PenAreaMod) / 3.1416) ^ 0.5 -- Breach probability diff --git a/lua/acf/shared/ammo_types/heat.lua b/lua/acf/shared/ammo_types/heat.lua index dbcbbab16..d45e147fe 100644 --- a/lua/acf/shared/ammo_types/heat.lua +++ b/lua/acf/shared/ammo_types/heat.lua @@ -38,14 +38,14 @@ end -- coneang now required for slug recalculation at detonation, defaults to 55 if not present function Ammo:CalcSlugMV(Data, HEATFillerMass) --keep fillermass/2 so that penetrator stays the same. - return (HEATFillerMass * 0.5 * ACF.HEPower * math.sin(math.rad(10 + (Data.ConeAng or 55)) * 0.5) / Data.SlugMass) ^ ACF.HEATMVScale + return (HEATFillerMass * 0.5 * ACF.HEPower * math.sin(math.rad(10 + Data.ConeAng) * 0.5) / Data.SlugMass) ^ ACF.HEATMVScale end function Ammo:GetDisplayData(Data) local Crushed, HEATFiller, BoomFiller = self:CrushCalc(Data.MuzzleVel, Data.FillerMass) local SlugMV = self:CalcSlugMV(Data, HEATFiller) * (Data.SlugPenMul or 1) local MassUsed = Data.SlugMass * (1 - Crushed) - local Energy = ACF_Kinetic(Data.MuzzleVel * 39.37 + SlugMV * 39.37, MassUsed, 999999) + local Energy = ACF_Kinetic(SlugMV * 39.37, MassUsed, 999999) local FragMass = Data.CasingMass + Data.SlugMass * Crushed local Fragments = math.max(math.floor((BoomFiller / FragMass) * ACF.HEFrag), 2) local Display = { @@ -188,14 +188,17 @@ if SERVER then if Crushed == 1 then return false end -- no HEAT jet to fire off, it was all converted to HE + local SlugMV = self:CalcSlugMV(Bullet, HEATFillerMass) * 39.37 * (Bullet.SlugPenMul or 1) + Bullet.Detonated = true - Bullet.Flight = Bullet.Flight:GetNormalized() * self:CalcSlugMV(Bullet, HEATFillerMass) * 39.37 + Bullet.Flight = Bullet.Flight:GetNormalized() * SlugMV Bullet.NextPos = HitPos Bullet.DragCoef = Bullet.SlugDragCoef Bullet.ProjMass = Bullet.SlugMass * (1 - Crushed) Bullet.Caliber = Bullet.SlugCaliber Bullet.PenArea = Bullet.SlugPenArea Bullet.Ricochet = Bullet.SlugRicochet + Bullet.LimitVel = 999999 return true end @@ -209,16 +212,18 @@ if SERVER then local HitNormal = Trace.HitNormal local Bone = Trace.HitGroup + -- TODO: Figure out why bullets are missing 10% of their penetration if Bullet.Detonated then - Bullet.NotFirstPen = true + local Multiplier = Bullet.NotFirstPen and ACF.HEATPenLayerMul or 1 + local Energy = ACF_Kinetic(Speed, Bullet.ProjMass, Bullet.LimitVel) + local HitRes = ACF_RoundImpact(Bullet, Speed, Energy, Target, HitPos, HitNormal, Bone) - local Energy = ACF_Kinetic(Speed, Bullet.ProjMass, 999999) - local HitRes = ACF_RoundImpact(Bullet, Speed, Energy, Target, HitPos, HitNormal, Bone) + Bullet.NotFirstPen = true if HitRes.Overkill > 0 then table.insert(Bullet.Filter, Target) --"Penetrate" (Ingoring the prop for the retry trace) - Bullet.Flight = Bullet.Flight:GetNormalized() * math.sqrt(Energy.Kinetic * (1 - HitRes.Loss) * ((Bullet.NotFirstPen and ACF.HEATPenLayerMul) or 1) * 2000 / Bullet.ProjMass) * 39.37 + Bullet.Flight = Bullet.Flight:GetNormalized() * math.sqrt(Energy.Kinetic * (1 - HitRes.Loss) * Multiplier * 2000 / Bullet.ProjMass) * 39.37 return "Penetrated" else @@ -383,7 +388,7 @@ else local Text = "Penetrator Caliber : %s mm\nPenetrator Mass : %s\nPenetrator Velocity : %s m/s" local Caliber = math.Round(BulletData.SlugCaliber * 10, 2) local Mass = ACF.GetProperMass(BulletData.SlugMassUsed) - local Velocity = math.Round(BulletData.MuzzleVel + BulletData.SlugMV, 2) + local Velocity = math.Round(BulletData.SlugMV, 2) return Text:format(Caliber, Mass, Velocity) end) @@ -396,15 +401,12 @@ else PenStats:DefineSetter(function() self:UpdateRoundData(ToolData, BulletData) - local Text = "Penetration : %s mm RHA\nAt 300m : %s mm RHA @ %s m/s\nAt 800m : %s mm RHA @ %s m/s" - local MaxPen = math.Round(BulletData.MaxPen, 2) - local R1V, R1P = ACF.PenRanging(BulletData.MuzzleVel, BulletData.DragCoef, BulletData.ProjMass, BulletData.PenArea, BulletData.LimitVel, 300) - local R2V, R2P = ACF.PenRanging(BulletData.MuzzleVel, BulletData.DragCoef, BulletData.ProjMass, BulletData.PenArea, BulletData.LimitVel, 800) - - R1P = math.Round((ACF_Kinetic((R1V + BulletData.SlugMV) * 39.37, BulletData.SlugMassUsed, 999999).Penetration / BulletData.SlugPenArea) * ACF.KEtoRHA, 2) - R2P = math.Round((ACF_Kinetic((R2V + BulletData.SlugMV) * 39.37, BulletData.SlugMassUsed, 999999).Penetration / BulletData.SlugPenArea) * ACF.KEtoRHA, 2) + local Text = "Penetration : %s mm RHA\nAt 300m : %s mm RHA @ %s m/s\nAt 800m : %s mm RHA @ %s m/s" + local MaxPen = math.Round(BulletData.MaxPen, 2) + local R1V = ACF.PenRanging(BulletData.MuzzleVel, BulletData.DragCoef, BulletData.ProjMass, BulletData.PenArea, BulletData.LimitVel, 300) + local R2V = ACF.PenRanging(BulletData.MuzzleVel, BulletData.DragCoef, BulletData.ProjMass, BulletData.PenArea, BulletData.LimitVel, 800) - return Text:format(MaxPen, R1P, R1V, R2P, R2V) + return Text:format(MaxPen, MaxPen, R1V, MaxPen, R2V) end) Base:AddLabel("Note: The penetration range data is an approximation and may not be entirely accurate.") From 092ad0ec39c2721622db08be6b5109a120d2c243 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Mon, 21 Dec 2020 06:15:53 -0300 Subject: [PATCH 225/279] Replaced isstring with ACF.CheckString - Replaced a few cases where isstring, which can throw errors if a nil value is given, was used instead of ACF.CheckString. --- lua/acf/base/data_vars/cl_data_vars.lua | 4 ++-- lua/acf/base/data_vars/sv_data_vars.lua | 2 +- lua/acf/base/sh_classes.lua | 10 ++++++---- lua/acf/base/sh_tool_functions.lua | 8 +++++--- lua/acf/base/util/sv_util.lua | 6 ++++-- 5 files changed, 18 insertions(+), 12 deletions(-) diff --git a/lua/acf/base/data_vars/cl_data_vars.lua b/lua/acf/base/data_vars/cl_data_vars.lua index 9fd9cc315..405c8fdd0 100644 --- a/lua/acf/base/data_vars/cl_data_vars.lua +++ b/lua/acf/base/data_vars/cl_data_vars.lua @@ -133,7 +133,7 @@ end do -- Client data setter function function ACF.SetClientData(Key, Value, Forced) - if not isstring(Key) then return end + if not ACF.CheckString(Key) then return end Value = Value or false @@ -149,7 +149,7 @@ end do -- Server data setter function function ACF.SetServerData(Key, Value, Forced) - if not isstring(Key) then return end + if not ACF.CheckString(Key) then return end local Player = LocalPlayer() diff --git a/lua/acf/base/data_vars/sv_data_vars.lua b/lua/acf/base/data_vars/sv_data_vars.lua index c04293e04..c444d8676 100644 --- a/lua/acf/base/data_vars/sv_data_vars.lua +++ b/lua/acf/base/data_vars/sv_data_vars.lua @@ -180,7 +180,7 @@ end do -- Server data setter function function ACF.SetServerData(Key, Value, Forced) - if not isstring(Key) then return end + if not ACF.CheckString(Key) then return end Value = Value or false diff --git a/lua/acf/base/sh_classes.lua b/lua/acf/base/sh_classes.lua index c03234da2..38d0f735f 100644 --- a/lua/acf/base/sh_classes.lua +++ b/lua/acf/base/sh_classes.lua @@ -1,3 +1,5 @@ +local ACF = ACF + do -- Basic class registration functions function ACF.AddSimpleClass(ID, Destiny, Data) if not ID then return end @@ -474,7 +476,7 @@ do -- Entity class registration function end function ACF.RegisterEntityClass(Class, Function, ...) - if not isstring(Class) then return end + if not ACF.CheckString(Class) then return end if not isfunction(Function) then return end local Entity = GetEntityTable(Class) @@ -487,7 +489,7 @@ do -- Entity class registration function end function ACF.AddEntityArguments(Class, ...) - if not isstring(Class) then return end + if not ACF.CheckString(Class) then return end local Entity = GetEntityTable(Class) local Arguments = istable(...) and ... or { ... } @@ -505,7 +507,7 @@ do -- Entity class registration function end function ACF.GetEntityArguments(Class) - if not isstring(Class) then return end + if not ACF.CheckString(Class) then return end local Entity = GetEntityTable(Class) local List = {} @@ -518,7 +520,7 @@ do -- Entity class registration function end function ACF.CreateEntity(Class, Player, Position, Angles, Data, NoUndo) - if not isstring(Class) then return false end + if not ACF.CheckString(Class) then return false end local ClassData = ACF.GetEntityClass(Class) diff --git a/lua/acf/base/sh_tool_functions.lua b/lua/acf/base/sh_tool_functions.lua index b9db0e5e8..c1dd2612e 100644 --- a/lua/acf/base/sh_tool_functions.lua +++ b/lua/acf/base/sh_tool_functions.lua @@ -1,3 +1,5 @@ +local ACF = ACF + ACF.Tools = ACF.Tools or {} local Tools = ACF.Tools @@ -369,9 +371,9 @@ do -- Clientside Tool interaction local Value = "%s:%s" function ACF.SetToolMode(Tool, Stage, Op) - if not isstring(Tool) then return end - if not isstring(Stage) then return end - if not isstring(Op) then return end + if not ACF.CheckString(Tool) then return end + if not ACF.CheckString(Stage) then return end + if not ACF.CheckString(Op) then return end ACF.SetClientData(Key:format(Tool), Value:format(Stage, Op)) end diff --git a/lua/acf/base/util/sv_util.lua b/lua/acf/base/util/sv_util.lua index b5ea83b0e..8009b6b6f 100644 --- a/lua/acf/base/util/sv_util.lua +++ b/lua/acf/base/util/sv_util.lua @@ -1,3 +1,5 @@ +local ACF = ACF + do -- Serverside console log messages local Types = { Normal = { @@ -284,7 +286,7 @@ do -- Extra overlay text local Classes = {} function ACF.RegisterOverlayText(ClassName, Identifier, Function) - if not isstring(ClassName) then return end + if not ACF.CheckString(ClassName) then return end if Identifier == nil then return end if not isfunction(Function) then return end @@ -300,7 +302,7 @@ do -- Extra overlay text end function ACF.RemoveOverlayText(ClassName, Identifier) - if not isstring(ClassName) then return end + if not ACF.CheckString(ClassName) then return end if Identifier == nil then return end local Class = Classes[ClassName] From a08830b89536ec8b07fa2dde1f823eaad7b73179 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Tue, 22 Dec 2020 18:20:45 -0300 Subject: [PATCH 226/279] Updated ACF.CreateEntity and added ACF.UpdateEntity - Updated ACF.CreateEntity to return a message if the entity couldn't be created. - Added ACF.UpdateEntity to prevent the incorrect use of ENT:Update. --- lua/acf/base/sh_classes.lua | 41 ++++++++++++--------- lua/acf/shared/tool_operations/acf_copy.lua | 2 +- lua/acf/shared/tool_operations/acf_menu.lua | 34 +++++++++-------- 3 files changed, 42 insertions(+), 35 deletions(-) diff --git a/lua/acf/base/sh_classes.lua b/lua/acf/base/sh_classes.lua index 38d0f735f..0cb645949 100644 --- a/lua/acf/base/sh_classes.lua +++ b/lua/acf/base/sh_classes.lua @@ -524,24 +524,16 @@ do -- Entity class registration function local ClassData = ACF.GetEntityClass(Class) - if not ClassData then - ACF.SendMessage(Player, "Error", Class, " is not a registered ACF entity class.") - return false - end + if not ClassData then return false, Class .. " is not a registered ACF entity class." end + if not ClassData.Spawn then return false, Class .. " doesn't have a spawn function assigned to it." end - if not ClassData.Spawn then - ACF.SendMessage(Player, "Error", Class, " doesn't have a spawn function assigned to it.") - return false - end + local HookResult, HookMessage = hook.Run("ACF_CanCreateEntity", Class, Player, Position, Angles, Data) - local Entity = ClassData.Spawn(Player, Position, Angles, Data) + if HookResult == false then return false, HookMessage end - if not IsValid(Entity) then - ACF.SendMessage(Player, "Error", Class, " entity couldn't be created.") - return false - end + local Entity = ClassData.Spawn(Player, Position, Angles, Data) - local PhysObj = Entity:GetPhysicsObject() + if not IsValid(Entity) then return false, "The spawn function for" .. Class .. " didn't return a value entity." end Entity:Activate() @@ -549,10 +541,6 @@ do -- Entity class registration function Entity:CPPISetOwner(Player) end - if IsValid(PhysObj) then - PhysObj:EnableMotion(false) - end - if not NoUndo then undo.Create(Entity.Name or Class) undo.AddEntity(Entity) @@ -562,6 +550,23 @@ do -- Entity class registration function return true, Entity end + + function ACF.UpdateEntity(Entity, Data) + if not IsValid(Entity) then return false, "Can't update invalid entities." end + if not isfunction(Entity.Update) then return false, "This entity does not support updating." end + + Data = istable(Data) and Data or {} + + local HookResult, HookMessage = hook.Run("ACF_CanUpdateEntity", Entity, Data) + + if HookResult == false then return false, "Couldn't update entity: " .. HookMessage end + + local Result, Message = Entity:Update(Data) + + if not Result then Message = "Couldn't update entity: " .. Message end + + return Result, Message + end end do -- Discontinued functions diff --git a/lua/acf/shared/tool_operations/acf_copy.lua b/lua/acf/shared/tool_operations/acf_copy.lua index c7341efba..94f8b5830 100644 --- a/lua/acf/shared/tool_operations/acf_copy.lua +++ b/lua/acf/shared/tool_operations/acf_copy.lua @@ -108,7 +108,7 @@ ACF.RegisterOperation("acfcopy", "Main", "CopyPaste", { Data[K] = Value end - local Result, Message = Entity:Update(Data) + local Result, Message = ACF.UpdateEntity(Entity, Data) if not Result then Message = "Couldn't update entity: " .. Message diff --git a/lua/acf/shared/tool_operations/acf_menu.lua b/lua/acf/shared/tool_operations/acf_menu.lua index 9f11ed2dc..b715827c7 100644 --- a/lua/acf/shared/tool_operations/acf_menu.lua +++ b/lua/acf/shared/tool_operations/acf_menu.lua @@ -39,18 +39,10 @@ local function SelectEntity(Tool, Player, Entity) end) end -local function CanTool(Player, Entity) - if not IsValid(Entity) then return false end - if CPPI then return Entity:CPPICanTool(Player, "acf_menu") end - - return hook.Run("CanTool", Player, { Hit = true, Entity = Entity }, "acf_menu") -end - do -- Spawner operation - local function CanUpdate(Player, Entity, ClassName) - if not CanTool(Player, Entity) then return false end + local function CanUpdate(Entity, ClassName) + if not IsValid(Entity) then return false end if Entity:GetClass() ~= ClassName then return false end - if not isfunction(Entity.Update) then return false end return true end @@ -60,10 +52,11 @@ do -- Spawner operation local Entity = Trace.Entity - if CanUpdate(Player, Entity, ClassName) then - local Result, Message = Entity:Update(Data) + if CanUpdate(Entity, ClassName) then + local Result, Message = ACF.UpdateEntity(Entity, Data) ACF.SendMessage(Player, Result and "Info" or "Error", Message) + return true end @@ -72,10 +65,19 @@ do -- Spawner operation local Position = Trace.HitPos + Trace.HitNormal * 128 local Angles = Trace.HitNormal:Angle():Up():Angle() - local Success, NewEntity = ACF.CreateEntity(ClassName, Player, Position, Angles, Data) + + local Success, Result = ACF.CreateEntity(ClassName, Player, Position, Angles, Data) if Success then - NewEntity:DropToFloor() + local PhysObj = Result:GetPhysicsObject() + + Result:DropToFloor() + + if IsValid(PhysObj) then + PhysObj:EnableMotion(false) + end + else + ACF.SendMessage(Player, "Error", "Couldn't create entity: " .. Result) end return Success @@ -100,7 +102,7 @@ do -- Spawner operation return true end - if not CanTool(Player, Trace.Entity) then return false end + if not IsValid(Trace.Entity) then return false end SelectEntity(Tool, Player, Trace.Entity) @@ -168,7 +170,7 @@ do -- Linker operation local Entity = Trace.Entity if Trace.HitWorld then Tool:Holster() return true end - if not CanTool(Player, Entity) then return false end + if not IsValid(Entity) then return false end local Ents = GetPlayerEnts(Player) From da5a5b787a861aeb6eff6340408c213c07a99b62 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Wed, 23 Dec 2020 00:51:35 -0300 Subject: [PATCH 227/279] Improved spawner menu option descriptions - Added shared ACF.CreateMenuOperation for creating generic spawner/linker menu operations. A new set of operations was created in order to provide more specific descriptions. - Changed controls for generic operations to require the user to hold Shift or R while pressing left click to spawn the secondary entity. Right click will now be only use to start the linking process. --- lua/acf/client/menu_items/components_menu.lua | 2 +- lua/acf/client/menu_items/engines_menu.lua | 2 +- lua/acf/client/menu_items/gearboxes_menu.lua | 2 +- lua/acf/client/menu_items/sensors_menu.lua | 2 +- lua/acf/client/menu_items/weapons_menu.lua | 2 +- lua/acf/shared/spawner_operation.lua | 225 +++++++++++++++++ lua/acf/shared/tool_operations/acf_menu.lua | 232 +----------------- 7 files changed, 238 insertions(+), 229 deletions(-) create mode 100644 lua/acf/shared/spawner_operation.lua diff --git a/lua/acf/client/menu_items/components_menu.lua b/lua/acf/client/menu_items/components_menu.lua index 632410059..e18f4500e 100644 --- a/lua/acf/client/menu_items/components_menu.lua +++ b/lua/acf/client/menu_items/components_menu.lua @@ -5,7 +5,7 @@ local function CreateMenu(Menu) ACF.SetClientData("PrimaryClass", "N/A") ACF.SetClientData("SecondaryClass", "N/A") - ACF.SetToolMode("acf_menu", "Main", "Spawner") + ACF.SetToolMode("acf_menu", "Spawner", "Component") if not next(Components) then Menu:AddTitle("No Components Registered") diff --git a/lua/acf/client/menu_items/engines_menu.lua b/lua/acf/client/menu_items/engines_menu.lua index 9ac6a5e91..0e48445ab 100644 --- a/lua/acf/client/menu_items/engines_menu.lua +++ b/lua/acf/client/menu_items/engines_menu.lua @@ -82,7 +82,7 @@ local function CreateMenu(Menu) ACF.SetClientData("PrimaryClass", "acf_engine") ACF.SetClientData("SecondaryClass", "acf_fueltank") - ACF.SetToolMode("acf_menu", "Main", "Spawner") + ACF.SetToolMode("acf_menu", "Spawner", "Engine") function EngineClass:OnSelect(Index, _, Data) if self.Selected == Data then return end diff --git a/lua/acf/client/menu_items/gearboxes_menu.lua b/lua/acf/client/menu_items/gearboxes_menu.lua index d3cb903ff..ee3927fe5 100644 --- a/lua/acf/client/menu_items/gearboxes_menu.lua +++ b/lua/acf/client/menu_items/gearboxes_menu.lua @@ -15,7 +15,7 @@ local function CreateMenu(Menu) ACF.SetClientData("PrimaryClass", "acf_gearbox") ACF.SetClientData("SecondaryClass", "N/A") - ACF.SetToolMode("acf_menu", "Main", "Spawner") + ACF.SetToolMode("acf_menu", "Spawner", "Gearbox") function GearboxClass:OnSelect(Index, _, Data) if self.Selected == Data then return end diff --git a/lua/acf/client/menu_items/sensors_menu.lua b/lua/acf/client/menu_items/sensors_menu.lua index ec654edeb..bb133f118 100644 --- a/lua/acf/client/menu_items/sensors_menu.lua +++ b/lua/acf/client/menu_items/sensors_menu.lua @@ -5,7 +5,7 @@ local function CreateMenu(Menu) ACF.SetClientData("PrimaryClass", "N/A") ACF.SetClientData("SecondaryClass", "N/A") - ACF.SetToolMode("acf_menu", "Main", "Spawner") + ACF.SetToolMode("acf_menu", "Spawner", "Sensor") if not next(Sensors) then Menu:AddTitle("No Sensors Registered") diff --git a/lua/acf/client/menu_items/weapons_menu.lua b/lua/acf/client/menu_items/weapons_menu.lua index cad9bbfbf..65f318739 100644 --- a/lua/acf/client/menu_items/weapons_menu.lua +++ b/lua/acf/client/menu_items/weapons_menu.lua @@ -21,7 +21,7 @@ local function CreateMenu(Menu) ACF.SetClientData("PrimaryClass", "acf_gun") ACF.SetClientData("SecondaryClass", "acf_ammo") - ACF.SetToolMode("acf_menu", "Main", "Spawner") + ACF.SetToolMode("acf_menu", "Spawner", "Weapon") function ClassList:OnSelect(Index, _, Data) if self.Selected == Data then return end diff --git a/lua/acf/shared/spawner_operation.lua b/lua/acf/shared/spawner_operation.lua new file mode 100644 index 000000000..19fec28cc --- /dev/null +++ b/lua/acf/shared/spawner_operation.lua @@ -0,0 +1,225 @@ +local ACF = ACF +local Entities = {} +local SpawnText = "Spawn a new %s or update an existing one." + +local function GetPlayerEnts(Player) + local Ents = Entities[Player] + + if not Ents then + Ents = {} + Entities[Player] = Ents + end + + return Ents +end + +local function CanUpdate(Entity, ClassName) + if not IsValid(Entity) then return false end + + return Entity:GetClass() == ClassName +end + +local function SpawnEntity(Player, ClassName, Trace, Data) + if not ClassName or ClassName == "N/A" then return false end + + local Entity = Trace.Entity + + if CanUpdate(Entity, ClassName) then + local Result, Message = ACF.UpdateEntity(Entity, Data) + + ACF.SendMessage(Player, Result and "Info" or "Error", Message) + + return true + end + + local Position = Trace.HitPos + Trace.HitNormal * 128 + local Angles = Trace.HitNormal:Angle():Up():Angle() + + local Success, Result = ACF.CreateEntity(ClassName, Player, Position, Angles, Data) + + if Success then + local PhysObj = Result:GetPhysicsObject() + + Result:DropToFloor() + + if IsValid(PhysObj) then + PhysObj:EnableMotion(false) + end + else + ACF.SendMessage(Player, "Error", "Couldn't create entity: " .. Result) + end + + return Success +end + +function ACF.CreateMenuOperation(Name, Primary, Secondary) + if not ACF.CheckString(Name) then return end + if not ACF.CheckString(Primary) then return end + + Secondary = ACF.CheckString(Secondary) + + local function UnselectEntity(Tool, Player, Entity) + local Ents = GetPlayerEnts(Player) + + Entity:RemoveCallOnRemove("ACF_ToolLinking") + Entity:SetColor(Ents[Entity]) + + Ents[Entity] = nil + + if not next(Ents) then + Tool:SetMode("Spawner", Name) + end + end + + local function SelectEntity(Tool, Player, Entity) + if not IsValid(Entity) then return false end + + local Ents = GetPlayerEnts(Player) + + if not next(Ents) then + Tool:SetMode("Linker", Name) + end + + Ents[Entity] = Entity:GetColor() + Entity:SetColor(Color(0, 255, 0)) + Entity:CallOnRemove("ACF_ToolLinking", function() + UnselectEntity(Tool, Player, Entity) + end) + + return true + end + + do -- Spawner stuff + ACF.RegisterOperation("acf_menu", "Spawner", Name, { + OnLeftClick = function(Tool, Trace) + if Trace.HitSky then return false end + + local Player = Tool:GetOwner() + local Data = ACF.GetAllClientData(Player) + local UseSecond = Player:KeyDown(IN_SPEED) or Player:KeyDown(IN_RELOAD) + local ClassName = UseSecond and Data.SecondaryClass or Data.PrimaryClass + + return SpawnEntity(Player, ClassName, Trace, Data) + end, + OnRightClick = function(Tool, Trace) + local Player = Tool:GetOwner() + + return SelectEntity(Tool, Player, Trace.Entity) + end, + }) + + ACF.RegisterToolInfo("acf_menu", "Spawner", Name, { + name = "left", + text = SpawnText:format(Primary), + }) + + if Secondary then + ACF.RegisterToolInfo("acf_menu", "Spawner", Name, { + name = "left_secondary", + text = "(Hold Shift or R) " .. SpawnText:format(Secondary), + icon2 = "gui/info", + }) + end + + ACF.RegisterToolInfo("acf_menu", "Spawner", Name, { + name = "right", + text = "Select the entity you want to link or unlink.", + }) + end + + do -- Linker stuff + local function LinkEntities(Tool, Player, Entity, Ents) + local Total, Done = 0, 0 + local Unlink = Player:KeyDown(IN_RELOAD) + local Action = Unlink and Entity.Unlink or Entity.Link + + for K in pairs(Ents) do + local EntAction = Unlink and K.Unlink or K.Link + local Success = false + + if EntAction then + Success = EntAction(K, Entity) + elseif Action then + Success = Action(Entity, K) + end + + Total = Total + 1 + + if Success then + Done = Done + 1 + end + + UnselectEntity(Tool, Player, K) + end + + -- TODO: Add list of reasons for failed links + if Done > 0 then + local Status = (Unlink and "unlinked " or "linked ") .. Done .. " out of " .. Total + + ACF.SendMessage(Player, "Info", "Successfully ", Status, " entities to ", tostring(Entity), ".") + else + local Status = Total .. " entities could be " .. (Unlink and "unlinked" or "linked") + + ACF.SendMessage(Player, "Error", "None of the ", Status, " to ", tostring(Entity), ".") + end + end + + ACF.RegisterOperation("acf_menu", "Linker", Name, { + OnRightClick = function(Tool, Trace) + local Player = Tool:GetOwner() + local Entity = Trace.Entity + + if Trace.HitWorld then Tool:Holster() return true end + if not IsValid(Entity) then return false end + + local Ents = GetPlayerEnts(Player) + + if not Player:KeyDown(IN_SPEED) then + LinkEntities(Tool, Player, Entity, Ents) + return true + end + + if not Ents[Entity] then + SelectEntity(Tool, Player, Entity) + else + UnselectEntity(Tool, Player, Entity) + end + + return true + end, + OnHolster = function(Tool) + local Player = Tool:GetOwner() + local Ents = GetPlayerEnts(Player) + + if not next(Ents) then return end + + for Entity in pairs(Ents) do + UnselectEntity(Tool, Player, Entity) + end + end, + }) + + ACF.RegisterToolInfo("acf_menu", "Linker", Name, { + name = "right", + text = "Link all the selected entities to an entity.", + }) + + ACF.RegisterToolInfo("acf_menu", "Linker", Name, { + name = "right_r", + text = "Unlink all the selected entities from an entity.", + icon2 = "gui/r.png", + }) + + ACF.RegisterToolInfo("acf_menu", "Linker", Name, { + name = "right_shift", + text = "Select another entity to link.", + icon2 = "gui/info", + }) + + ACF.RegisterToolInfo("acf_menu", "Linker", Name, { + name = "right_world", + text = "(Hit the World) Unselected all selected entities.", + icon2 = "gui/info", + }) + end +end diff --git a/lua/acf/shared/tool_operations/acf_menu.lua b/lua/acf/shared/tool_operations/acf_menu.lua index b715827c7..b46dc7eee 100644 --- a/lua/acf/shared/tool_operations/acf_menu.lua +++ b/lua/acf/shared/tool_operations/acf_menu.lua @@ -1,224 +1,8 @@ -local ACF = ACF -local Entities = {} - -local function GetPlayerEnts(Player) - local Ents = Entities[Player] - - if not Ents then - Ents = {} - Entities[Player] = Ents - end - - return Ents -end - -local function UnselectEntity(Tool, Player, Entity) - local Ents = GetPlayerEnts(Player) - - Entity:RemoveCallOnRemove("ACF_ToolLinking") - Entity:SetColor(Ents[Entity]) - - Ents[Entity] = nil - - if not next(Ents) then - Tool:SetMode("Main", "Spawner") - end -end - -local function SelectEntity(Tool, Player, Entity) - local Ents = GetPlayerEnts(Player) - - if not next(Ents) then - Tool:SetMode("Main", "Linker") - end - - Ents[Entity] = Entity:GetColor() - Entity:SetColor(Color(0, 255, 0)) - Entity:CallOnRemove("ACF_ToolLinking", function() - UnselectEntity(Tool, Player, Entity) - end) -end - -do -- Spawner operation - local function CanUpdate(Entity, ClassName) - if not IsValid(Entity) then return false end - if Entity:GetClass() ~= ClassName then return false end - - return true - end - - local function SpawnEntity(Player, ClassName, Trace, Data) - if not ClassName or ClassName == "N/A" then return false end - - local Entity = Trace.Entity - - if CanUpdate(Entity, ClassName) then - local Result, Message = ACF.UpdateEntity(Entity, Data) - - ACF.SendMessage(Player, Result and "Info" or "Error", Message) - - return true - end - - -- Couldn't update the entity, aborting spawn - if IsValid(Entity) then return false end - - local Position = Trace.HitPos + Trace.HitNormal * 128 - local Angles = Trace.HitNormal:Angle():Up():Angle() - - local Success, Result = ACF.CreateEntity(ClassName, Player, Position, Angles, Data) - - if Success then - local PhysObj = Result:GetPhysicsObject() - - Result:DropToFloor() - - if IsValid(PhysObj) then - PhysObj:EnableMotion(false) - end - else - ACF.SendMessage(Player, "Error", "Couldn't create entity: " .. Result) - end - - return Success - end - - ACF.RegisterOperation("acf_menu", "Main", "Spawner", { - OnLeftClick = function(Tool, Trace) - if Trace.HitSky then return false end - - local Player = Tool:GetOwner() - local Data = ACF.GetAllClientData(Player) - local ClassName = Data.PrimaryClass - - return SpawnEntity(Player, ClassName, Trace, Data) - end, - OnRightClick = function(Tool, Trace) - local Player = Tool:GetOwner() - local Data = ACF.GetAllClientData(Player) - local ClassName = Data.SecondaryClass - - if not Player:KeyDown(IN_SPEED) and SpawnEntity(Player, ClassName, Trace, Data) then - return true - end - - if not IsValid(Trace.Entity) then return false end - - SelectEntity(Tool, Player, Trace.Entity) - - return true - end, - }) - - ACF.RegisterToolInfo("acf_menu", "Main", "Spawner", { - name = "left", - text = "Spawn or update the selected primary entity.", - }) - - ACF.RegisterToolInfo("acf_menu", "Main", "Spawner", { - name = "right", - text = "If valid, spawn or update the selected secondary entity.", - }) - - ACF.RegisterToolInfo("acf_menu", "Main", "Spawner", { - name = "right_shift", - text = "(Hold Shift) Select the entity you want to link or unlink.", - icon2 = "gui/info", - }) -end - -do -- Linker operation - local function LinkEntities(Tool, Player, Entity, Ents) - local Total, Done = 0, 0 - local Unlink = Player:KeyDown(IN_RELOAD) - local Action = Unlink and Entity.Unlink or Entity.Link - - for K in pairs(Ents) do - local EntAction = Unlink and K.Unlink or K.Link - local Success = false - - if EntAction then - Success = EntAction(K, Entity) - elseif Action then - Success = Action(Entity, K) - end - - Total = Total + 1 - - if Success then - Done = Done + 1 - end - - UnselectEntity(Tool, Player, K) - end - - -- TODO: Add list of reasons for failed links - if Done > 0 then - local Status = (Unlink and "unlinked " or "linked ") .. Done .. " out of " .. Total - - ACF.SendMessage(Player, "Info", "Successfully ", Status, " entities to ", tostring(Entity), ".") - else - local Status = Total .. " entities could be " .. (Unlink and "unlinked" or "linked") - - ACF.SendMessage(Player, "Error", "None of the ", Status, " to ", tostring(Entity), ".") - end - end - - ACF.RegisterOperation("acf_menu", "Main", "Linker", { - OnRightClick = function(Tool, Trace) - local Player = Tool:GetOwner() - local Entity = Trace.Entity - - if Trace.HitWorld then Tool:Holster() return true end - if not IsValid(Entity) then return false end - - local Ents = GetPlayerEnts(Player) - - if not Player:KeyDown(IN_SPEED) then - LinkEntities(Tool, Player, Entity, Ents) - return true - end - - if not Ents[Entity] then - SelectEntity(Tool, Player, Entity) - else - UnselectEntity(Tool, Player, Entity) - end - - return true - end, - OnHolster = function(Tool) - local Player = Tool:GetOwner() - local Ents = GetPlayerEnts(Player) - - if not next(Ents) then return end - - for Entity in pairs(Ents) do - UnselectEntity(Tool, Player, Entity) - end - end, - }) - - ACF.RegisterToolInfo("acf_menu", "Main", "Linker", { - name = "right", - text = "Link all the selected entities to an entity.", - }) - - ACF.RegisterToolInfo("acf_menu", "Main", "Linker", { - name = "right_r", - text = "Unlink all the selected entities from an entity.", - icon2 = "gui/r.png", - }) - - ACF.RegisterToolInfo("acf_menu", "Main", "Linker", { - name = "right_shift", - text = "Select another entity to link.", - icon2 = "gui/info", - }) - - ACF.RegisterToolInfo("acf_menu", "Main", "Linker", { - name = "right_world", - text = "(Hit the World) Unselected all selected entities.", - icon2 = "gui/info", - }) -end +local ACF = ACF + +ACF.CreateMenuOperation("Weapon", "weapon", "ammo crate") +ACF.CreateMenuOperation("Missile", "rack", "ammo crate") +ACF.CreateMenuOperation("Engine", "engine", "fuel tank") +ACF.CreateMenuOperation("Component", "component") +ACF.CreateMenuOperation("Gearbox", "gearbox") +ACF.CreateMenuOperation("Sensor", "sensor") From bdb8464ff7326d9dccfbb5ea87351ceb9cffbce1 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Wed, 23 Dec 2020 02:11:53 -0300 Subject: [PATCH 228/279] Copy tool can now spawn entities - The copy tool is now capable of spawning entities with the copied information by left clicking the world. --- lua/acf/client/cl_copy_menu.lua | 2 + lua/acf/shared/tool_operations/acf_copy.lua | 75 ++++++++++++++++----- 2 files changed, 61 insertions(+), 16 deletions(-) diff --git a/lua/acf/client/cl_copy_menu.lua b/lua/acf/client/cl_copy_menu.lua index 7296a4a00..e72ddf70f 100644 --- a/lua/acf/client/cl_copy_menu.lua +++ b/lua/acf/client/cl_copy_menu.lua @@ -115,6 +115,8 @@ function ACF.CreateCopyMenu(Panel) function ClassList:OnSelect(_, Class, Data) Selected = Class + ACF.SetClientData("CopyClass", Class) + PopulateTree(TreeList, Data) end diff --git a/lua/acf/shared/tool_operations/acf_copy.lua b/lua/acf/shared/tool_operations/acf_copy.lua index 94f8b5830..90f60218a 100644 --- a/lua/acf/shared/tool_operations/acf_copy.lua +++ b/lua/acf/shared/tool_operations/acf_copy.lua @@ -74,6 +74,56 @@ local function SaveCopyData(Player, Entity) return util.TableToJSON(List) end +local function GetSpawnData(Player, Entity, Class) + local Saved = GetCopyData(Player, Class) + + if not Saved then return end + + local Ignored = GetDisabledData(Player, Class) + local Data = {} + + for K, V in pairs(Saved) do + if Ignored[K] then + Data[K] = Entity and Entity[K] + else + Data[K] = V + end + end + + return Data +end + +local function CreateNewEntity(Player, Trace) + local Class = ACF.GetClientData(Player, "CopyClass") + + if not Class then return false end + + local Data = GetSpawnData(Player, nil, Class) + local Position = Trace.HitPos + Trace.HitNormal * 128 + local Angles = Trace.HitNormal:Angle():Up():Angle() + local Message = "" + + local Success, Result = ACF.CreateEntity(Class, Player, Position, Angles, Data) + + if not Success then + Message = "Couldn't create entity: " .. Result + else + local PhysObj = Result:GetPhysicsObject() + + Result:DropToFloor() + + if IsValid(PhysObj) then + PhysObj:EnableMotion(false) + end + + Message = "Entity created successfully." + end + + ACF.SendMessage(Player, Result and "Info" or "Error", Message) + + return true +end + ACF.RegisterOperation("acfcopy", "Main", "CopyPaste", { OnLeftClick = function(Tool, Trace) if Trace.HitSky then return false end @@ -81,33 +131,20 @@ ACF.RegisterOperation("acfcopy", "Main", "CopyPaste", { local Entity = Trace.Entity local Player = Tool:GetOwner() - if not IsValid(Entity) then return false end + if not IsValid(Entity) then return CreateNewEntity(Player, Trace) end if not isfunction(Entity.Update) then ACF.SendMessage(Player, "Error", "This entity doesn't support updating!") return false end local Class = Entity:GetClass() - local Saved = GetCopyData(Player, Class) + local Data = GetSpawnData(Player, Entity, Class) - if not Saved then + if not Data then ACF.SendMessage(Player, "Error", "No information has been copied for '", Class, "' entities!") return false end - local DisabledData = GetDisabledData(Player, Class) - local Data = {} - - for K, V in pairs(Saved) do - local Value = V - - if DisabledData[K] then - Value = Entity[K] - end - - Data[K] = Value - end - local Result, Message = ACF.UpdateEntity(Entity, Data) if not Result then @@ -143,6 +180,12 @@ ACF.RegisterToolInfo("acfcopy", "Main", "CopyPaste", { text = "Update the ACF entity with the copied information for its class.", }) +ACF.RegisterToolInfo("acfcopy", "Main", "CopyPaste", { + name = "left_spawn", + text = "If no entity is hit, a new entity will be created with the copied information.", + icon2 = "gui/info", +}) + ACF.RegisterToolInfo("acfcopy", "Main", "CopyPaste", { name = "right", text = "Copy the relevant information from an ACF entity.", From 32d360a7fda67dd84c4c72e7e38de5173d2ea0d6 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Wed, 23 Dec 2020 17:54:58 -0300 Subject: [PATCH 229/279] Added a few default persisted vars - Clients will now persist the values of each crate axis size. Servers will persist a few admin settings. - Renamed a few clientside only files. --- lua/acf/client/{cl_ammo_menu.lua => ammo_menu.lua} | 0 lua/acf/client/{cl_ballistics.lua => ballistics.lua} | 0 lua/acf/client/{cl_copy_menu.lua => copy_menu.lua} | 0 lua/acf/client/{cl_damage.lua => damage.lua} | 0 lua/acf/client/{cl_permissions.lua => permissions.lua} | 0 lua/acf/client/persisted_vars.lua | 5 +++++ lua/acf/client/{cl_spawn_menu.lua => spawn_menu.lua} | 0 lua/acf/server/persisted_vars.lua | 4 ++++ 8 files changed, 9 insertions(+) rename lua/acf/client/{cl_ammo_menu.lua => ammo_menu.lua} (100%) rename lua/acf/client/{cl_ballistics.lua => ballistics.lua} (100%) rename lua/acf/client/{cl_copy_menu.lua => copy_menu.lua} (100%) rename lua/acf/client/{cl_damage.lua => damage.lua} (100%) rename lua/acf/client/{cl_permissions.lua => permissions.lua} (100%) create mode 100644 lua/acf/client/persisted_vars.lua rename lua/acf/client/{cl_spawn_menu.lua => spawn_menu.lua} (100%) create mode 100644 lua/acf/server/persisted_vars.lua diff --git a/lua/acf/client/cl_ammo_menu.lua b/lua/acf/client/ammo_menu.lua similarity index 100% rename from lua/acf/client/cl_ammo_menu.lua rename to lua/acf/client/ammo_menu.lua diff --git a/lua/acf/client/cl_ballistics.lua b/lua/acf/client/ballistics.lua similarity index 100% rename from lua/acf/client/cl_ballistics.lua rename to lua/acf/client/ballistics.lua diff --git a/lua/acf/client/cl_copy_menu.lua b/lua/acf/client/copy_menu.lua similarity index 100% rename from lua/acf/client/cl_copy_menu.lua rename to lua/acf/client/copy_menu.lua diff --git a/lua/acf/client/cl_damage.lua b/lua/acf/client/damage.lua similarity index 100% rename from lua/acf/client/cl_damage.lua rename to lua/acf/client/damage.lua diff --git a/lua/acf/client/cl_permissions.lua b/lua/acf/client/permissions.lua similarity index 100% rename from lua/acf/client/cl_permissions.lua rename to lua/acf/client/permissions.lua diff --git a/lua/acf/client/persisted_vars.lua b/lua/acf/client/persisted_vars.lua new file mode 100644 index 000000000..0df5e1b36 --- /dev/null +++ b/lua/acf/client/persisted_vars.lua @@ -0,0 +1,5 @@ +-- Variables that should be persisted between servers + +ACF.PersistClientData("CrateSizeX", 24) +ACF.PersistClientData("CrateSizeY", 24) +ACF.PersistClientData("CrateSizeZ", 24) diff --git a/lua/acf/client/cl_spawn_menu.lua b/lua/acf/client/spawn_menu.lua similarity index 100% rename from lua/acf/client/cl_spawn_menu.lua rename to lua/acf/client/spawn_menu.lua diff --git a/lua/acf/server/persisted_vars.lua b/lua/acf/server/persisted_vars.lua new file mode 100644 index 000000000..8260fd0df --- /dev/null +++ b/lua/acf/server/persisted_vars.lua @@ -0,0 +1,4 @@ +-- Variables that should be persisted between server restarts + +ACF.PersistServerData("ServerDataAllowAdmin", false) +ACF.PersistServerData("ShowFunMenu", true) \ No newline at end of file From ffa322694917536bd0fc12f3aa312e358216e998 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Wed, 23 Dec 2020 21:00:30 -0300 Subject: [PATCH 230/279] Fixed persisted variables not being loaded - Fixed persisted variables not being loaded if the stored data file doesn't exist. --- lua/acf/base/data_vars/cl_data_vars.lua | 6 +-- lua/acf/base/data_vars/sh_data_vars.lua | 50 ++++++++++++------------- 2 files changed, 27 insertions(+), 29 deletions(-) diff --git a/lua/acf/base/data_vars/cl_data_vars.lua b/lua/acf/base/data_vars/cl_data_vars.lua index 405c8fdd0..dbf0b3731 100644 --- a/lua/acf/base/data_vars/cl_data_vars.lua +++ b/lua/acf/base/data_vars/cl_data_vars.lua @@ -78,13 +78,11 @@ do -- Server data var syncronization end) -- We'll request the server data vars as soon as the player starts moving - hook.Add("CreateMove", "ACF Request Data Vars", function(Move) - if Move:GetButtons() == 0 then return end - + hook.Add("InitPostEntity", "ACF Request Data Vars", function() net.Start("ACF_RequestDataVars") net.SendToServer() - hook.Remove("CreateMove", "ACF Request Data Vars") + hook.Remove("InitPostEntity", "ACF Request Data Vars") end) end diff --git a/lua/acf/base/data_vars/sh_data_vars.lua b/lua/acf/base/data_vars/sh_data_vars.lua index 406b9b185..2341be8fc 100644 --- a/lua/acf/base/data_vars/sh_data_vars.lua +++ b/lua/acf/base/data_vars/sh_data_vars.lua @@ -64,29 +64,6 @@ do -- Data persisting local Values = ACF[Realm .. "Data"] local Folder = "acf/data_vars" local File = "stored.json" - local Loaded = false - - local function LoadData() - local Saved = ACF.LoadFromFile(Folder, File) - - if Saved then - local SetFunction = ACF["Set" .. Realm .. "Data"] - - for Key, Stored in pairs(Saved) do - if Keys[Key] == nil then - Keys[Key] = Stored.Default - end - - if Stored.Value ~= "nil" then - SetFunction(Key, Stored.Value) - end - end - end - - Loaded = true - - hook.Remove("Initialize", "ACF Load Persisted Data") - end local function StoreData() local Result = {} @@ -112,7 +89,7 @@ do -- Data persisting if Persist[Key] ~= Value then Persist[Key] = Value - if not Loaded or timer.Exists("ACF Store Persisted") then return end + if timer.Exists("ACF Store Persisted") then return end timer.Create("ACF Store Persisted", 1, 1, StoreData) end @@ -135,5 +112,28 @@ do -- Data persisting UpdateData(Key) end) - hook.Add("Initialize", "ACF Load Persisted Data", LoadData) + hook.Add("Initialize", "ACF Load Persisted Data", function() + local Saved = ACF.LoadFromFile(Folder, File) + local SetFunction = ACF["Set" .. Realm .. "Data"] + + if Saved then + for Key, Stored in pairs(Saved) do + if Keys[Key] == nil then + Keys[Key] = Stored.Default + end + + if Stored.Value ~= "nil" then + SetFunction(Key, Stored.Value) + end + end + else + for Key, Default in pairs(Keys) do + local Value = Either(Persist[Key] ~= nil, Persist[Key], Default) + + SetFunction(Key, Value) + end + end + + hook.Remove("Initialize", "ACF Load Persisted Data") + end) end From 8f808d3171807e22d2591dec8a07e234497a546d Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Wed, 23 Dec 2020 21:17:31 -0300 Subject: [PATCH 231/279] Moved ACF.CreateMenuOperation to another file - Moved ACF.CreateMenuOperation function to the tool functions file. --- lua/acf/base/sh_tool_functions.lua | 227 +++++++++++++++++++++++++++ lua/acf/shared/spawner_operation.lua | 225 -------------------------- 2 files changed, 227 insertions(+), 225 deletions(-) delete mode 100644 lua/acf/shared/spawner_operation.lua diff --git a/lua/acf/base/sh_tool_functions.lua b/lua/acf/base/sh_tool_functions.lua index c1dd2612e..167ba6392 100644 --- a/lua/acf/base/sh_tool_functions.lua +++ b/lua/acf/base/sh_tool_functions.lua @@ -379,3 +379,230 @@ do -- Clientside Tool interaction end end end + +do -- Generic Spawner/Linker operation creator + local Entities = {} + local SpawnText = "Spawn a new %s or update an existing one." + + local function GetPlayerEnts(Player) + local Ents = Entities[Player] + + if not Ents then + Ents = {} + Entities[Player] = Ents + end + + return Ents + end + + local function CanUpdate(Entity, ClassName) + if not IsValid(Entity) then return false end + + return Entity:GetClass() == ClassName + end + + local function SpawnEntity(Player, ClassName, Trace, Data) + if not ClassName or ClassName == "N/A" then return false end + + local Entity = Trace.Entity + + if CanUpdate(Entity, ClassName) then + local Result, Message = ACF.UpdateEntity(Entity, Data) + + ACF.SendMessage(Player, Result and "Info" or "Error", Message) + + return true + end + + local Position = Trace.HitPos + Trace.HitNormal * 128 + local Angles = Trace.HitNormal:Angle():Up():Angle() + + local Success, Result = ACF.CreateEntity(ClassName, Player, Position, Angles, Data) + + if Success then + local PhysObj = Result:GetPhysicsObject() + + Result:DropToFloor() + + if IsValid(PhysObj) then + PhysObj:EnableMotion(false) + end + else + ACF.SendMessage(Player, "Error", "Couldn't create entity: " .. Result) + end + + return Success + end + + function ACF.CreateMenuOperation(Name, Primary, Secondary) + if not ACF.CheckString(Name) then return end + if not ACF.CheckString(Primary) then return end + + Secondary = ACF.CheckString(Secondary) + + local function UnselectEntity(Tool, Player, Entity) + local Ents = GetPlayerEnts(Player) + + Entity:RemoveCallOnRemove("ACF_ToolLinking") + Entity:SetColor(Ents[Entity]) + + Ents[Entity] = nil + + if not next(Ents) then + Tool:SetMode("Spawner", Name) + end + end + + local function SelectEntity(Tool, Player, Entity) + if not IsValid(Entity) then return false end + + local Ents = GetPlayerEnts(Player) + + if not next(Ents) then + Tool:SetMode("Linker", Name) + end + + Ents[Entity] = Entity:GetColor() + Entity:SetColor(Color(0, 255, 0)) + Entity:CallOnRemove("ACF_ToolLinking", function() + UnselectEntity(Tool, Player, Entity) + end) + + return true + end + + do -- Spawner stuff + ACF.RegisterOperation("acf_menu", "Spawner", Name, { + OnLeftClick = function(Tool, Trace) + if Trace.HitSky then return false end + + local Player = Tool:GetOwner() + local Data = ACF.GetAllClientData(Player) + local UseSecond = Player:KeyDown(IN_SPEED) or Player:KeyDown(IN_RELOAD) + local ClassName = UseSecond and Data.SecondaryClass or Data.PrimaryClass + + return SpawnEntity(Player, ClassName, Trace, Data) + end, + OnRightClick = function(Tool, Trace) + local Player = Tool:GetOwner() + + return SelectEntity(Tool, Player, Trace.Entity) + end, + }) + + ACF.RegisterToolInfo("acf_menu", "Spawner", Name, { + name = "left", + text = SpawnText:format(Primary), + }) + + if Secondary then + ACF.RegisterToolInfo("acf_menu", "Spawner", Name, { + name = "left_secondary", + text = "(Hold Shift or R) " .. SpawnText:format(Secondary), + icon2 = "gui/info", + }) + end + + ACF.RegisterToolInfo("acf_menu", "Spawner", Name, { + name = "right", + text = "Select the entity you want to link or unlink.", + }) + end + + do -- Linker stuff + local function LinkEntities(Tool, Player, Entity, Ents) + local Total, Done = 0, 0 + local Unlink = Player:KeyDown(IN_RELOAD) + local Action = Unlink and Entity.Unlink or Entity.Link + + for K in pairs(Ents) do + local EntAction = Unlink and K.Unlink or K.Link + local Success = false + + if EntAction then + Success = EntAction(K, Entity) + elseif Action then + Success = Action(Entity, K) + end + + Total = Total + 1 + + if Success then + Done = Done + 1 + end + + UnselectEntity(Tool, Player, K) + end + + -- TODO: Add list of reasons for failed links + if Done > 0 then + local Status = (Unlink and "unlinked " or "linked ") .. Done .. " out of " .. Total + + ACF.SendMessage(Player, "Info", "Successfully ", Status, " entities to ", tostring(Entity), ".") + else + local Status = Total .. " entities could be " .. (Unlink and "unlinked" or "linked") + + ACF.SendMessage(Player, "Error", "None of the ", Status, " to ", tostring(Entity), ".") + end + end + + ACF.RegisterOperation("acf_menu", "Linker", Name, { + OnRightClick = function(Tool, Trace) + local Player = Tool:GetOwner() + local Entity = Trace.Entity + + if Trace.HitWorld then Tool:Holster() return true end + if not IsValid(Entity) then return false end + + local Ents = GetPlayerEnts(Player) + + if not Player:KeyDown(IN_SPEED) then + LinkEntities(Tool, Player, Entity, Ents) + return true + end + + if not Ents[Entity] then + SelectEntity(Tool, Player, Entity) + else + UnselectEntity(Tool, Player, Entity) + end + + return true + end, + OnHolster = function(Tool) + local Player = Tool:GetOwner() + local Ents = GetPlayerEnts(Player) + + if not next(Ents) then return end + + for Entity in pairs(Ents) do + UnselectEntity(Tool, Player, Entity) + end + end, + }) + + ACF.RegisterToolInfo("acf_menu", "Linker", Name, { + name = "right", + text = "Link all the selected entities to an entity.", + }) + + ACF.RegisterToolInfo("acf_menu", "Linker", Name, { + name = "right_r", + text = "Unlink all the selected entities from an entity.", + icon2 = "gui/r.png", + }) + + ACF.RegisterToolInfo("acf_menu", "Linker", Name, { + name = "right_shift", + text = "Select another entity to link.", + icon2 = "gui/info", + }) + + ACF.RegisterToolInfo("acf_menu", "Linker", Name, { + name = "right_world", + text = "(Hit the World) Unselected all selected entities.", + icon2 = "gui/info", + }) + end + end +end diff --git a/lua/acf/shared/spawner_operation.lua b/lua/acf/shared/spawner_operation.lua deleted file mode 100644 index 19fec28cc..000000000 --- a/lua/acf/shared/spawner_operation.lua +++ /dev/null @@ -1,225 +0,0 @@ -local ACF = ACF -local Entities = {} -local SpawnText = "Spawn a new %s or update an existing one." - -local function GetPlayerEnts(Player) - local Ents = Entities[Player] - - if not Ents then - Ents = {} - Entities[Player] = Ents - end - - return Ents -end - -local function CanUpdate(Entity, ClassName) - if not IsValid(Entity) then return false end - - return Entity:GetClass() == ClassName -end - -local function SpawnEntity(Player, ClassName, Trace, Data) - if not ClassName or ClassName == "N/A" then return false end - - local Entity = Trace.Entity - - if CanUpdate(Entity, ClassName) then - local Result, Message = ACF.UpdateEntity(Entity, Data) - - ACF.SendMessage(Player, Result and "Info" or "Error", Message) - - return true - end - - local Position = Trace.HitPos + Trace.HitNormal * 128 - local Angles = Trace.HitNormal:Angle():Up():Angle() - - local Success, Result = ACF.CreateEntity(ClassName, Player, Position, Angles, Data) - - if Success then - local PhysObj = Result:GetPhysicsObject() - - Result:DropToFloor() - - if IsValid(PhysObj) then - PhysObj:EnableMotion(false) - end - else - ACF.SendMessage(Player, "Error", "Couldn't create entity: " .. Result) - end - - return Success -end - -function ACF.CreateMenuOperation(Name, Primary, Secondary) - if not ACF.CheckString(Name) then return end - if not ACF.CheckString(Primary) then return end - - Secondary = ACF.CheckString(Secondary) - - local function UnselectEntity(Tool, Player, Entity) - local Ents = GetPlayerEnts(Player) - - Entity:RemoveCallOnRemove("ACF_ToolLinking") - Entity:SetColor(Ents[Entity]) - - Ents[Entity] = nil - - if not next(Ents) then - Tool:SetMode("Spawner", Name) - end - end - - local function SelectEntity(Tool, Player, Entity) - if not IsValid(Entity) then return false end - - local Ents = GetPlayerEnts(Player) - - if not next(Ents) then - Tool:SetMode("Linker", Name) - end - - Ents[Entity] = Entity:GetColor() - Entity:SetColor(Color(0, 255, 0)) - Entity:CallOnRemove("ACF_ToolLinking", function() - UnselectEntity(Tool, Player, Entity) - end) - - return true - end - - do -- Spawner stuff - ACF.RegisterOperation("acf_menu", "Spawner", Name, { - OnLeftClick = function(Tool, Trace) - if Trace.HitSky then return false end - - local Player = Tool:GetOwner() - local Data = ACF.GetAllClientData(Player) - local UseSecond = Player:KeyDown(IN_SPEED) or Player:KeyDown(IN_RELOAD) - local ClassName = UseSecond and Data.SecondaryClass or Data.PrimaryClass - - return SpawnEntity(Player, ClassName, Trace, Data) - end, - OnRightClick = function(Tool, Trace) - local Player = Tool:GetOwner() - - return SelectEntity(Tool, Player, Trace.Entity) - end, - }) - - ACF.RegisterToolInfo("acf_menu", "Spawner", Name, { - name = "left", - text = SpawnText:format(Primary), - }) - - if Secondary then - ACF.RegisterToolInfo("acf_menu", "Spawner", Name, { - name = "left_secondary", - text = "(Hold Shift or R) " .. SpawnText:format(Secondary), - icon2 = "gui/info", - }) - end - - ACF.RegisterToolInfo("acf_menu", "Spawner", Name, { - name = "right", - text = "Select the entity you want to link or unlink.", - }) - end - - do -- Linker stuff - local function LinkEntities(Tool, Player, Entity, Ents) - local Total, Done = 0, 0 - local Unlink = Player:KeyDown(IN_RELOAD) - local Action = Unlink and Entity.Unlink or Entity.Link - - for K in pairs(Ents) do - local EntAction = Unlink and K.Unlink or K.Link - local Success = false - - if EntAction then - Success = EntAction(K, Entity) - elseif Action then - Success = Action(Entity, K) - end - - Total = Total + 1 - - if Success then - Done = Done + 1 - end - - UnselectEntity(Tool, Player, K) - end - - -- TODO: Add list of reasons for failed links - if Done > 0 then - local Status = (Unlink and "unlinked " or "linked ") .. Done .. " out of " .. Total - - ACF.SendMessage(Player, "Info", "Successfully ", Status, " entities to ", tostring(Entity), ".") - else - local Status = Total .. " entities could be " .. (Unlink and "unlinked" or "linked") - - ACF.SendMessage(Player, "Error", "None of the ", Status, " to ", tostring(Entity), ".") - end - end - - ACF.RegisterOperation("acf_menu", "Linker", Name, { - OnRightClick = function(Tool, Trace) - local Player = Tool:GetOwner() - local Entity = Trace.Entity - - if Trace.HitWorld then Tool:Holster() return true end - if not IsValid(Entity) then return false end - - local Ents = GetPlayerEnts(Player) - - if not Player:KeyDown(IN_SPEED) then - LinkEntities(Tool, Player, Entity, Ents) - return true - end - - if not Ents[Entity] then - SelectEntity(Tool, Player, Entity) - else - UnselectEntity(Tool, Player, Entity) - end - - return true - end, - OnHolster = function(Tool) - local Player = Tool:GetOwner() - local Ents = GetPlayerEnts(Player) - - if not next(Ents) then return end - - for Entity in pairs(Ents) do - UnselectEntity(Tool, Player, Entity) - end - end, - }) - - ACF.RegisterToolInfo("acf_menu", "Linker", Name, { - name = "right", - text = "Link all the selected entities to an entity.", - }) - - ACF.RegisterToolInfo("acf_menu", "Linker", Name, { - name = "right_r", - text = "Unlink all the selected entities from an entity.", - icon2 = "gui/r.png", - }) - - ACF.RegisterToolInfo("acf_menu", "Linker", Name, { - name = "right_shift", - text = "Select another entity to link.", - icon2 = "gui/info", - }) - - ACF.RegisterToolInfo("acf_menu", "Linker", Name, { - name = "right_world", - text = "(Hit the World) Unselected all selected entities.", - icon2 = "gui/info", - }) - end -end From e110a749284c4a2afd33305d60a27aed3beb113a Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Thu, 24 Dec 2020 12:55:04 -0300 Subject: [PATCH 232/279] ACF bases will now define ENT:UpdateOverlay - Both ACF bases will now define ENT:UpdateOverlay. - Players will now be supposed to overwrite ENT:UpdateOverlayText, which should return a string with the updated overlay text. - Added ENT:GetDisableText to both bases. If the entity happens to be disabled when the overlay is updated, it'll be updated with the text returned by this function. --- lua/entities/acf_ammo/init.lua | 74 ++++++++----------------- lua/entities/acf_base_scalable/init.lua | 40 ++++++++++++- lua/entities/acf_base_simple/init.lua | 44 ++++++++++++++- lua/entities/acf_engine/init.lua | 41 +++----------- lua/entities/acf_fueltank/init.lua | 59 ++++++-------------- lua/entities/acf_gearbox/init.lua | 51 +++++------------ lua/entities/acf_gun/init.lua | 55 ++++++------------ 7 files changed, 160 insertions(+), 204 deletions(-) diff --git a/lua/entities/acf_ammo/init.lua b/lua/entities/acf_ammo/init.lua index 9440eea0f..e2cf9838b 100644 --- a/lua/entities/acf_ammo/init.lua +++ b/lua/entities/acf_ammo/init.lua @@ -669,64 +669,38 @@ do -- Entity Overlay ---------------------------- local Text = "%s\n\nSize: %sx%sx%s\n\nContents: %s ( %s / %s )%s%s%s" local BulletText = "\nCartridge Mass: %s kg\nProjectile Mass: %s kg\nPropellant Mass: %s kg" - local function Overlay(Ent) - if Ent.Disabled then - Ent:SetOverlayText("Disabled: " .. Ent.DisableReason .. "\n" .. Ent.DisableDescription) + function ENT:UpdateOverlayText() + local Tracer = self.BulletData.Tracer ~= 0 and "-T" or "" + local AmmoType = self.BulletData.Type .. Tracer + local X, Y, Z = self:GetSize():Unpack() + local AmmoInfo = self.RoundData:GetCrateText(self.BulletData) + local ExtraInfo = ACF.GetOverlayText(self) + local BulletInfo = "" + local Status + + if next(self.Weapons) or self.IsRefill then + Status = self:CanConsume() and "Providing Ammo" or (self.Ammo ~= 0 and "Idle" or "Empty") else - local Tracer = Ent.BulletData.Tracer ~= 0 and "-T" or "" - local AmmoType = Ent.BulletData.Type .. Tracer - local X, Y, Z = Ent:GetSize():Unpack() - local AmmoInfo = Ent.RoundData:GetCrateText(Ent.BulletData) - local ExtraInfo = ACF.GetOverlayText(Ent) - local BulletInfo = "" - local Status - - if next(Ent.Weapons) or Ent.IsRefill then - Status = Ent:CanConsume() and "Providing Ammo" or (Ent.Ammo ~= 0 and "Idle" or "Empty") - else - Status = "Not linked to a weapon!" - end - - X = math.Round(X, 2) - Y = math.Round(Y, 2) - Z = math.Round(Z, 2) + Status = "Not linked to a weapon!" + end - if Ent.BulletData.Type ~= "Refill" then - local ProjectileMass = math.Round(Ent.BulletData.ProjMass, 2) - local PropellantMass = math.Round(Ent.BulletData.PropMass, 2) - local CartridgeMass = math.Round(Ent.BulletData.CartMass, 2) + X = math.Round(X, 2) + Y = math.Round(Y, 2) + Z = math.Round(Z, 2) - BulletInfo = BulletText:format(CartridgeMass, ProjectileMass, PropellantMass) - end + if self.BulletData.Type ~= "Refill" then + local Projectile = math.Round(self.BulletData.ProjMass, 2) + local Propellant = math.Round(self.BulletData.PropMass, 2) + local Cartridge = math.Round(self.BulletData.CartMass, 2) - if AmmoInfo and AmmoInfo ~= "" then - AmmoInfo = "\n\n" .. AmmoInfo - end - - Ent:SetOverlayText(Text:format(Status, X, Y, Z, AmmoType, Ent.Ammo, Ent.Capacity, BulletInfo, AmmoInfo, ExtraInfo)) + BulletInfo = BulletText:format(Cartridge, Projectile, Propellant) end - end - ------------------------------------------------------------------------------- - - function ENT:UpdateOverlay(Instant) - if Instant then - return Overlay(self) + if AmmoInfo and AmmoInfo ~= "" then + AmmoInfo = "\n\n" .. AmmoInfo end - if TimerExists("ACF Overlay Buffer" .. self:EntIndex()) then -- This entity has been updated too recently - self.OverlayBuffer = true -- Mark it to update when buffer time has expired - else - TimerCreate("ACF Overlay Buffer" .. self:EntIndex(), 1, 1, function() - if IsValid(self) and self.OverlayBuffer then - self.OverlayBuffer = nil - - Overlay(self) - end - end) - - Overlay(self) - end + return Text:format(Status, X, Y, Z, AmmoType, self.Ammo, self.Capacity, BulletInfo, AmmoInfo, ExtraInfo) end end --------------------------------------------- diff --git a/lua/entities/acf_base_scalable/init.lua b/lua/entities/acf_base_scalable/init.lua index 4a78cf274..a6b080188 100644 --- a/lua/entities/acf_base_scalable/init.lua +++ b/lua/entities/acf_base_scalable/init.lua @@ -5,10 +5,48 @@ include("shared.lua") local ACF = ACF +ENT.OverlayDelay = 1 -- Time in seconds between each overlay update + -- You should overwrite these function ENT:Enable() end function ENT:Disable() end -function ENT:UpdateOverlay() end +function ENT:UpdateOverlayText() end + +do -- Entity Overlay ---------------------------- + local Disable = "Disabled: %s\n%s" + local TimerName = "ACF Overlay Buffer %s" + local timer = timer + + function ENT:GetDisableText() + return Disable:format(self.DisableReason, self.DisableDescription) + end + + function ENT:UpdateOverlay(Instant) + if Instant then + local Text = Either(self.Disabled, self:GetDisableText(), self:UpdateOverlayText()) + + return self:SetOverlayText(Text) + end + + local Name = TimerName:format(self:EntIndex()) + + if timer.Exists(Name) then -- This entity has been updated too recently + self.OverlayBuffer = true -- Mark it to update when buffer time has expired + else + timer.Create(Name, self.OverlayDelay, 1, function() + if not IsValid(self) then return end + if not self.OverlayBuffer then return end + + self.OverlayBuffer = nil + self:UpdateOverlay() + end) + + local Text = Either(self.Disabled, self:GetDisableText(), self:UpdateOverlayText()) + + self:SetOverlayText(Text) + end + end +end --------------------------------------------- do -- Entity linking and unlinking -------------- local LinkText = "%s can't be linked to %s." diff --git a/lua/entities/acf_base_simple/init.lua b/lua/entities/acf_base_simple/init.lua index 4a78cf274..7f86e2121 100644 --- a/lua/entities/acf_base_simple/init.lua +++ b/lua/entities/acf_base_simple/init.lua @@ -5,10 +5,52 @@ include("shared.lua") local ACF = ACF +ENT.OverlayDelay = 1 -- Time in seconds between each overlay update + -- You should overwrite these function ENT:Enable() end function ENT:Disable() end -function ENT:UpdateOverlay() end +function ENT:UpdateOverlayText() end + +do -- Entity Overlay ---------------------------- + local Disable = "Disabled: %s\n%s" + local TimerName = "ACF Overlay Buffer %s" + local timer = timer + + local function GetText(Entity) + if Entity.Disabled then + return Entity:GetDisableText() + end + + return Entity:UpdateOverlayText() + end + + function ENT:GetDisableText() + return Disable:format(self.DisableReason, self.DisableDescription) + end + + function ENT:UpdateOverlay(Instant) + if Instant then + return self:SetOverlayText(GetText(self)) + end + + local Name = TimerName:format(self:EntIndex()) + + if timer.Exists(Name) then -- This entity has been updated too recently + self.OverlayBuffer = true -- Mark it to update when buffer time has expired + else + timer.Create(Name, self.OverlayDelay, 1, function() + if not IsValid(self) then return end + if not self.OverlayBuffer then return end + + self.OverlayBuffer = nil + self:UpdateOverlay() + end) + + self:SetOverlayText(GetText(self)) + end + end +end --------------------------------------------- do -- Entity linking and unlinking -------------- local LinkText = "%s can't be linked to %s." diff --git a/lua/entities/acf_engine/init.lua b/lua/entities/acf_engine/init.lua index 3a4ac761e..04daf62a5 100644 --- a/lua/entities/acf_engine/init.lua +++ b/lua/entities/acf_engine/init.lua @@ -108,7 +108,6 @@ local UnlinkSound = "physics/metal/metal_box_impact_bullet%s.wav" local Round = math.Round local max = math.max local TimerCreate = timer.Create -local TimerExists = timer.Exists local TimerSimple = timer.Simple local TimerRemove = timer.Remove local HookRun = hook.Run @@ -501,39 +500,17 @@ function ENT:UpdateOutputs() WireLib.TriggerOutput(self, "RPM", math.floor(self.FlyRPM)) end -local function Overlay(Ent) - if Ent.Disabled then - Ent:SetOverlayText("Disabled: " .. Ent.DisableReason .. "\n" .. Ent.DisableDescription) - else - local Text = "%s\n\n%s\nPower: %s kW / %s hp\nTorque: %s Nm / %s ft-lb\nPowerband: %s - %s RPM\nRedline: %s RPM" - local State, Name = Ent.Active and "Active" or "Idle", Ent.Name - local Power, PowerFt = Round(Ent.peakkw), Round(Ent.peakkw * 1.34) - local Torque, TorqueFt = Round(Ent.PeakTorque), Round(Ent.PeakTorque * 0.73) - local PowerbandMin = Ent.IsElectric and Ent.IdleRPM or Ent.PeakMinRPM - local PowerbandMax = Ent.IsElectric and math.floor(Ent.LimitRPM / 2) or Ent.PeakMaxRPM - local Redline = Ent.LimitRPM - - Ent:SetOverlayText(Text:format(State, Name, Power, PowerFt, Torque, TorqueFt, PowerbandMin, PowerbandMax, Redline)) - end -end +local Text = "%s\n\n%s\nPower: %s kW / %s hp\nTorque: %s Nm / %s ft-lb\nPowerband: %s - %s RPM\nRedline: %s RPM" -function ENT:UpdateOverlay(Instant) - if Instant then - return Overlay(self) - end +function ENT:UpdateOverlayText() + local State, Name = self.Active and "Active" or "Idle", self.Name + local Power, PowerFt = Round(self.peakkw), Round(self.peakkw * 1.34) + local Torque, TorqueFt = Round(self.PeakTorque), Round(self.PeakTorque * 0.73) + local PowerbandMin = self.IsElectric and self.IdleRPM or self.PeakMinRPM + local PowerbandMax = self.IsElectric and math.floor(self.LimitRPM / 2) or self.PeakMaxRPM + local Redline = self.LimitRPM - if TimerExists("ACF Overlay Buffer" .. self:EntIndex()) then -- This entity has been updated too recently - self.OverlayBuffer = true -- Mark it to update when buffer time has expired - else - TimerCreate("ACF Overlay Buffer" .. self:EntIndex(), 1, 1, function() - if IsValid(self) and self.OverlayBuffer then - self.OverlayBuffer = nil - self:UpdateOverlay() - end - end) - - Overlay(self) - end + return Text:format(State, Name, Power, PowerFt, Torque, TorqueFt, PowerbandMin, PowerbandMax, Redline) end ACF.AddInputAction("acf_engine", "Throttle", function(Entity, Value) diff --git a/lua/entities/acf_fueltank/init.lua b/lua/entities/acf_fueltank/init.lua index f36103534..7ddbf587f 100644 --- a/lua/entities/acf_fueltank/init.lua +++ b/lua/entities/acf_fueltank/init.lua @@ -370,57 +370,30 @@ do -- Mass Update end do -- Overlay Update - local function Overlay(Ent) - if Ent.Disabled then - Ent:SetOverlayText("Disabled: " .. Ent.DisableReason .. "\n" .. Ent.DisableDescription) - else - local Text - - if Ent.Leaking > 0 then - Text = "Leaking" - else - Text = Ent:CanConsume() and "Providing Fuel" or "Idle" - end - - Text = Text .. "\n\nFuel Type: " .. Ent.FuelType - - if Ent.FuelType == "Electric" then - local KiloWatt = math.Round(Ent.Fuel, 1) - local Joules = math.Round(Ent.Fuel * 3.6, 1) - - Text = Text .. "\nCharge Level: " .. KiloWatt .. " kWh / " .. Joules .. " MJ" - else - local Liters = math.Round(Ent.Fuel, 1) - - local Gallons = math.Round(Ent.Fuel * 0.264172, 1) - Text = Text .. "\nFuel Remaining: " .. Liters .. " liters / " .. Gallons .. " gallons" - end + local Text = "%s\n\nFuel Type: %s\n%s" - WireLib.TriggerOutput(Ent, "Fuel", math.Round(Ent.Fuel, 2)) - WireLib.TriggerOutput(Ent, "Capacity", math.Round(Ent.Capacity, 2)) - WireLib.TriggerOutput(Ent, "Leaking", Ent.Leaking > 0 and 1 or 0) + function ENT:UpdateOverlayText() + local Status, Content - Ent:SetOverlayText(Text) + if self.Leaking > 0 then + Status = "Leaking" + else + Status = self:CanConsume() and "Providing Fuel" or "Idle" end - end - function ENT:UpdateOverlay(Instant) - if Instant then - return Overlay(self) - end + if self.FuelType == "Electric" then -- TODO: Replace hardcoded stuff + local KiloWatt = math.Round(self.Fuel, 1) + local Joules = math.Round(self.Fuel * 3.6, 1) - if TimerExists("ACF Overlay Buffer" .. self:EntIndex()) then -- This entity has been updated too recently - self.OverlayBuffer = true -- Mark it to update when buffer time has expired + Content = "Charge Level: " .. KiloWatt .. " kWh / " .. Joules .. " MJ" else - TimerCreate("ACF Overlay Buffer" .. self:EntIndex(), 1, 1, function() - if IsValid(self) and self.OverlayBuffer then - self.OverlayBuffer = nil - self:UpdateOverlay() - end - end) + local Liters = math.Round(self.Fuel, 1) + local Gallons = math.Round(self.Fuel * 0.264172, 1) - Overlay(self) + Content = "Fuel Remaining: " .. Liters .. " liters / " .. Gallons .. " gallons" end + + return Text:format(Status, self.FuelType, Content) end end diff --git a/lua/entities/acf_gearbox/init.lua b/lua/entities/acf_gearbox/init.lua index 963dc45ea..d116a61ca 100644 --- a/lua/entities/acf_gearbox/init.lua +++ b/lua/entities/acf_gearbox/init.lua @@ -7,9 +7,6 @@ include("shared.lua") -- Local Funcs and Vars --===============================================================================================-- -local TimerCreate = timer.Create -local TimerExists = timer.Exists - local function CheckLoopedGearbox(This, Target) local Queued = { [Target] = true } local Checked = {} @@ -627,47 +624,25 @@ function ENT:Disable() self:UpdateOverlay() end -local function Overlay(Ent) - if Ent.Disabled then - Ent:SetOverlayText("Disabled: " .. Ent.DisableReason .. "\n" .. Ent.DisableDescription) - else - local Text = "Current Gear: " .. Ent.Gear .. "\n\n" .. Ent.Name .. "\n" - local GearsText = Ent.ClassData.GetGearsText and Ent.ClassData.GetGearsText(Ent) - local Gears = Ent.Gears +local Text = "%s\nCurrent Gear: %s\n\n%s\nFinal Driver: %s\nTorque Rating: %s Nm / %s fl-lb\nTorque Output: %s Nm / %s fl-lb" - if GearsText and GearsText ~= "" then - Text = Text .. GearsText .. "\n" - else - for i = 1, Ent.MaxGear do - Text = Text .. "Gear " .. i .. ": " .. math.Round(Gears[i], 2) .. "\n" - end - end +function ENT:UpdateOverlayText() + local GearsText = self.ClassData.GetGearsText and self.ClassData.GetGearsText(self) + local Final = math.Round(self.FinalDrive, 2) + local Torque = math.Round(self.MaxTorque * 0.73) + local Output = math.Round(self.TorqueOutput * 0.73) - Text = Text .. "Final Drive: " .. math.Round(Ent.FinalDrive, 2) .. "\n" - Text = Text .. "Torque Rating: " .. Ent.MaxTorque .. " Nm / " .. math.Round(Ent.MaxTorque * 0.73) .. " ft-lb\n" - Text = Text .. "Torque Output: " .. math.floor(Ent.TorqueOutput) .. " Nm / " .. math.Round(Ent.TorqueOutput * 0.73) .. " ft-lb" + if not GearsText or GearsText == "" then + local Gears = self.Gears - Ent:SetOverlayText(Text) - end -end + GearsText = "" -function ENT:UpdateOverlay(Instant) - if Instant then - return Overlay(self) + for I = 1, self.MaxGear do + GearsText = GearsText .. "Gear " .. I .. ": " .. math.Round(Gears[I], 2) .. "\n" + end end - if TimerExists("ACF Overlay Buffer" .. self:EntIndex()) then -- This entity has been updated too recently - self.OverlayBuffer = true -- Mark it to update when buffer time has expired - else - TimerCreate("ACF Overlay Buffer" .. self:EntIndex(), 1, 1, function() - self.OverlayBuffer = nil - if IsValid(self) and self.OverlayBuffer then - self:UpdateOverlay() - end - end) - Overlay(self) - - end + return Text:format(self.Name, self.Gear, GearsText, Final, self.MaxTorque, Torque, math.floor(self.TorqueOutput), Output) end -- prevent people from changing bodygroup diff --git a/lua/entities/acf_gun/init.lua b/lua/entities/acf_gun/init.lua index 39d107734..122b149d0 100644 --- a/lua/entities/acf_gun/init.lua +++ b/lua/entities/acf_gun/init.lua @@ -16,7 +16,6 @@ local AmmoTypes = ACF.Classes.AmmoTypes local TraceRes = {} -- Output for traces local TraceData = {start = true, endpos = true, filter = true, mask = MASK_SOLID, output = TraceRes} local Trace = util.TraceLine -local TimerExists = timer.Exists local TimerCreate = timer.Create local HookRun = hook.Run local EMPTY = { Type = "Empty", PropMass = 0, ProjMass = 0, Tracer = 0 } @@ -670,49 +669,27 @@ do -- Metamethods -------------------------------- end ----------------------------------------- do -- Overlay ------------------------------- - local function Overlay(Ent) - if Ent.Disabled then - Ent:SetOverlayText("Disabled: " .. Ent.DisableReason .. "\n" .. Ent.DisableDescription) - else - local Text = "%s\n\nRate of Fire: %s rpm\nShots Left: %s\nAmmo Available: %s" - local AmmoType = Ent.BulletData.Type .. (Ent.BulletData.Tracer ~= 0 and "-T" or "") - local Firerate = math.floor(60 / Ent.ReloadTime) - local CrateAmmo = 0 - local Status - - if not next(Ent.Crates) then - Status = "Not linked to an ammo crate!" - else - Status = Ent.State == "Loaded" and "Loaded with " .. AmmoType or Ent.State - end + local Text = "%s\n\nRate of Fire: %s rpm\nShots Left: %s\nAmmo Available: %s" - for Crate in pairs(Ent.Crates) do -- Tally up the amount of ammo being provided by active crates - if Crate:CanConsume() then - CrateAmmo = CrateAmmo + Crate.Ammo - end - end + function ENT:UpdateOverlayText() + local AmmoType = self.BulletData.Type .. (self.BulletData.Tracer ~= 0 and "-T" or "") + local Firerate = math.floor(60 / self.ReloadTime) + local CrateAmmo = 0 + local Status - Ent:SetOverlayText(Text:format(Status, Firerate, Ent.CurrentShot, CrateAmmo)) + if not next(self.Crates) then + Status = "Not linked to an ammo crate!" + else + Status = self.State == "Loaded" and "Loaded with " .. AmmoType or self.State end - end - function ENT:UpdateOverlay(Instant) - if Instant then - return Overlay(self) + for Crate in pairs(self.Crates) do -- Tally up the amount of ammo being provided by active crates + if Crate:CanConsume() then + CrateAmmo = CrateAmmo + Crate.Ammo + end end - if TimerExists("ACF Overlay Buffer" .. self:EntIndex()) then -- This entity has been updated too recently - self.OverlayBuffer = true -- Mark it to update when buffer time has expired - else - TimerCreate("ACF Overlay Buffer" .. self:EntIndex(), 1, 1, function() - if IsValid(self) and self.OverlayBuffer then - self.OverlayBuffer = nil - self:UpdateOverlay() - end - end) - - Overlay(self) - end + return Text:format(Status, Firerate, self.CurrentShot, CrateAmmo) end end ----------------------------------------- @@ -815,4 +792,4 @@ do -- Metamethods -------------------------------- WireLib.Remove(self) end end ----------------------------------------- -end \ No newline at end of file +end From b956c423362ed8c0d0303786e874b8259d0518a7 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Thu, 24 Dec 2020 13:27:10 -0300 Subject: [PATCH 233/279] Fixed error related to NULL panels - Fixed error when attempting to update data var related to panels not being cleaned. --- lua/acf/base/data_vars/cl_data_vars.lua | 5 +++++ lua/acf/server/persisted_vars.lua | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/lua/acf/base/data_vars/cl_data_vars.lua b/lua/acf/base/data_vars/cl_data_vars.lua index dbf0b3731..a012c86b7 100644 --- a/lua/acf/base/data_vars/cl_data_vars.lua +++ b/lua/acf/base/data_vars/cl_data_vars.lua @@ -304,6 +304,11 @@ do -- Panel functions if not Panels then return end for Panel in pairs(Panels) do + if not IsValid(Panel) then + ClearData(Panel) -- Somehow Panel:Remove is not being called + continue + end + local Result = Value if Panel.SetCustomValue then diff --git a/lua/acf/server/persisted_vars.lua b/lua/acf/server/persisted_vars.lua index 8260fd0df..fe8696aef 100644 --- a/lua/acf/server/persisted_vars.lua +++ b/lua/acf/server/persisted_vars.lua @@ -1,4 +1,5 @@ -- Variables that should be persisted between server restarts ACF.PersistServerData("ServerDataAllowAdmin", false) -ACF.PersistServerData("ShowFunMenu", true) \ No newline at end of file +ACF.PersistServerData("AllowFunEnts", true) +ACF.PersistServerData("ShowFunMenu", true) From 669eed8d556cefaf554b6a33ea1b069ed408f102 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Thu, 24 Dec 2020 14:50:02 -0300 Subject: [PATCH 234/279] Fixed error on weapon data verification - Fixed local Class variable not being updated if the given Weapon value is not registered on any of the weapon classes. --- lua/entities/acf_gun/init.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lua/entities/acf_gun/init.lua b/lua/entities/acf_gun/init.lua index 122b149d0..cda231c82 100644 --- a/lua/entities/acf_gun/init.lua +++ b/lua/entities/acf_gun/init.lua @@ -49,6 +49,8 @@ do -- Spawn and Update functions -------------------------------- if not Class then Data.Weapon = Data.Weapon and Updated[Data.Weapon] or "50mmC" + + Class = ACF.GetClassGroup(Weapons, Data.Weapon) end do -- External verifications From 1db8510161cf1d10c8f9db5754af927a5fa03237 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Fri, 25 Dec 2020 10:32:24 -0300 Subject: [PATCH 235/279] Changed arguments on ACF_AllowMenuX hooks - ACF_AllowMenuOption hook will now receive the option index and name as arguments. - ACF_AllowMenuItem hook will now receive the item index, option and name as arguments. --- lua/acf/client/spawn_menu.lua | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lua/acf/client/spawn_menu.lua b/lua/acf/client/spawn_menu.lua index df005cbfd..f73036769 100644 --- a/lua/acf/client/spawn_menu.lua +++ b/lua/acf/client/spawn_menu.lua @@ -58,6 +58,7 @@ do -- Menu population functions Icon = "icon16/" .. (Icon or "plugin") .. ".png", Action = Action or DefaultAction, IsEnabled = Enabled, + Option = Option, Index = Index, Name = Name, } @@ -67,6 +68,7 @@ do -- Menu population functions Item.Icon = "icon16/" .. (Icon or "plugin") .. ".png" Item.Action = Action or DefaultAction Item.IsEnabled = Enabled + Item.Option = Option Item.Index = Index Item.Name = Name end @@ -94,13 +96,13 @@ do -- ACF Menu context panel local function AllowOption(Option) if Option.IsEnabled and not Option:IsEnabled() then return false end - return hook.Run("ACF_AllowMenuOption", Option) ~= false + return hook.Run("ACF_AllowMenuOption", Option.Index, Option.Name) ~= false end local function AllowItem(Item) if Item.IsEnabled and not Item:IsEnabled() then return false end - return hook.Run("ACF_AllowMenuItem", Item) ~= false + return hook.Run("ACF_AllowMenuItem", Item.Index, Item.Option, Item.Name) ~= false end local function PopulateTree(Tree) From c69b46559316854471084bfff9c3a0182e31dca2 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sat, 26 Dec 2020 18:31:18 -0300 Subject: [PATCH 236/279] Entities will now store their caliber in mm - Updates all entities that stored their caliber, it'll now be saved in millimeters. - ACF.MinFuzeCaliber is, once again, on millimeters instead of centimeters. - Updated E2 and SF functions to retrieve the caliber of an entity. --- lua/acf/base/acf_globals.lua | 2 +- lua/acf/shared/ammo_types/aphe.lua | 2 +- lua/acf/shared/ammo_types/he.lua | 2 +- lua/acf/shared/ammo_types/heat.lua | 2 +- lua/acf/shared/ammo_types/smoke.lua | 2 +- lua/entities/acf_ammo/init.lua | 2 +- lua/entities/acf_gun/init.lua | 9 +++------ .../gmod_wire_expression2/core/custom/acffunctions.lua | 4 +--- lua/starfall/libs_sv/acffunctions.lua | 6 ++---- 9 files changed, 12 insertions(+), 19 deletions(-) diff --git a/lua/acf/base/acf_globals.lua b/lua/acf/base/acf_globals.lua index f79df3aec..3cff435c7 100644 --- a/lua/acf/base/acf_globals.lua +++ b/lua/acf/base/acf_globals.lua @@ -14,7 +14,7 @@ do -- ACF global vars ACF.EnableKillicons = true -- Enable killicons overwriting. -- Fuzes - ACF.MinFuzeCaliber = 2 -- Minimum caliber in centimeters that can be fuzed + ACF.MinFuzeCaliber = 20 -- Minimum caliber in millimeters that can be fuzed -- Reload Mechanics ACF.BaseReload = 1 -- Minimum reload time. Time it takes to move around a weightless projectile diff --git a/lua/acf/shared/ammo_types/aphe.lua b/lua/acf/shared/ammo_types/aphe.lua index a33cce93a..f514401b0 100644 --- a/lua/acf/shared/ammo_types/aphe.lua +++ b/lua/acf/shared/ammo_types/aphe.lua @@ -66,7 +66,7 @@ function Ammo:BaseConvert(ToolData) Data.LimitVel = 700 --Most efficient penetration speed in m/s Data.KETransfert = 0.1 --Kinetic energy transfert to the target for movement purposes Data.Ricochet = 65 --Base ricochet angle - Data.CanFuze = Data.Caliber > ACF.MinFuzeCaliber -- Can fuze on calibers > 20mm + Data.CanFuze = Data.Caliber * 10 > ACF.MinFuzeCaliber -- Can fuze on calibers > 20mm self:UpdateRoundData(ToolData, Data, GUIData) diff --git a/lua/acf/shared/ammo_types/he.lua b/lua/acf/shared/ammo_types/he.lua index 4e8bbeb80..7c8e65f81 100644 --- a/lua/acf/shared/ammo_types/he.lua +++ b/lua/acf/shared/ammo_types/he.lua @@ -67,7 +67,7 @@ function Ammo:BaseConvert(ToolData) Data.KETransfert = 0.1 --Kinetic energy transfert to the target for movement purposes Data.Ricochet = 60 --Base ricochet angle Data.DetonatorAngle = 80 - Data.CanFuze = Data.Caliber > ACF.MinFuzeCaliber -- Can fuze on calibers > 20mm + Data.CanFuze = Data.Caliber * 10 > ACF.MinFuzeCaliber -- Can fuze on calibers > 20mm self:UpdateRoundData(ToolData, Data, GUIData) diff --git a/lua/acf/shared/ammo_types/heat.lua b/lua/acf/shared/ammo_types/heat.lua index d45e147fe..cf7733527 100644 --- a/lua/acf/shared/ammo_types/heat.lua +++ b/lua/acf/shared/ammo_types/heat.lua @@ -128,7 +128,7 @@ function Ammo:BaseConvert(ToolData) Data.DetonatorAngle = 75 Data.Detonated = false Data.NotFirstPen = false - Data.CanFuze = Data.Caliber > ACF.MinFuzeCaliber -- Can fuze on calibers > 20mm + Data.CanFuze = Data.Caliber * 10 > ACF.MinFuzeCaliber -- Can fuze on calibers > 20mm self:UpdateRoundData(ToolData, Data, GUIData) diff --git a/lua/acf/shared/ammo_types/smoke.lua b/lua/acf/shared/ammo_types/smoke.lua index c0bbfe649..65523383e 100644 --- a/lua/acf/shared/ammo_types/smoke.lua +++ b/lua/acf/shared/ammo_types/smoke.lua @@ -84,7 +84,7 @@ function Ammo:BaseConvert(ToolData) Data.KETransfert = 0.1 --Kinetic energy transfert to the target for movement purposes Data.Ricochet = 60 --Base ricochet angle Data.DetonatorAngle = 80 - Data.CanFuze = Data.Caliber > ACF.MinFuzeCaliber -- Can fuze on calibers > 20mm + Data.CanFuze = Data.Caliber * 10 > ACF.MinFuzeCaliber -- Can fuze on calibers > 20mm self:UpdateRoundData(ToolData, Data, GUIData) diff --git a/lua/entities/acf_ammo/init.lua b/lua/entities/acf_ammo/init.lua index e2cf9838b..a2fa131e8 100644 --- a/lua/entities/acf_ammo/init.lua +++ b/lua/entities/acf_ammo/init.lua @@ -266,7 +266,7 @@ do -- Spawning and Updating -------------------- Entity.EntType = "Ammo Crate" Entity.ClassData = Class Entity.WeaponData = Weapon - Entity.Caliber = Weapon.Caliber * 0.1 + Entity.Caliber = Weapon.Caliber Entity.Class = Class.ID Entity:SetNWString("WireName", "ACF " .. (WireName or Weapon.Name .. " Ammo Crate")) diff --git a/lua/entities/acf_gun/init.lua b/lua/entities/acf_gun/init.lua index cda231c82..6fcfce728 100644 --- a/lua/entities/acf_gun/init.lua +++ b/lua/entities/acf_gun/init.lua @@ -95,8 +95,6 @@ do -- Spawn and Update functions -------------------------------- end local function UpdateWeapon(Entity, Data, Class, Weapon) - local Caliber = Weapon.Caliber * 0.1 - Entity:SetModel(Weapon.Model) Entity:PhysicsInit(SOLID_VPHYSICS) @@ -113,13 +111,12 @@ do -- Spawn and Update functions -------------------------------- Entity.ClassData = Class Entity.WeaponData = Weapon Entity.Class = Class.ID -- Needed for custom killicons - Entity.Caliber = Caliber + Entity.Caliber = Weapon.Caliber Entity.MagReload = Weapon.MagReload Entity.MagSize = Weapon.MagSize or 1 Entity.Cyclic = Weapon.Cyclic and 60 / Weapon.Cyclic Entity.ReloadTime = Entity.Cyclic or 1 Entity.Spread = Class.Spread - Entity.MinLengthBonus = 0.75 * 3.1416 * (Caliber * 0.5) ^ 2 * Weapon.Round.MaxLength Entity.HitBoxes = ACF.HitBoxes[Weapon.Model] Entity.Long = Class.LongBarrel Entity.NormalMuzzle = Entity:WorldToLocal(Entity:GetAttachment(Entity:LookupAttachment("muzzle")).Pos) @@ -431,7 +428,7 @@ do -- Metamethods -------------------------------- local Velocity = ACF_GetAncestor(self):GetVelocity() if self.BulletData.CanFuze and self.SetFuze then - local Variance = math.Rand(-0.015, 0.015) * (20.3 - self.Caliber) * 0.1 + local Variance = math.Rand(-0.015, 0.015) * math.max(0, 203 - self.Caliber) * 0.01 self.Fuze = math.max(self.SetFuze, 0.02) + Variance -- If possible, we're gonna update the fuze time else @@ -705,7 +702,7 @@ do -- Metamethods -------------------------------- local Volume = PhysObj:GetVolume() * 2 - local Armour = self.Caliber * 10 + local Armour = self.Caliber local Health = Volume / ACF.Threshold --Setting the threshold of the prop Area gone local Percent = 1 diff --git a/lua/entities/gmod_wire_expression2/core/custom/acffunctions.lua b/lua/entities/gmod_wire_expression2/core/custom/acffunctions.lua index 5a7a97914..ff55c90fc 100644 --- a/lua/entities/gmod_wire_expression2/core/custom/acffunctions.lua +++ b/lua/entities/gmod_wire_expression2/core/custom/acffunctions.lua @@ -966,9 +966,7 @@ e2function number entity:acfCaliber() if not IsACFEntity(this) then return 0 end if RestrictInfo(self, this) then return 0 end - local Caliber = this.Caliber - - return Caliber and Caliber * 10 or 0 + return this.Caliber or 0 end -- Returns the muzzle velocity of the ammo in a crate or gun diff --git a/lua/starfall/libs_sv/acffunctions.lua b/lua/starfall/libs_sv/acffunctions.lua index 7c2516479..1bf9c6a3c 100644 --- a/lua/starfall/libs_sv/acffunctions.lua +++ b/lua/starfall/libs_sv/acffunctions.lua @@ -1002,7 +1002,7 @@ function ents_methods:acfLinkTo(target, notify) return Success, Message end ---- TODO: Perform ACF unlinks +--- Perform ACF unlinks -- @server function ents_methods:acfUnlinkFrom(target, notify) CheckType(self, ents_metatable) @@ -1994,9 +1994,7 @@ function ents_methods:acfCaliber() if not IsACFEntity(This) then SF.Throw("Entity is not valid", 2) end if RestrictInfo(This) then return 0 end - local Caliber = This.Caliber - - return Caliber and Caliber * 10 or 0 + return This.Caliber or 0 end --- Returns the muzzle velocity of the ammo in a crate or gun From 3416cc5e0d4b8540c5e7337f72a6a6b6c34f3fc9 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Tue, 29 Dec 2020 03:11:21 -0300 Subject: [PATCH 237/279] Added settings tab and functions - Converted Settings item into a menu option with two items: Clientside and Serverside settings. - Added ACF.AddClientSettings and ACF.AddServerSettings function to add more settings options to the menu. - Added ACF_OnClientSettingsLoaded and ACF_OnServerSettingsLoaded hooks, called whenever a new settings tab is added to the menu. --- lua/acf/client/menu_items/settings_menu.lua | 66 ++++++++++----------- lua/acf/client/spawn_menu.lua | 57 +++++++++++++++++- lua/acf/server/persisted_vars.lua | 1 + 3 files changed, 90 insertions(+), 34 deletions(-) diff --git a/lua/acf/client/menu_items/settings_menu.lua b/lua/acf/client/menu_items/settings_menu.lua index 8ca2a9ed4..9e1de23ed 100644 --- a/lua/acf/client/menu_items/settings_menu.lua +++ b/lua/acf/client/menu_items/settings_menu.lua @@ -1,14 +1,27 @@ -local Ent_Info = GetConVar("acf_show_entity_info") -local InfoHelp = { - [0] = "ACF entities will never display their information bubble when the player looks at them.", - [1] = "ACF entities will only display their information bubble when the player looks at them while they're not seated.", - [2] = "ACF entities will always display their information bubble when a player looks at them." -} - -local function CreateMenu(Menu) - do -- Entity Information Settings +local ACF = ACF + +do -- Clientside settings + local Ent_Info = GetConVar("acf_show_entity_info") + local InfoHelp = { + [0] = "ACF entities will never display their information bubble when the player looks at them.", + [1] = "ACF entities will only display their information bubble when the player looks at them while they're not seated.", + [2] = "ACF entities will always display their information bubble when a player looks at them." + } + + ACF.AddMenuItem(1, "Settings", "Clientside Settings", "user", ACF.GenerateClientSettings) + + ACF.AddClientSettings("Effects and Visual Elements", function(Base) + local Ropes = Base:AddCheckBox("Create mobility rope links.") + Ropes:SetConVar("acf_mobilityropelinks") + + local Particles = Base:AddSlider("Particle Mult.", 0.1, 1, 2) + Particles:SetConVar("acf_cl_particlemul") + + Base:AddHelp("Defines the clientside particle multiplier, reduce it if you're experiencing lag when ACF effects are created.") + end) + + ACF.AddClientSettings("Entity Information", function(Base) local InfoValue = InfoHelp[Ent_Info:GetInt()] and Ent_Info:GetInt() or 1 - local Base = Menu:AddCollapsible("Entity Information") Base:AddLabel("Display ACF entity information:") @@ -40,36 +53,23 @@ local function CreateMenu(Menu) local Rounds = Base:AddSlider("Max Rounds", 0, 64, 0) Rounds:SetConVar("ACF_MaxRoundsDisplay") - Base:AddHelp("Requires hitboxes to be enabled. Defines the maximum amount of rounds an ammo crate needs to have before using bulk display.") - end - - do -- Legal Check Settings - local Base = Menu:AddCollapsible("Legal Checks") + Base:AddHelp("Defines the maximum amount of rounds an ammo crate needs to have before using bulk display.") + Base:AddHelp("Requires hitboxes to be enabled.") + end) + ACF.AddClientSettings("Legal Checks", function(Base) local Hints = Base:AddCheckBox("Enable hints on entity disabling.") Hints:SetConVar("acf_legalhints") - end - - do -- Aesthetic Settings - local Base = Menu:AddCollapsible("Aesthetic Settings") - - local Ropes = Base:AddCheckBox("Create mobility rope links.") - Ropes:SetConVar("acf_mobilityropelinks") - - local Particles = Base:AddSlider("Particle Mult.", 0.1, 1, 2) - Particles:SetConVar("acf_cl_particlemul") - - Base:AddHelp("Defines the clientside particle multiplier, reduce it if you're experiencing lag when ACF effects are created.") - end - - do -- Tool Settings - local Base = Menu:AddCollapsible("Tool Settings") + end) + ACF.AddClientSettings("Tool Category", function(Base) local Category = Base:AddCheckBox("Use custom category for ACF tools.") Category:SetConVar("acf_tool_category") Base:AddHelp("You will need to rejoin the server for this option to apply.") - end + end) end -ACF.AddMenuItem(201, "About the Addon", "Settings", "wrench", CreateMenu) +do -- Serverside settings + ACF.AddMenuItem(101, "Settings", "Serverside Settings", "server", ACF.GenerateServerSettings) +end \ No newline at end of file diff --git a/lua/acf/client/spawn_menu.lua b/lua/acf/client/spawn_menu.lua index f73036769..e3fa010c8 100644 --- a/lua/acf/client/spawn_menu.lua +++ b/lua/acf/client/spawn_menu.lua @@ -77,7 +77,8 @@ do -- Menu population functions ACF.AddMenuOption(1, "About the Addon", "information") ACF.AddMenuItem(101, "About the Addon", "Updates", "newspaper") -- TODO: Add Updates item - ACF.AddMenuOption(101, "Entities", "brick") + ACF.AddMenuOption(101, "Settings", "wrench") + ACF.AddMenuOption(201, "Entities", "brick") end do -- ACF Menu context panel @@ -219,3 +220,57 @@ do -- ACF Menu context panel PopulateTree(Tree) end end + +do -- Client and server settings + ACF.SettingsPanels = ACF.SettingsPanels or { + Client = {}, + Server = {}, + } + + local Settings = ACF.SettingsPanels + + --- Generates the following functions: + -- ACF.AddClientSettings(Name, Function) + -- ACF.RemoveClientSettings(Name) + -- ACF.GenerateClientSettings(MenuPanel) + -- ACF.AddServerSettings(Name, Function) + -- ACF.RemoveServerSettings(Name) + -- ACF.GenerateServerSettings(MenuPanel) + + for Realm in pairs(Settings) do + local Destiny = Settings[Realm] + local Hook = "ACF_On" .. Realm .. "SettingsLoaded" + local Message = "No %sside settings have been registered." + + ACF["Add" .. Realm .. "Settings"] = function(Name, Function) + if not isstring(Name) then return end + if not isfunction(Function) then return end + + Destiny[Name] = Function + end + + ACF["Remove" .. Realm .. "Settings"] = function(Name) + if not isstring(Name) then return end + + Destiny[Name] = nil + end + + ACF["Generate" .. Realm .. "Settings"] = function(Menu) + if not ispanel(Menu) then return end + + if not next(Destiny) then + Menu:AddTitle("Nothing to see here.") + Menu:AddLabel(Message:format(Realm)) + return + end + + for Name, Function in SortedPairs(Destiny) do + local Base = Menu:AddCollapsible(Name) + + Function(Base) + + hook.Run(Hook, Name, Base) + end + end + end +end diff --git a/lua/acf/server/persisted_vars.lua b/lua/acf/server/persisted_vars.lua index fe8696aef..2b8cfe72f 100644 --- a/lua/acf/server/persisted_vars.lua +++ b/lua/acf/server/persisted_vars.lua @@ -1,5 +1,6 @@ -- Variables that should be persisted between server restarts ACF.PersistServerData("ServerDataAllowAdmin", false) +ACF.PersistServerData("GunfireEnabled", true) ACF.PersistServerData("AllowFunEnts", true) ACF.PersistServerData("ShowFunMenu", true) From 4f3554c379f28c40164e3ea9c03f441fb1281fca Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Tue, 29 Dec 2020 18:37:19 -0300 Subject: [PATCH 238/279] Added Fun Entities and Custom Killicons server settings - Added Fun Entities and Menu server settings to the menu tool. - Added Custom Killicons server settings to the menu tool. ACF.EnableKillicons is no longer used and was therefore removed. --- lua/acf/base/acf_globals.lua | 1 - lua/acf/client/menu_items/settings_menu.lua | 34 +++ lua/acf/server/ballistics.lua | 2 + lua/acf/server/persisted_vars.lua | 1 + lua/acf/shared/killicons.lua | 278 +++++++++----------- 5 files changed, 167 insertions(+), 149 deletions(-) diff --git a/lua/acf/base/acf_globals.lua b/lua/acf/base/acf_globals.lua index 3cff435c7..da4d60a1e 100644 --- a/lua/acf/base/acf_globals.lua +++ b/lua/acf/base/acf_globals.lua @@ -11,7 +11,6 @@ do -- ACF global vars ACF.IllegalDisableTime = 30 -- Time in seconds for an entity to be disabled when it fails ACF_IsLegal ACF.GunfireEnabled = true ACF.SmokeWind = 5 + math.random() * 35 --affects the ability of smoke to be used for screening effect - ACF.EnableKillicons = true -- Enable killicons overwriting. -- Fuzes ACF.MinFuzeCaliber = 20 -- Minimum caliber in millimeters that can be fuzed diff --git a/lua/acf/client/menu_items/settings_menu.lua b/lua/acf/client/menu_items/settings_menu.lua index 9e1de23ed..1b4958bbf 100644 --- a/lua/acf/client/menu_items/settings_menu.lua +++ b/lua/acf/client/menu_items/settings_menu.lua @@ -72,4 +72,38 @@ end do -- Serverside settings ACF.AddMenuItem(101, "Settings", "Serverside Settings", "server", ACF.GenerateServerSettings) + + ACF.AddServerSettings("Fun Entities and Menu", function(Base) + local Entities = Base:AddCheckBox("Allow use of Fun Entities.") + Entities:SetServerData("AllowFunEnts", "OnChange") + Entities:DefineSetter(function(Panel, _, _, Value) + Panel:SetValue(Value) + + return Value + end) + + Base:AddHelp("Entities can be still spawned if this option is disabled.") + + local Menu = Base:AddCheckBox("Show Fun Entities menu option.") + Menu:SetServerData("ShowFunMenu", "OnChange") + Menu:DefineSetter(function(Panel, _, _, Value) + Panel:SetValue(Value) + + return Value + end) + + Base:AddHelp("Changes on this option will only take effect once the players reload their menu.") + end) + + ACF.AddServerSettings("Custom Killicons", function(Base) + local Icons = Base:AddCheckBox("Use custom killicons for ACF entities.") + Icons:SetServerData("UseKillicons", "OnChange") + Icons:DefineSetter(function(Panel, _, _, Value) + Panel:SetValue(Value) + + return Value + end) + + Base:AddHelp("Changing this option will require a server restart.") + end) end \ No newline at end of file diff --git a/lua/acf/server/ballistics.lua b/lua/acf/server/ballistics.lua index b30fbbc8f..85cf957ce 100644 --- a/lua/acf/server/ballistics.lua +++ b/lua/acf/server/ballistics.lua @@ -101,6 +101,8 @@ function ACF.RemoveBullet(Bullet) Bullet.Removed = true + ACF.BulletClient(Bullet, "Update", 1, Bullet.Pos) -- Kills the bullet on the clientside + if not next(Bullets) then hook.Remove("Tick", "IterateBullets") end diff --git a/lua/acf/server/persisted_vars.lua b/lua/acf/server/persisted_vars.lua index 2b8cfe72f..07c98cd96 100644 --- a/lua/acf/server/persisted_vars.lua +++ b/lua/acf/server/persisted_vars.lua @@ -3,4 +3,5 @@ ACF.PersistServerData("ServerDataAllowAdmin", false) ACF.PersistServerData("GunfireEnabled", true) ACF.PersistServerData("AllowFunEnts", true) +ACF.PersistServerData("UseKillicons", true) ACF.PersistServerData("ShowFunMenu", true) diff --git a/lua/acf/shared/killicons.lua b/lua/acf/shared/killicons.lua index 5bbfdd1fc..af5b86386 100644 --- a/lua/acf/shared/killicons.lua +++ b/lua/acf/shared/killicons.lua @@ -25,87 +25,77 @@ ------------------------------------------------------------------------------]] -if SERVER and ACF.EnableKillicons then - util.AddNetworkString( "ACF_PlayerKilledNPC" ) - util.AddNetworkString( "ACF_NPCKilledNPC" ) +local function ServerSideActions(Enabled) + if not SERVER then return end + if not Enabled then return end - local function ACF_OnNPCKilled( ent, attacker, inflictor ) - -- Don't spam the killfeed with scripted stuff - if ( ent:GetClass() == "npc_bullseye" or ent:GetClass() == "npc_launcher" ) then return end + util.AddNetworkString("ACF_PlayerKilledNPC") + util.AddNetworkString("ACF_NPCKilledNPC") + util.AddNetworkString("ACF_PlayerKilled") + util.AddNetworkString("ACF_PlayerKilledSelf") + util.AddNetworkString("ACF_PlayerKilledByPlayer") - if ( IsValid( attacker ) and attacker:GetClass() == "trigger_hurt" ) then attacker = ent end + hook.Add("OnNPCKilled", "ACF_OnNPCKilled", function(ent, attacker, inflictor) + -- Don't spam the killfeed with scripted stuff + if ent:GetClass() == "npc_bullseye" or ent:GetClass() == "npc_launcher" then return end + if IsValid(attacker) and attacker:GetClass() == "trigger_hurt" then attacker = ent end - if ( IsValid( attacker ) and attacker:IsVehicle() and IsValid( attacker:GetDriver() ) ) then + if IsValid(attacker) and attacker:IsVehicle() and IsValid(attacker:GetDriver()) then attacker = attacker:GetDriver() end - if ( !IsValid( inflictor ) and IsValid( attacker ) ) then + if not IsValid(inflictor) and IsValid(attacker) then inflictor = attacker end -- Convert the inflictor to the weapon that they're holding if we can. - if ( IsValid( inflictor ) and attacker == inflictor and ( inflictor:IsPlayer() or inflictor:IsNPC() ) ) then - + if IsValid(inflictor) and attacker == inflictor and (inflictor:IsPlayer() or inflictor:IsNPC()) then inflictor = inflictor:GetActiveWeapon() - if ( !IsValid( attacker ) ) then inflictor = attacker end + if not IsValid(attacker) then inflictor = attacker end end local InflictorClass = "worldspawn" - local AttackerClass = "worldspawn" + local AttackerClass = "worldspawn" - if ( IsValid( inflictor ) ) then - if inflictor.ACF and inflictor.Class and inflictor:GetClass() != "acf_ammo" then + if IsValid(inflictor) then + if inflictor.ACF and inflictor.Class and inflictor:GetClass() ~= "acf_ammo" then InflictorClass = "acf_" .. inflictor.Class else InflictorClass = inflictor:GetClass() end end - if ( IsValid( attacker ) ) then - + if IsValid(attacker) then AttackerClass = attacker:GetClass() - if ( attacker:IsPlayer() ) then - - net.Start( "ACF_PlayerKilledNPC" ) - - net.WriteString( ent:GetClass() ) - net.WriteString( InflictorClass ) - net.WriteEntity( attacker ) - + if attacker:IsPlayer() then + net.Start("ACF_PlayerKilledNPC") + net.WriteString(ent:GetClass()) + net.WriteString(InflictorClass) + net.WriteEntity(attacker) net.Broadcast() return end - end - if ( ent:GetClass() == "npc_turret_floor" ) then AttackerClass = ent:GetClass() end - - net.Start( "ACF_NPCKilledNPC" ) - - net.WriteString( ent:GetClass() ) - net.WriteString( InflictorClass ) - net.WriteString( AttackerClass ) + if ent:GetClass() == "npc_turret_floor" then AttackerClass = ent:GetClass() end + net.Start("ACF_NPCKilledNPC") + net.WriteString(ent:GetClass()) + net.WriteString(InflictorClass) + net.WriteString(AttackerClass) net.Broadcast() - end - hook.Add( "OnNPCKilled", "ACF_OnNPCKilled", ACF_OnNPCKilled ) - - util.AddNetworkString( "ACF_PlayerKilled" ) - util.AddNetworkString( "ACF_PlayerKilledSelf" ) - util.AddNetworkString( "ACF_PlayerKilledByPlayer" ) - - local function ACF_PlayerDeath( ply, inflictor, attacker ) + end) - if ( IsValid( attacker ) and attacker:GetClass() == "trigger_hurt" ) then attacker = ply end - - if ( IsValid( attacker ) and attacker:IsVehicle() and IsValid( attacker:GetDriver() ) ) then + hook.Add("PlayerDeath", "ACF_PlayerDeath", function(ply, inflictor, attacker) + if IsValid(attacker) and attacker:GetClass() == "trigger_hurt" then attacker = ply end + if IsValid(attacker) and attacker:IsVehicle() and IsValid(attacker:GetDriver()) then attacker = attacker:GetDriver() end - if ( !IsValid( inflictor ) and IsValid( attacker ) ) then + if not IsValid(inflictor) and IsValid(attacker) then inflictor = attacker end @@ -114,151 +104,143 @@ if SERVER and ACF.EnableKillicons then -- pistol but kill you by hitting you with their arm. local InflictorClass = "worldspawn" - if ( IsValid( inflictor ) and inflictor == attacker and ( inflictor:IsPlayer() or inflictor:IsNPC() ) ) then - + if IsValid(inflictor) and inflictor == attacker and (inflictor:IsPlayer() or inflictor:IsNPC()) then inflictor = inflictor:GetActiveWeapon() - if ( !IsValid( inflictor ) ) then inflictor = attacker end + + if not IsValid(inflictor) then inflictor = attacker end end - if inflictor.ACF and inflictor.Class and inflictor:GetClass() != "acf_ammo" then + if inflictor.ACF and inflictor.Class and inflictor:GetClass() ~= "acf_ammo" then InflictorClass = "acf_" .. inflictor.Class else InflictorClass = inflictor:GetClass() end - if ( attacker == ply ) then return end - - if ( attacker:IsPlayer() ) then - - net.Start( "ACF_PlayerKilledByPlayer" ) - - net.WriteEntity( ply ) - net.WriteString( InflictorClass ) - net.WriteEntity( attacker ) + if attacker == ply then return end + if attacker:IsPlayer() then + net.Start("ACF_PlayerKilledByPlayer") + net.WriteEntity(ply) + net.WriteString(InflictorClass) + net.WriteEntity(attacker) net.Broadcast() return end - net.Start( "ACF_PlayerKilled" ) - - net.WriteEntity( ply ) - net.WriteString( InflictorClass ) - net.WriteString( attacker:GetClass() ) - + net.Start("ACF_PlayerKilled") + net.WriteEntity(ply) + net.WriteString(InflictorClass) + net.WriteString(attacker:GetClass()) net.Broadcast() - end - hook.Add( "PlayerDeath", "ACF_PlayerDeath", ACF_PlayerDeath ) + end) end -if CLIENT then - local IconColor = Color( 200, 200, 48, 255 ) - - killicon.Add( "acf_gun", "HUD/killicons/acf_gun", IconColor ) - killicon.Add( "acf_ammo", "HUD/killicons/acf_ammo", IconColor ) - killicon.Add( "torch", "HUD/killicons/torch", IconColor ) - - if ACF.EnableKillicons then - killicon.Add( "acf_AC", "HUD/killicons/acf_AC", IconColor ) - killicon.Add( "acf_AL", "HUD/killicons/acf_AL", IconColor ) - killicon.Add( "acf_C", "HUD/killicons/acf_C", IconColor ) - killicon.Add( "acf_GL", "HUD/killicons/acf_GL", IconColor ) - killicon.Add( "acf_HMG", "HUD/killicons/acf_HMG", IconColor ) - killicon.Add( "acf_HW", "HUD/killicons/acf_HW", IconColor ) - killicon.Add( "acf_MG", "HUD/killicons/acf_MG", IconColor ) - killicon.Add( "acf_MO", "HUD/killicons/acf_MO", IconColor ) - killicon.Add( "acf_RAC", "HUD/killicons/acf_RAC", IconColor ) - killicon.Add( "acf_SA", "HUD/killicons/acf_SA", IconColor ) - - local function doNothing() - return false - end +local function ClientSideActions(Enabled) + if not CLIENT then return end - net.Receive( "PlayerKilledByPlayer", doNothing ) - net.Receive( "PlayerKilled", doNothing ) + local IconColor = Color(200, 200, 48) - net.Receive( "PlayerKilledNPC", doNothing ) - net.Receive( "NPCKilledNPC", doNothing ) + killicon.Add("acf_ammo", "HUD/killicons/acf_ammo", IconColor) + killicon.Add("acf_gun", "HUD/killicons/acf_gun", IconColor) + killicon.Add("torch", "HUD/killicons/torch", IconColor) - local function RecvPlayerKilledByPlayer() + if not Enabled then return end - local victim = net.ReadEntity() - local inflictor = net.ReadString() - local attacker = net.ReadEntity() + killicon.Add("acf_AC", "HUD/killicons/acf_AC", IconColor) + killicon.Add("acf_AL", "HUD/killicons/acf_AL", IconColor) + killicon.Add("acf_C", "HUD/killicons/acf_C", IconColor) + killicon.Add("acf_GL", "HUD/killicons/acf_GL", IconColor) + killicon.Add("acf_HMG", "HUD/killicons/acf_HMG", IconColor) + killicon.Add("acf_HW", "HUD/killicons/acf_HW", IconColor) + killicon.Add("acf_MG", "HUD/killicons/acf_MG", IconColor) + killicon.Add("acf_MO", "HUD/killicons/acf_MO", IconColor) + killicon.Add("acf_RAC", "HUD/killicons/acf_RAC", IconColor) + killicon.Add("acf_SA", "HUD/killicons/acf_SA", IconColor) - if ( !IsValid( attacker ) ) then return end - if ( !IsValid( victim ) ) then return end + local function doNothing() + return false + end - GAMEMODE:AddDeathNotice( attacker:Name(), attacker:Team(), inflictor, victim:Name(), victim:Team() ) + -- TODO: Overwrite these instead of creating new net messages. + net.Receive("PlayerKilledByPlayer", doNothing) + net.Receive("PlayerKilledNPC", doNothing) + net.Receive("PlayerKilled", doNothing) + net.Receive("NPCKilledNPC", doNothing) - end - net.Receive( "ACF_PlayerKilledByPlayer", RecvPlayerKilledByPlayer ) + net.Receive("ACF_PlayerKilledByPlayer", function() + local victim = net.ReadEntity() + local inflictor = net.ReadString() + local attacker = net.ReadEntity() - local function RecvPlayerKilledSelf() + if not IsValid(attacker) then return end + if not IsValid(victim) then return end - local victim = net.ReadEntity() - if ( !IsValid( victim ) ) then return end - GAMEMODE:AddDeathNotice( nil, 0, "suicide", victim:Name(), victim:Team() ) + GAMEMODE:AddDeathNotice(attacker:Name(), attacker:Team(), inflictor, victim:Name(), victim:Team()) + end) - end - net.Receive( "ACF_PlayerKilledSelf", RecvPlayerKilledSelf ) + net.Receive("ACF_PlayerKilledSelf", function() + local victim = net.ReadEntity() - local function RecvPlayerKilled() + if not IsValid(victim) then return end - local victim = net.ReadEntity() - if ( !IsValid( victim ) ) then return end - local inflictor = net.ReadString() - local attacker = "#" .. net.ReadString() + GAMEMODE:AddDeathNotice(nil, 0, "suicide", victim:Name(), victim:Team()) + end) - GAMEMODE:AddDeathNotice( attacker, -1, inflictor, victim:Name(), victim:Team() ) + net.Receive("ACF_PlayerKilled", function() + local victim = net.ReadEntity() + local inflictor = net.ReadString() + local attacker = "#" .. net.ReadString() - end - net.Receive( "ACF_PlayerKilled", RecvPlayerKilled ) + if not IsValid(victim) then return end - local function RecvPlayerKilledNPC() + GAMEMODE:AddDeathNotice(attacker, -1, inflictor, victim:Name(), victim:Team()) + end) - local victimtype = net.ReadString() - local victim = "#" .. victimtype - local inflictor = net.ReadString() - local attacker = net.ReadEntity() + net.Receive("ACF_PlayerKilledNPC", function() + local victimtype = net.ReadString() + local victim = "#" .. victimtype + local inflictor = net.ReadString() + local attacker = net.ReadEntity() - -- - -- For some reason the killer isn't known to us, so don't proceed. - -- - if ( !IsValid( attacker ) ) then return end + -- For some reason the killer isn't known to us, so don't proceed. + if not IsValid(attacker) then return end - GAMEMODE:AddDeathNotice( attacker:Name(), attacker:Team(), inflictor, victim, -1 ) + GAMEMODE:AddDeathNotice(attacker:Name(), attacker:Team(), inflictor, victim, -1) - local bIsLocalPlayer = ( IsValid(attacker) and attacker == LocalPlayer() ) + local bIsLocalPlayer = IsValid(attacker) and attacker == LocalPlayer() + local bIsEnemy = IsEnemyEntityName(victimtype) + local bIsFriend = IsFriendEntityName(victimtype) - local bIsEnemy = IsEnemyEntityName( victimtype ) - local bIsFriend = IsFriendEntityName( victimtype ) + if bIsLocalPlayer and bIsEnemy then + achievements.IncBaddies() + end - if ( bIsLocalPlayer and bIsEnemy ) then - achievements.IncBaddies() - end + if bIsLocalPlayer and bIsFriend then + achievements.IncGoodies() + end - if ( bIsLocalPlayer and bIsFriend ) then - achievements.IncGoodies() - end + if bIsLocalPlayer and not (bIsFriend or bIsEnemy) then + achievements.IncBystander() + end + end) - if ( bIsLocalPlayer and ( !bIsFriend and !bIsEnemy ) ) then - achievements.IncBystander() - end + net.Receive("ACF_NPCKilledNPC", function() + local victim = "#" .. net.ReadString() + local inflictor = net.ReadString() + local attacker = "#" .. net.ReadString() - end - net.Receive( "ACF_PlayerKilledNPC", RecvPlayerKilledNPC ) + GAMEMODE:AddDeathNotice(attacker, -1, inflictor, victim, -1) + end) +end - local function RecvNPCKilledNPC() +hook.Add("InitPostEntity", "ACF Custom Killicons", function() + local Enabled = ACF.GetServerBool("UseKillicons") - local victim = "#" .. net.ReadString() - local inflictor = net.ReadString() - local attacker = "#" .. net.ReadString() + print("peepee poopoo", Enabled) - GAMEMODE:AddDeathNotice( attacker, -1, inflictor, victim, -1 ) + ClientSideActions(Enabled) + ServerSideActions(Enabled) - end - net.Receive( "ACF_NPCKilledNPC", RecvNPCKilledNPC ) - end -end + hook.Remove("InitPostEntity", "ACF Custom Killicons") +end) From c4967787e538da78fc721139e71f7462b13bb923 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Thu, 31 Dec 2020 03:04:09 -0300 Subject: [PATCH 239/279] Improved scalable weapon specifications retrieval - The round table will now be used when attempting to get the weapon specification data from a scalable weapon class, along with the Caliber.Base field. - Removed unused network message. --- lua/acf/base/acf_globals.lua | 1 - lua/acf/base/sh_round_functions.lua | 14 ++++++-------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/lua/acf/base/acf_globals.lua b/lua/acf/base/acf_globals.lua index da4d60a1e..ec7139f6e 100644 --- a/lua/acf/base/acf_globals.lua +++ b/lua/acf/base/acf_globals.lua @@ -150,7 +150,6 @@ end if SERVER then util.AddNetworkString("ACF_UpdateEntity") - util.AddNetworkString("ACF_KilledByACF") util.AddNetworkString("ACF_RenderDamage") util.AddNetworkString("ACF_Notify") diff --git a/lua/acf/base/sh_round_functions.lua b/lua/acf/base/sh_round_functions.lua index 5dcd38608..68380804b 100644 --- a/lua/acf/base/sh_round_functions.lua +++ b/lua/acf/base/sh_round_functions.lua @@ -9,19 +9,17 @@ local function GetWeaponSpecs(ToolData) if not Class.IsScalable then local Weapon = Class.Lookup[ToolData.Weapon] + local Round = Weapon.Round - if not Weapon then return end - - local RoundData = Weapon.Round - - return Weapon.Caliber, RoundData.MaxLength, RoundData.PropMass + return Weapon.Caliber, Round.MaxLength, Round.PropMass end local Bounds = Class.Caliber - local Caliber = math.Clamp(ToolData.Caliber or 0, Bounds.Min, Bounds.Max) - local Scale = Caliber / Class.BaseCaliber + local Round = Weapon.Round + local Caliber = math.Clamp(ToolData.Caliber or Bounds.Base, Bounds.Min, Bounds.Max) + local Scale = Caliber / Bounds.Base - return Caliber, Class.BaseLength * Scale, Class.BaseProp * Scale + return Caliber, Round.MaxLength * Scale, Round.PropMass * Scale end function ACF.RoundBaseGunpowder(ToolData, Data) From ecf3d06310f2b86967215915e95523f6913e6150 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Thu, 31 Dec 2020 03:06:27 -0300 Subject: [PATCH 240/279] Added piledriver registration function - Added piledriver class and piledriver, only for backwards compatibility, registration functions. - Registered basic piledriver with backwards compatibility with GGG piledriver IDs. - Registed piledrivers as a weaponry source. - Removed redundant IsValid check inside ENT:CanFire on weapons. --- lua/acf/base/sh_classes.lua | 26 ++++++++++++++++++++++++ lua/acf/base/sh_round_functions.lua | 1 + lua/acf/shared/fun_stuff/piledriver.lua | 27 +++++++++++++++++++++++++ lua/entities/acf_gun/init.lua | 1 - 4 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 lua/acf/shared/fun_stuff/piledriver.lua diff --git a/lua/acf/base/sh_classes.lua b/lua/acf/base/sh_classes.lua index 0cb645949..3464eec1d 100644 --- a/lua/acf/base/sh_classes.lua +++ b/lua/acf/base/sh_classes.lua @@ -437,6 +437,32 @@ do -- Sensor registration functions end end +do -- Piledriver registration functions + ACF.Classes.Piledrivers = ACF.Classes.Piledrivers or {} + + local Piledrivers = ACF.Classes.Piledrivers + + function ACF.RegisterPiledriverClass(ID, Data) + local Group = AddClassGroup(ID, Piledrivers, Data) + + if not Group.LimitConVar then + Group.LimitConVar = { + Name = "_acf_piledriver", + Amount = 4, + Text = "Maximum amount of ACF piledrivers a player can create." + } + end + + AddSboxLimit(Group.LimitConVar) + + return Group + end + + function ACF.RegisterPiledriver(ID, ClassID, Data) + return AddGroupedClass(ID, ClassID, Piledrivers, Data) + end +end + do -- Entity class registration function ACF.Classes.Entities = ACF.Classes.Entities or {} diff --git a/lua/acf/base/sh_round_functions.lua b/lua/acf/base/sh_round_functions.lua index 68380804b..61027e630 100644 --- a/lua/acf/base/sh_round_functions.lua +++ b/lua/acf/base/sh_round_functions.lua @@ -70,6 +70,7 @@ function ACF.UpdateRoundSpecs(ToolData, Data, GUIData) end local Weaponry = { + Piledrivers = Classes.Piledrivers, Missiles = Classes.Missiles, Weapons = Classes.Weapons, } diff --git a/lua/acf/shared/fun_stuff/piledriver.lua b/lua/acf/shared/fun_stuff/piledriver.lua new file mode 100644 index 000000000..04c5c5a3c --- /dev/null +++ b/lua/acf/shared/fun_stuff/piledriver.lua @@ -0,0 +1,27 @@ +ACF.RegisterPiledriverClass("PD", { + Name = "Piledriver", + Description = "Formerly a piece of construction equipment, it was modified to be used in close-quarters combat. Doesn't actually drive piles.", + Model = "models/piledriver/piledriver_100mm.mdl", + IsScalable = true, + Caliber = { + Base = 100, + Min = 50, + Max = 300, + }, + Round = { + MaxLength = 45, + PropMass = 0, + } +}) + +ACF.RegisterPiledriver("75mmPD", "PD", { + Caliber = 75 +}) + +ACF.RegisterPiledriver("100mmPD", "PD", { + Caliber = 100 +}) + +ACF.RegisterPiledriver("150mmPD", "PD", { + Caliber = 150 +}) diff --git a/lua/entities/acf_gun/init.lua b/lua/entities/acf_gun/init.lua index 6fcfce728..2b5f6d4f5 100644 --- a/lua/entities/acf_gun/init.lua +++ b/lua/entities/acf_gun/init.lua @@ -384,7 +384,6 @@ do -- Metamethods -------------------------------- end function ENT:CanFire() - if not IsValid(self) then return false end -- Weapon doesn't exist if not self.Firing then return false end -- Nobody is holding the trigger if self.Disabled then return false end -- Disabled if self.State ~= "Loaded" then -- Weapon is not loaded From 383012dc24566101fc7a9b672a1b4a2b275b558a Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Thu, 31 Dec 2020 16:12:05 -0300 Subject: [PATCH 241/279] Moved a few functions out of acf_globals - Moved a few ballistic related function from acf_globals to sh_util. --- lua/acf/base/acf_globals.lua | 36 ---- lua/acf/base/util/sh_util.lua | 367 +++++++++++++++++++--------------- 2 files changed, 204 insertions(+), 199 deletions(-) diff --git a/lua/acf/base/acf_globals.lua b/lua/acf/base/acf_globals.lua index ec7139f6e..714ebc947 100644 --- a/lua/acf/base/acf_globals.lua +++ b/lua/acf/base/acf_globals.lua @@ -225,42 +225,6 @@ elseif CLIENT then --------------------------------------------- end -function switch(cases, arg) - local Var = cases[arg] - - return Var ~= nil and Var or cases.default -end - --- changes here will be automatically reflected in the armor properties tool -function ACF_CalcArmor(Area, Ductility, Mass) - return (Mass * 1000 / Area / 0.78) / (1 + Ductility) ^ 0.5 * ACF.ArmorMod -end - -function ACF_MuzzleVelocity(Propellant, Mass) - local PEnergy = ACF.PBase * ((1 + Propellant) ^ ACF.PScale - 1) - local Speed = ((PEnergy * 2000 / Mass) ^ ACF.MVScale) - local Final = Speed -- - Speed * math.Clamp(Speed/2000,0,0.5) - - return Final -end - -function ACF_Kinetic(Speed, Mass, LimitVel) - LimitVel = LimitVel or 99999 - Speed = Speed / 39.37 - - local Energy = { - Kinetic = (Mass * (Speed ^ 2)) / 2000, --Energy in KiloJoules - Momentum = Speed * Mass, - } - local KE = (Mass * (Speed ^ ACF.KinFudgeFactor)) / 2000 + Energy.Momentum - - Energy.Penetration = math.max(KE - (math.max(Speed - LimitVel, 0) ^ 2) / (LimitVel * 5) * (KE / 200) ^ 0.95, KE * 0.1) - --Energy.Penetration = math.max( KE - (math.max(Speed-LimitVel,0)^2)/(LimitVel*5) * (KE/200)^0.95 , KE*0.1 ) - --Energy.Penetration = math.max(Energy.Momentum^ACF.KinFudgeFactor - math.max(Speed-LimitVel,0)/(LimitVel*5) * Energy.Momentum , Energy.Momentum*0.1) - - return Energy -end - do -- ACF Notify ----------------------------------- if SERVER then function ACF_SendNotify(ply, success, msg) diff --git a/lua/acf/base/util/sh_util.lua b/lua/acf/base/util/sh_util.lua index b181e3695..471992f08 100644 --- a/lua/acf/base/util/sh_util.lua +++ b/lua/acf/base/util/sh_util.lua @@ -187,171 +187,13 @@ do -- Trace functions end end -do -- Sound aliases - local Stored = {} - local Lookup = {} - local Path = "sound/%s" - - local function CreateData(Name) - if not Lookup[Name] then - Lookup[Name] = { - Name = Name, - Children = {} - } - else - Stored[Name] = nil - end - - return Lookup[Name] - end - - local function RegisterAlias(Old, New) - if not isstring(Old) then return end - if not isstring(New) then return end - - Old = Old:lower() - New = New:lower() - - local OldData = CreateData(Old) - local NewData = CreateData(New) - - NewData.Children[OldData] = true - OldData.Parent = NewData - end - - local function GetParentSound(Name, List, Total) - for I = Total, 1, -1 do - local Sound = List[I].Name - - if file.Exists(Path:format(Sound), "GAME") then - Stored[Name] = Sound - - return Sound - end - end - end +-- Pretty much unused, should be moved into the ACF namespace or just removed +function switch(cases, arg) + local Var = cases[arg] - -- Note: This isn't syncronized between server and client. - -- If a sound happens to have multiple children, the result will differ between client and server. - local function GetChildSound(Name) - local Data = Lookup[Name] - local Next = Data.Children - local Checked = { [Data] = true } - - repeat - local New = {} - - for Child in pairs(Next) do - if Checked[Child] then continue end - - local Sound = Child.Name - - if file.Exists(Path:format(Sound), "GAME") then - Stored[Name] = Sound + if Var ~= nil then return Var end - return Sound - end - - for K in pairs(Child.Children) do - New[K] = true - end - - Checked[Child] = true - end - - Next = New - - until not next(Next) - end - - local function GetAlias(Name) - if not isstring(Name) then return end - - Name = Name:lower() - - if not Lookup[Name] then return Name end - if Stored[Name] then return Stored[Name] end - - local Checked, List = {}, {} - local Next = Lookup[Name] - local Count = 0 - - repeat - if Checked[Next] then break end - - Count = Count + 1 - - Checked[Next] = true - List[Count] = Next - - Next = Next.Parent - until not Next - - local Parent = GetParentSound(Name, List, Count) - if Parent then return Parent end - - local Children = GetChildSound(Name) - if Children then return Children end - - Stored[Name] = Name - - return Name - end - - function ACF.RegisterSoundAliases(Table) - if not istable(Table) then return end - - for K, V in pairs(Table) do - RegisterAlias(K, V) - end - end - - ACF.GetSoundAlias = GetAlias - - -- sound.Play hijacking - -- TODO: BURN THIS TO THE GROUND - sound.DefaultPlay = sound.DefaultPlay or sound.Play - - function sound.Play(Name, ...) - Name = GetAlias(Name) - - return sound.DefaultPlay(Name, ...) - end - - -- ENT:EmitSound hijacking - local ENT = FindMetaTable("Entity") - - ENT.DefaultEmitSound = ENT.DefaultEmitSound or ENT.EmitSound - - function ENT:EmitSound(Name, ...) - Name = GetAlias(Name) - - return self:DefaultEmitSound(Name, ...) - end - - -- CreateSound hijacking - DefaultCreateSound = DefaultCreateSound or CreateSound - - function CreateSound(Entity, Name, ...) - Name = GetAlias(Name) - - return DefaultCreateSound(Entity, Name, ...) - end - - -- Valid sound check - if CLIENT then - local SoundCache = {} - - function ACF.IsValidSound(Name) - Name = GetAlias(Name) - - if SoundCache[Name] == nil then - SoundCache[Name] = file.Exists(Path:format(Name), "GAME") - end - - return SoundCache[Name] - end - end + return cases.default end do -- Native type verification functions @@ -595,3 +437,202 @@ do -- File creation return util.JSONToTable(file.Read(FullPath, "DATA")) end end + +do -- Ballistic functions + -- changes here will be automatically reflected in the armor properties tool + function ACF_CalcArmor(Area, Ductility, Mass) + return (Mass * 1000 / Area / 0.78) / (1 + Ductility) ^ 0.5 * ACF.ArmorMod + end + + function ACF_MuzzleVelocity(Propellant, Mass) + local PEnergy = ACF.PBase * ((1 + Propellant) ^ ACF.PScale - 1) + local Speed = ((PEnergy * 2000 / Mass) ^ ACF.MVScale) + local Final = Speed -- - Speed * math.Clamp(Speed/2000,0,0.5) + + return Final + end + + function ACF_Kinetic(Speed, Mass, LimitVel) + LimitVel = LimitVel or 99999 + Speed = Speed / 39.37 + + local Energy = { + Kinetic = (Mass * (Speed ^ 2)) / 2000, --Energy in KiloJoules + Momentum = Speed * Mass, + } + local KE = (Mass * (Speed ^ ACF.KinFudgeFactor)) / 2000 + Energy.Momentum + + Energy.Penetration = math.max(KE - (math.max(Speed - LimitVel, 0) ^ 2) / (LimitVel * 5) * (KE / 200) ^ 0.95, KE * 0.1) + --Energy.Penetration = math.max( KE - (math.max(Speed-LimitVel,0)^2)/(LimitVel*5) * (KE/200)^0.95 , KE*0.1 ) + --Energy.Penetration = math.max(Energy.Momentum^ACF.KinFudgeFactor - math.max(Speed-LimitVel,0)/(LimitVel*5) * Energy.Momentum , Energy.Momentum*0.1) + + return Energy + end +end + +do -- Sound aliases + local Stored = {} + local Lookup = {} + local Path = "sound/%s" + + local function CreateData(Name) + if not Lookup[Name] then + Lookup[Name] = { + Name = Name, + Children = {} + } + else + Stored[Name] = nil + end + + return Lookup[Name] + end + + local function RegisterAlias(Old, New) + if not isstring(Old) then return end + if not isstring(New) then return end + + Old = Old:lower() + New = New:lower() + + local OldData = CreateData(Old) + local NewData = CreateData(New) + + NewData.Children[OldData] = true + OldData.Parent = NewData + end + + local function GetParentSound(Name, List, Total) + for I = Total, 1, -1 do + local Sound = List[I].Name + + if file.Exists(Path:format(Sound), "GAME") then + Stored[Name] = Sound + + return Sound + end + end + end + + -- Note: This isn't syncronized between server and client. + -- If a sound happens to have multiple children, the result will differ between client and server. + local function GetChildSound(Name) + local Data = Lookup[Name] + local Next = Data.Children + local Checked = { [Data] = true } + + repeat + local New = {} + + for Child in pairs(Next) do + if Checked[Child] then continue end + + local Sound = Child.Name + + if file.Exists(Path:format(Sound), "GAME") then + Stored[Name] = Sound + + return Sound + end + + for K in pairs(Child.Children) do + New[K] = true + end + + Checked[Child] = true + end + + Next = New + + until not next(Next) + end + + local function GetAlias(Name) + if not isstring(Name) then return end + + Name = Name:lower() + + if not Lookup[Name] then return Name end + if Stored[Name] then return Stored[Name] end + + local Checked, List = {}, {} + local Next = Lookup[Name] + local Count = 0 + + repeat + if Checked[Next] then break end + + Count = Count + 1 + + Checked[Next] = true + List[Count] = Next + + Next = Next.Parent + until not Next + + local Parent = GetParentSound(Name, List, Count) + if Parent then return Parent end + + local Children = GetChildSound(Name) + if Children then return Children end + + Stored[Name] = Name + + return Name + end + + function ACF.RegisterSoundAliases(Table) + if not istable(Table) then return end + + for K, V in pairs(Table) do + RegisterAlias(K, V) + end + end + + ACF.GetSoundAlias = GetAlias + + -- sound.Play hijacking + -- TODO: BURN THIS TO THE GROUND + sound.DefaultPlay = sound.DefaultPlay or sound.Play + + function sound.Play(Name, ...) + Name = GetAlias(Name) + + return sound.DefaultPlay(Name, ...) + end + + -- ENT:EmitSound hijacking + local ENT = FindMetaTable("Entity") + + ENT.DefaultEmitSound = ENT.DefaultEmitSound or ENT.EmitSound + + function ENT:EmitSound(Name, ...) + Name = GetAlias(Name) + + return self:DefaultEmitSound(Name, ...) + end + + -- CreateSound hijacking + DefaultCreateSound = DefaultCreateSound or CreateSound + + function CreateSound(Entity, Name, ...) + Name = GetAlias(Name) + + return DefaultCreateSound(Entity, Name, ...) + end + + -- Valid sound check + if CLIENT then + local SoundCache = {} + + function ACF.IsValidSound(Name) + Name = GetAlias(Name) + + if SoundCache[Name] == nil then + SoundCache[Name] = file.Exists(Path:format(Name), "GAME") + end + + return SoundCache[Name] + end + end +end From 8fcf03d4c549ab9e8da8efe21354d5a5439df99f Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Thu, 31 Dec 2020 16:24:20 -0300 Subject: [PATCH 242/279] Reverted isstring replacement - Reverted every case where isstring was replaced with ACF.CheckString since the first can actually check nil values without throwing errors. - Fixed ACF.CheckString missing its second argument. --- lua/acf/base/data_vars/cl_data_vars.lua | 8 ++++---- lua/acf/base/data_vars/sh_data_vars.lua | 2 +- lua/acf/base/data_vars/sv_data_vars.lua | 2 +- lua/acf/base/sh_classes.lua | 8 ++++---- lua/acf/base/sh_tool_functions.lua | 10 +++++----- lua/acf/base/util/sh_util.lua | 26 ++++++++++++------------- lua/acf/base/util/sv_util.lua | 4 ++-- 7 files changed, 30 insertions(+), 30 deletions(-) diff --git a/lua/acf/base/data_vars/cl_data_vars.lua b/lua/acf/base/data_vars/cl_data_vars.lua index a012c86b7..4d5640146 100644 --- a/lua/acf/base/data_vars/cl_data_vars.lua +++ b/lua/acf/base/data_vars/cl_data_vars.lua @@ -131,7 +131,7 @@ end do -- Client data setter function function ACF.SetClientData(Key, Value, Forced) - if not ACF.CheckString(Key) then return end + if not isstring(Key) then return end Value = Value or false @@ -147,7 +147,7 @@ end do -- Server data setter function function ACF.SetServerData(Key, Value, Forced) - if not ACF.CheckString(Key) then return end + if not isstring(Key) then return end local Player = LocalPlayer() @@ -355,7 +355,7 @@ do -- Panel functions for Type in pairs(Queued) do PanelMeta["Set" .. Type .. "Data"] = function(Panel, Key, Setter) - if not ACF.CheckString(Key) then return end + if not isstring(Key) then return end local Variables = ACF[Type .. "Data"] local SetFunction = ACF["Set" .. Type .. "Data"] @@ -375,7 +375,7 @@ do -- Panel functions end PanelMeta["Track" .. Type .. "Data"] = function(Panel, Key, Setter) - if not ACF.CheckString(Key) then return end + if not isstring(Key) then return end StoreData("Panels", Panel, Type, Key, "Tracker") StoreData(Type, Key, "Tracker", Panel) diff --git a/lua/acf/base/data_vars/sh_data_vars.lua b/lua/acf/base/data_vars/sh_data_vars.lua index 2341be8fc..bb0dca301 100644 --- a/lua/acf/base/data_vars/sh_data_vars.lua +++ b/lua/acf/base/data_vars/sh_data_vars.lua @@ -100,7 +100,7 @@ do -- Data persisting -- ACF.PersistClientData(Key, Default) - Clientside only ACF["Persist" .. Realm .. "Data"] = function(Key, Default) - if not ACF.CheckString(Key) then return end + if not isstring(Key) then return end if Default == nil then Default = "nil" end Keys[Key] = Default diff --git a/lua/acf/base/data_vars/sv_data_vars.lua b/lua/acf/base/data_vars/sv_data_vars.lua index c444d8676..c04293e04 100644 --- a/lua/acf/base/data_vars/sv_data_vars.lua +++ b/lua/acf/base/data_vars/sv_data_vars.lua @@ -180,7 +180,7 @@ end do -- Server data setter function function ACF.SetServerData(Key, Value, Forced) - if not ACF.CheckString(Key) then return end + if not isstring(Key) then return end Value = Value or false diff --git a/lua/acf/base/sh_classes.lua b/lua/acf/base/sh_classes.lua index 3464eec1d..406162948 100644 --- a/lua/acf/base/sh_classes.lua +++ b/lua/acf/base/sh_classes.lua @@ -502,7 +502,7 @@ do -- Entity class registration function end function ACF.RegisterEntityClass(Class, Function, ...) - if not ACF.CheckString(Class) then return end + if not isstring(Class) then return end if not isfunction(Function) then return end local Entity = GetEntityTable(Class) @@ -515,7 +515,7 @@ do -- Entity class registration function end function ACF.AddEntityArguments(Class, ...) - if not ACF.CheckString(Class) then return end + if not isstring(Class) then return end local Entity = GetEntityTable(Class) local Arguments = istable(...) and ... or { ... } @@ -533,7 +533,7 @@ do -- Entity class registration function end function ACF.GetEntityArguments(Class) - if not ACF.CheckString(Class) then return end + if not isstring(Class) then return end local Entity = GetEntityTable(Class) local List = {} @@ -546,7 +546,7 @@ do -- Entity class registration function end function ACF.CreateEntity(Class, Player, Position, Angles, Data, NoUndo) - if not ACF.CheckString(Class) then return false end + if not isstring(Class) then return false end local ClassData = ACF.GetEntityClass(Class) diff --git a/lua/acf/base/sh_tool_functions.lua b/lua/acf/base/sh_tool_functions.lua index 167ba6392..d365c605a 100644 --- a/lua/acf/base/sh_tool_functions.lua +++ b/lua/acf/base/sh_tool_functions.lua @@ -371,9 +371,9 @@ do -- Clientside Tool interaction local Value = "%s:%s" function ACF.SetToolMode(Tool, Stage, Op) - if not ACF.CheckString(Tool) then return end - if not ACF.CheckString(Stage) then return end - if not ACF.CheckString(Op) then return end + if not isstring(Tool) then return end + if not isstring(Stage) then return end + if not isstring(Op) then return end ACF.SetClientData(Key:format(Tool), Value:format(Stage, Op)) end @@ -435,8 +435,8 @@ do -- Generic Spawner/Linker operation creator end function ACF.CreateMenuOperation(Name, Primary, Secondary) - if not ACF.CheckString(Name) then return end - if not ACF.CheckString(Primary) then return end + if not isstring(Name) then return end + if not isstring(Primary) then return end Secondary = ACF.CheckString(Secondary) diff --git a/lua/acf/base/util/sh_util.lua b/lua/acf/base/util/sh_util.lua index 471992f08..6c5040441 100644 --- a/lua/acf/base/util/sh_util.lua +++ b/lua/acf/base/util/sh_util.lua @@ -203,8 +203,8 @@ do -- Native type verification functions return tonumber(Value) or Default end - function ACF.CheckString(Value) - if not Value then return Default end + function ACF.CheckString(Value, Default) + if Value == nil then return Default end return tostring(Value) or Default end @@ -266,7 +266,7 @@ do -- Attachment storage ------------------------------------------------------------------- function ACF.AddCustomAttachment(Model, Name, Pos, Ang, Bone) - if not ACF.CheckString(Model) then return end + if not isstring(Model) then return end SaveAttachments(Model, {{ Name = Name, @@ -277,14 +277,14 @@ do -- Attachment storage end function ACF.AddCustomAttachments(Model, Attachments) - if not ACF.CheckString(Model) then return end + if not isstring(Model) then return end if not istable(Attachments) then return end SaveAttachments(Model, Attachments) end function ACF.SetCustomAttachment(Model, Name, Pos, Ang, Bone) - if not ACF.CheckString(Model) then return end + if not isstring(Model) then return end SaveAttachments(Model, {{ Name = Name, @@ -295,14 +295,14 @@ do -- Attachment storage end function ACF.SetCustomAttachments(Model, Attachments) - if not ACF.CheckString(Model) then return end + if not isstring(Model) then return end if not istable(Attachments) then return end SaveAttachments(Model, Attachments, true) end function ACF.RemoveCustomAttachment(Model, Index) - if not ACF.CheckString(Model) then return end + if not isstring(Model) then return end local Data = GetModelData(Model, true) @@ -316,7 +316,7 @@ do -- Attachment storage end function ACF.RemoveCustomAttachments(Model) - if not ACF.CheckString(Model) then return end + if not isstring(Model) then return end local Data = GetModelData(Model, true) @@ -401,7 +401,7 @@ end do -- File creation function ACF.FolderExists(Path, Create) - if not ACF.CheckString(Path) then return end + if not isstring(Path) then return end local Exists = file.Exists(Path, "DATA") @@ -415,8 +415,8 @@ do -- File creation end function ACF.SaveToJSON(Path, Name, Table, GoodFormat) - if not ACF.CheckString(Path) then return end - if not ACF.CheckString(Name) then return end + if not isstring(Path) then return end + if not isstring(Name) then return end if not istable(Table) then return end ACF.FolderExists(Path, true) -- Creating the folder if it doesn't exist @@ -427,8 +427,8 @@ do -- File creation end function ACF.LoadFromFile(Path, Name) - if not ACF.CheckString(Path) then return end - if not ACF.CheckString(Name) then return end + if not isstring(Path) then return end + if not isstring(Name) then return end local FullPath = Path .. "/" .. Name diff --git a/lua/acf/base/util/sv_util.lua b/lua/acf/base/util/sv_util.lua index 8009b6b6f..0b4e8fd5d 100644 --- a/lua/acf/base/util/sv_util.lua +++ b/lua/acf/base/util/sv_util.lua @@ -286,7 +286,7 @@ do -- Extra overlay text local Classes = {} function ACF.RegisterOverlayText(ClassName, Identifier, Function) - if not ACF.CheckString(ClassName) then return end + if not isstring(ClassName) then return end if Identifier == nil then return end if not isfunction(Function) then return end @@ -302,7 +302,7 @@ do -- Extra overlay text end function ACF.RemoveOverlayText(ClassName, Identifier) - if not ACF.CheckString(ClassName) then return end + if not isstring(ClassName) then return end if Identifier == nil then return end local Class = Classes[ClassName] From 42af6670d0eab0f7b3100df9a3a625695caeb95c Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Thu, 31 Dec 2020 17:21:33 -0300 Subject: [PATCH 243/279] Added ACF_OnPlayerLoaded hook - Added serverside ACF_OnPlayerLoaded hook, will be called when the client is completely ready to send and receive network traffic. - Removed a debug print, please don't look for it. --- lua/acf/base/acf_globals.lua | 36 +++++++++++++++++++++-------- lua/acf/base/version/sv_version.lua | 10 +------- lua/acf/shared/killicons.lua | 2 -- 3 files changed, 27 insertions(+), 21 deletions(-) diff --git a/lua/acf/base/acf_globals.lua b/lua/acf/base/acf_globals.lua index 714ebc947..323c0506a 100644 --- a/lua/acf/base/acf_globals.lua +++ b/lua/acf/base/acf_globals.lua @@ -225,6 +225,26 @@ elseif CLIENT then --------------------------------------------- end +do -- Player loaded hook + -- PlayerInitialSpawn isn't reliable when it comes to network messages + -- So we'll ask the clientside to tell us when it's actually ready to send and receive net messages + -- For more info, see: https://wiki.facepunch.com/gmod/GM:PlayerInitialSpawn + if SERVER then + util.AddNetworkString("ACF_PlayerLoaded") + + net.Receive("ACF_PlayerLoaded", function(_, Player) + hook.Run("ACF_OnPlayerLoaded", Player) + end) + else + hook.Add("InitPostEntity", "ACF Player Loaded", function() + net.Start("ACF_PlayerLoaded") + net.SendToServer() + + hook.Remove("InitPostEntity", "ACF Player Loaded") + end) + end +end + do -- ACF Notify ----------------------------------- if SERVER then function ACF_SendNotify(ply, success, msg) @@ -251,7 +271,7 @@ do -- ACF Notify ----------------------------------- end ------------------------------------------------ do -- Render Damage -------------------------------- - hook.Add("PlayerInitialSpawn", "renderdamage", function(ply) + hook.Add("ACF_OnPlayerLoaded", "ACF Render Damage", function(ply) local Table = {} for _, v in pairs(ents.GetAll()) do @@ -321,18 +341,14 @@ do -- Smoke/Wind ----------------------------------- end end) - local function sendSmokeWind(ply) + hook.Add("ACF_OnPlayerLoaded", "ACF Send Smoke Wind", function(Player) net.Start("acf_smokewind") net.WriteFloat(ACF.SmokeWind) - net.Send(ply) - end - - hook.Add("PlayerInitialSpawn", "ACF_SendSmokeWind", sendSmokeWind) + net.Send(Player) + end) else - local function recvSmokeWind() + net.Receive("acf_smokewind", function() ACF.SmokeWind = net.ReadFloat() - end - - net.Receive("acf_smokewind", recvSmokeWind) + end) end end ------------------------------------------------ diff --git a/lua/acf/base/version/sv_version.lua b/lua/acf/base/version/sv_version.lua index 667b470d4..8d8fc1c35 100644 --- a/lua/acf/base/version/sv_version.lua +++ b/lua/acf/base/version/sv_version.lua @@ -171,17 +171,9 @@ end do -- Client syncronization util.AddNetworkString("ACF_VersionSync") - local function SyncInformation(Player) - if not IsValid(Player) then return end - + hook.Add("ACF_OnPlayerLoaded", "ACF_VersionSync", function(Player) net.Start("ACF_VersionSync") net.WriteTable(Repos) net.Send(Player) - end - - hook.Add("PlayerInitialSpawn", "ACF_VersionSync", function(Player) - timer.Simple(7.5, function() - SyncInformation(Player) - end) end) end diff --git a/lua/acf/shared/killicons.lua b/lua/acf/shared/killicons.lua index af5b86386..5f9776930 100644 --- a/lua/acf/shared/killicons.lua +++ b/lua/acf/shared/killicons.lua @@ -237,8 +237,6 @@ end hook.Add("InitPostEntity", "ACF Custom Killicons", function() local Enabled = ACF.GetServerBool("UseKillicons") - print("peepee poopoo", Enabled) - ClientSideActions(Enabled) ServerSideActions(Enabled) From 32be9f170b22b36070142a454df24cba03bd1175 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Fri, 1 Jan 2021 22:56:15 -0300 Subject: [PATCH 244/279] Improved ACF base entities overlay update - Improved ACF base entity overlay failing to update on certain cases due to timer.Exists giving inconsistent results. --- lua/entities/acf_base_scalable/init.lua | 42 +++++++++++++++---------- lua/entities/acf_base_simple/init.lua | 30 ++++++++++-------- 2 files changed, 42 insertions(+), 30 deletions(-) diff --git a/lua/entities/acf_base_scalable/init.lua b/lua/entities/acf_base_scalable/init.lua index a6b080188..b6f53e1ef 100644 --- a/lua/entities/acf_base_scalable/init.lua +++ b/lua/entities/acf_base_scalable/init.lua @@ -13,9 +13,17 @@ function ENT:Disable() end function ENT:UpdateOverlayText() end do -- Entity Overlay ---------------------------- - local Disable = "Disabled: %s\n%s" - local TimerName = "ACF Overlay Buffer %s" - local timer = timer + local Disable = "Disabled: %s\n%s" + local Name = "ACF Overlay Buffer %s" + local timer = timer + + local function GetText(Entity) + if Entity.Disabled then + return Entity:GetDisableText() + end + + return Entity:UpdateOverlayText() + end function ENT:GetDisableText() return Disable:format(self.DisableReason, self.DisableDescription) @@ -23,27 +31,27 @@ do -- Entity Overlay ---------------------------- function ENT:UpdateOverlay(Instant) if Instant then - local Text = Either(self.Disabled, self:GetDisableText(), self:UpdateOverlayText()) - - return self:SetOverlayText(Text) + return self:SetOverlayText(GetText(self)) end - local Name = TimerName:format(self:EntIndex()) - - if timer.Exists(Name) then -- This entity has been updated too recently - self.OverlayBuffer = true -- Mark it to update when buffer time has expired + if self.OverlayCooldown then -- This entity has been updated too recently + self.QueueOverlay = true -- Mark it to update when buffer time has expired else - timer.Create(Name, self.OverlayDelay, 1, function() + self:SetOverlayText(GetText(self)) + + self.OverlayCooldown = true + + timer.Create(Name:format(self:EntIndex()), self.OverlayDelay, 1, function() if not IsValid(self) then return end - if not self.OverlayBuffer then return end - self.OverlayBuffer = nil - self:UpdateOverlay() - end) + self.OverlayCooldown = nil - local Text = Either(self.Disabled, self:GetDisableText(), self:UpdateOverlayText()) + if self.QueueOverlay then + self.QueueOverlay = nil - self:SetOverlayText(Text) + self:UpdateOverlay() + end + end) end end end --------------------------------------------- diff --git a/lua/entities/acf_base_simple/init.lua b/lua/entities/acf_base_simple/init.lua index 7f86e2121..b6f53e1ef 100644 --- a/lua/entities/acf_base_simple/init.lua +++ b/lua/entities/acf_base_simple/init.lua @@ -13,9 +13,9 @@ function ENT:Disable() end function ENT:UpdateOverlayText() end do -- Entity Overlay ---------------------------- - local Disable = "Disabled: %s\n%s" - local TimerName = "ACF Overlay Buffer %s" - local timer = timer + local Disable = "Disabled: %s\n%s" + local Name = "ACF Overlay Buffer %s" + local timer = timer local function GetText(Entity) if Entity.Disabled then @@ -34,20 +34,24 @@ do -- Entity Overlay ---------------------------- return self:SetOverlayText(GetText(self)) end - local Name = TimerName:format(self:EntIndex()) - - if timer.Exists(Name) then -- This entity has been updated too recently - self.OverlayBuffer = true -- Mark it to update when buffer time has expired + if self.OverlayCooldown then -- This entity has been updated too recently + self.QueueOverlay = true -- Mark it to update when buffer time has expired else - timer.Create(Name, self.OverlayDelay, 1, function() + self:SetOverlayText(GetText(self)) + + self.OverlayCooldown = true + + timer.Create(Name:format(self:EntIndex()), self.OverlayDelay, 1, function() if not IsValid(self) then return end - if not self.OverlayBuffer then return end - self.OverlayBuffer = nil - self:UpdateOverlay() - end) + self.OverlayCooldown = nil - self:SetOverlayText(GetText(self)) + if self.QueueOverlay then + self.QueueOverlay = nil + + self:UpdateOverlay() + end + end) end end end --------------------------------------------- From fec1a0a1568d9569bc0a197d8a8ada79d28c8592 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sat, 2 Jan 2021 03:25:50 -0300 Subject: [PATCH 245/279] Added sound replacer support code for piledrivers - Added sound replacer tool support code for the upcoming piledriver entities. --- lua/acf/shared/fun_stuff/piledriver.lua | 2 ++ lua/weapons/gmod_tool/stools/acfsound.lua | 12 ++++++++++++ 2 files changed, 14 insertions(+) diff --git a/lua/acf/shared/fun_stuff/piledriver.lua b/lua/acf/shared/fun_stuff/piledriver.lua index 04c5c5a3c..10abb3769 100644 --- a/lua/acf/shared/fun_stuff/piledriver.lua +++ b/lua/acf/shared/fun_stuff/piledriver.lua @@ -3,6 +3,8 @@ ACF.RegisterPiledriverClass("PD", { Description = "Formerly a piece of construction equipment, it was modified to be used in close-quarters combat. Doesn't actually drive piles.", Model = "models/piledriver/piledriver_100mm.mdl", IsScalable = true, + MagSize = 15, + ChargeRate = 0.5, Caliber = { Base = 100, Min = 50, diff --git a/lua/weapons/gmod_tool/stools/acfsound.lua b/lua/weapons/gmod_tool/stools/acfsound.lua index 0f2b001c0..59e7e8303 100644 --- a/lua/weapons/gmod_tool/stools/acfsound.lua +++ b/lua/weapons/gmod_tool/stools/acfsound.lua @@ -50,6 +50,18 @@ Sounds.acf_engine = { end } +Sounds.acf_piledriver = { + GetSound = function(ent) + return { Sound = ent.SoundPath or "" } + end, + SetSound = function(ent, soundData) + ent.SoundPath = soundData.Sound + end, + ResetSound = function(ent) + ent.SoundPath = nil + end +} + local function ReplaceSound(_, Entity, data) if not IsValid(Entity) then return end local sound = data[1] From 59d4e9cfdd5ad0eca15ad10a72e076fec1695d35 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sun, 3 Jan 2021 16:24:08 -0300 Subject: [PATCH 246/279] Improved clientside bullet effect - Bullet indexes no longer have a limit. - Bullets can now set their Bullet.HideEffect flag to true to visually hide the clientside effect while also retaining the impact effects. - Bullets can set their Bullet.KillTime field with the desired CurTime where the bullet will exist for the last time. --- lua/acf/server/ballistics.lua | 9 ++++-- lua/effects/acf_bullet_effect.lua | 46 ++++++++++++++++++------------- 2 files changed, 33 insertions(+), 22 deletions(-) diff --git a/lua/acf/server/ballistics.lua b/lua/acf/server/ballistics.lua index 85cf957ce..64ae30819 100644 --- a/lua/acf/server/ballistics.lua +++ b/lua/acf/server/ballistics.lua @@ -67,8 +67,9 @@ function ACF.BulletClient(Bullet, Type, Hit, HitPos) if Bullet.NoEffect then return end -- No clientside effect will be created for this bullet local Effect = EffectData() - Effect:SetHitBox(Bullet.Index) + Effect:SetDamageType(Bullet.Index) Effect:SetStart(Bullet.Flight * 0.1) + Effect:SetAttachment(Bullet.HideEffect and 0 or 1) if Type == "Update" then if Hit > 0 then @@ -80,7 +81,7 @@ function ACF.BulletClient(Bullet, Type, Hit, HitPos) Effect:SetScale(Hit) else Effect:SetOrigin(Bullet.Pos) - Effect:SetEntity(Entity(Bullet.Crate)) + Effect:SetEntIndex(Bullet.Crate) Effect:SetScale(0) end @@ -109,7 +110,9 @@ function ACF.RemoveBullet(Bullet) end function ACF.CalcBulletFlight(Bullet) - if not Bullet.LastThink then return ACF.RemoveBullet(Bullet) end + if Bullet.KillTime and ACF.CurTime > Bullet.KillTime then + return ACF.RemoveBullet(Bullet) + end if Bullet.PreCalcFlight then Bullet:PreCalcFlight() diff --git a/lua/effects/acf_bullet_effect.lua b/lua/effects/acf_bullet_effect.lua index 65945f96f..17ceaa101 100644 --- a/lua/effects/acf_bullet_effect.lua +++ b/lua/effects/acf_bullet_effect.lua @@ -4,7 +4,7 @@ local AmmoTypes = ACF.Classes.AmmoTypes local Bullets = ACF.BulletEffect function EFFECT:Init(Data) - self.Index = Data:GetHitBox() + self.Index = Data:GetDamageType() self:SetModel("models/munitions/round_100mm_shot.mdl") @@ -16,16 +16,18 @@ function EFFECT:Init(Data) self.CreateTime = ACF.CurTime - local Bullet = Bullets[self.Index] - local Flight = Data:GetStart() * 10 - local Origin = Data:GetOrigin() - local Hit = Data:GetScale() + local CanDraw = Data:GetAttachment() > 0 + local Bullet = Bullets[self.Index] + local Flight = Data:GetStart() * 10 + local Origin = Data:GetOrigin() + local Hit = Data:GetScale() -- Scale encodes the hit type, so if it's 0 it's a new bullet, else it's an update so we need to remove the effect if Bullet and Hit > 0 then local RoundData = AmmoTypes[Bullet.AmmoType] -- Updating old effect with new values + Bullet.Effect.DrawEffect = CanDraw Bullet.SimFlight = Flight Bullet.SimPos = Origin @@ -57,21 +59,21 @@ function EFFECT:Init(Data) -- TODO: Force crates to network and store this information on the client when they're created local Tracer = Crate:GetNW2Float("Tracer") > 0 local BulletData = { - Crate = Crate, - SimFlight = Flight, - SimPos = Origin, + Crate = Crate, + SimFlight = Flight, + SimPos = Origin, SimPosLast = Origin, - Caliber = Crate:GetNW2Float("Caliber", 10), - RoundMass = Crate:GetNW2Float("ProjMass", 10), + Caliber = Crate:GetNW2Float("Caliber", 10), + RoundMass = Crate:GetNW2Float("ProjMass", 10), FillerMass = Crate:GetNW2Float("FillerMass"), - WPMass = Crate:GetNW2Float("WPMass"), - DragCoef = Crate:GetNW2Float("DragCoef", 1), - AmmoType = Crate:GetNW2String("AmmoType", "AP"), - Tracer = Tracer and ParticleEmitter(Origin) or nil, - TracerColour = Tracer and Crate:GetColor() or nil, - Accel = Crate:GetNW2Vector("Accel", Vector(0, 0, -600)), - LastThink = ACF.CurTime, - Effect = self, + WPMass = Crate:GetNW2Float("WPMass"), + DragCoef = Crate:GetNW2Float("DragCoef", 1), + AmmoType = Crate:GetNW2String("AmmoType", "AP"), + Tracer = Tracer and ParticleEmitter(Origin) or nil, + Color = Tracer and Crate:GetColor() or nil, + Accel = Crate:GetNW2Vector("Accel", Vector(0, 0, -600)), + LastThink = ACF.CurTime, + Effect = self, } --Add all that data to the bullet table, overwriting if needed @@ -81,6 +83,8 @@ function EFFECT:Init(Data) self:SetAngles(Flight:Angle()) self:SetModelScale(BulletData.Caliber * 0.1, 0) + self.DrawEffect = CanDraw + local CustomEffect = hook.Run("ACF_BulletEffect", BulletData.AmmoType) if CustomEffect then @@ -120,6 +124,8 @@ function EFFECT:ApplyMovement(Bullet) self:SetAngles(Bullet.SimFlight:Angle()) end + if not self.DrawEffect then return end + if Bullet.Tracer and IsValid(Bullet.Tracer) then local DeltaPos = Position - Bullet.SimPosLast local Length = math.max(DeltaPos:Length() * 2, 1) @@ -127,7 +133,7 @@ function EFFECT:ApplyMovement(Bullet) local Light = Bullet.Tracer:Add("sprites/acf_tracer.vmt", Position) if Light then - local Color = Bullet.TracerColour + local Color = Bullet.Color Light:SetAngles(Bullet.SimFlight:Angle()) Light:SetVelocity(Bullet.SimFlight:GetNormalized()) @@ -162,5 +168,7 @@ function EFFECT:ApplyMovement(Bullet) end function EFFECT:Render() + if not self.DrawEffect then return end + self:DrawModel() end \ No newline at end of file From 04537c091da47e697d1f6b0acbbae98412023821 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sun, 3 Jan 2021 16:26:01 -0300 Subject: [PATCH 247/279] Fixed typo - Fixed a typo when attempting to get the weapon data specifications from a scalable weapon class. --- lua/acf/base/sh_round_functions.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/acf/base/sh_round_functions.lua b/lua/acf/base/sh_round_functions.lua index 61027e630..94e91c342 100644 --- a/lua/acf/base/sh_round_functions.lua +++ b/lua/acf/base/sh_round_functions.lua @@ -15,7 +15,7 @@ local function GetWeaponSpecs(ToolData) end local Bounds = Class.Caliber - local Round = Weapon.Round + local Round = Class.Round local Caliber = math.Clamp(ToolData.Caliber or Bounds.Base, Bounds.Min, Bounds.Max) local Scale = Caliber / Bounds.Base From c698ce7522cee72c5f205001f3b82390d898ff73 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sun, 3 Jan 2021 16:26:58 -0300 Subject: [PATCH 248/279] Added custom attachments to piledrivers - Added custom attachments to the piledriver model to prevent scaling issues. --- lua/acf/shared/fun_stuff/piledriver.lua | 5 +++++ lua/entities/acf_ammo/init.lua | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/lua/acf/shared/fun_stuff/piledriver.lua b/lua/acf/shared/fun_stuff/piledriver.lua index 10abb3769..b482ad74f 100644 --- a/lua/acf/shared/fun_stuff/piledriver.lua +++ b/lua/acf/shared/fun_stuff/piledriver.lua @@ -27,3 +27,8 @@ ACF.RegisterPiledriver("100mmPD", "PD", { ACF.RegisterPiledriver("150mmPD", "PD", { Caliber = 150 }) + +ACF.SetCustomAttachments("models/piledriver/piledriver_100mm.mdl", { + { Name = "muzzle", Pos = Vector(20), Ang = Angle() }, + { Name = "tip", Pos = Vector(65), Ang = Angle() }, +}) diff --git a/lua/entities/acf_ammo/init.lua b/lua/entities/acf_ammo/init.lua index a2fa131e8..875f0f6e5 100644 --- a/lua/entities/acf_ammo/init.lua +++ b/lua/entities/acf_ammo/init.lua @@ -224,7 +224,7 @@ do -- Spawning and Updating -------------------- Size.z = math.Clamp(Size.z, 6, 96) end - if not Data.Destiny then + if not isstring(Data.Destiny) then Data.Destiny = ACF.FindWeaponrySource(Data.Weapon) or "Weapons" end From 9daed61f16014eb16318d0a41a8729d5bfa5263b Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sat, 9 Jan 2021 04:20:10 -0300 Subject: [PATCH 249/279] Added more information to piledriver registration - Piledriver registration will now store the base mass, cyclic fire rate and preview settings. - Piledriver registration function will restrict the cyclic fire rate to 120 rounds per minute at most. --- lua/acf/base/sh_classes.lua | 2 ++ lua/acf/shared/fun_stuff/piledriver.lua | 11 +++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/lua/acf/base/sh_classes.lua b/lua/acf/base/sh_classes.lua index 406162948..78365a670 100644 --- a/lua/acf/base/sh_classes.lua +++ b/lua/acf/base/sh_classes.lua @@ -445,6 +445,8 @@ do -- Piledriver registration functions function ACF.RegisterPiledriverClass(ID, Data) local Group = AddClassGroup(ID, Piledrivers, Data) + Group.Cyclic = math.min(120, Group.Cyclic or 60) + if not Group.LimitConVar then Group.LimitConVar = { Name = "_acf_piledriver", diff --git a/lua/acf/shared/fun_stuff/piledriver.lua b/lua/acf/shared/fun_stuff/piledriver.lua index b482ad74f..b1224b635 100644 --- a/lua/acf/shared/fun_stuff/piledriver.lua +++ b/lua/acf/shared/fun_stuff/piledriver.lua @@ -3,7 +3,9 @@ ACF.RegisterPiledriverClass("PD", { Description = "Formerly a piece of construction equipment, it was modified to be used in close-quarters combat. Doesn't actually drive piles.", Model = "models/piledriver/piledriver_100mm.mdl", IsScalable = true, + Mass = 1200, -- Relative to the Base caliber MagSize = 15, + Cyclic = 60, ChargeRate = 0.5, Caliber = { Base = 100, @@ -11,9 +13,14 @@ ACF.RegisterPiledriverClass("PD", { Max = 300, }, Round = { - MaxLength = 45, + MaxLength = 45, -- Relative to the Base caliber PropMass = 0, - } + }, + Preview = { + Position = Vector(0, 0, -5), + Offset = Vector(45, 45, 20), + Height = 120, + }, }) ACF.RegisterPiledriver("75mmPD", "PD", { From 584a93e45a2abf1e11c2926bb99143deaec10369 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sat, 9 Jan 2021 04:21:53 -0300 Subject: [PATCH 250/279] Minor changes to ballistics and ammo menu - Renamed flag to hide the clientside effect from HideEffect to just Hide. - Added a simple patch to deal with ammo settings text not being updated on the ammo menu. --- lua/acf/client/ammo_menu.lua | 3 +++ lua/acf/server/ballistics.lua | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/lua/acf/client/ammo_menu.lua b/lua/acf/client/ammo_menu.lua index 11cdf15d8..fe01f6114 100644 --- a/lua/acf/client/ammo_menu.lua +++ b/lua/acf/client/ammo_menu.lua @@ -214,6 +214,9 @@ function ACF.CreateAmmoMenu(Menu, Settings) Desc:SetText(Data.Description) ACF.UpdateAmmoMenu(Menu, Settings) + + -- Best patch 2021 + ACF.SetClientData("Projectile", ACF.GetClientNumber("Projectile"), true) end Menu.AmmoBase = Base diff --git a/lua/acf/server/ballistics.lua b/lua/acf/server/ballistics.lua index 64ae30819..740f1e69b 100644 --- a/lua/acf/server/ballistics.lua +++ b/lua/acf/server/ballistics.lua @@ -69,7 +69,7 @@ function ACF.BulletClient(Bullet, Type, Hit, HitPos) local Effect = EffectData() Effect:SetDamageType(Bullet.Index) Effect:SetStart(Bullet.Flight * 0.1) - Effect:SetAttachment(Bullet.HideEffect and 0 or 1) + Effect:SetAttachment(Bullet.Hide and 0 or 1) if Type == "Update" then if Hit > 0 then From f893306cd92984a7b8ac609cde3db930bf5c33dc Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sat, 9 Jan 2021 04:26:06 -0300 Subject: [PATCH 251/279] Added Fun Stuff menu option - Added Fun Stuff menu option, it'll attempt to stay at the bottom of the list. - Added Piledriver Menu item to the Fun Stuff option. - Fun Stuff option will not be displayed if the server has ShowFunMenu set to false. --- lua/acf/client/menu_items/fun_menu.lua | 127 +++++++++++++++++++++++++ lua/acf/client/spawn_menu.lua | 1 + 2 files changed, 128 insertions(+) create mode 100644 lua/acf/client/menu_items/fun_menu.lua diff --git a/lua/acf/client/menu_items/fun_menu.lua b/lua/acf/client/menu_items/fun_menu.lua new file mode 100644 index 000000000..08fab5209 --- /dev/null +++ b/lua/acf/client/menu_items/fun_menu.lua @@ -0,0 +1,127 @@ +local ACF = ACF + +do -- Piledrivers menu + local Info = "Mass : %s kg\nRate of Fire : %s rpm\nMax Charges : %s\nRecharge Rate : %s charges/s" + local Stats = "Penetration : %s mm RHA\nSpike Velocity : %s m/s\nSpike Length : %s cm\nSpike Mass : %s" + local Piledrivers = ACF.Classes.Piledrivers + local AmmoTypes = ACF.Classes.AmmoTypes + local Ammo, BulletData + + local function CreateMenu(Menu) + Menu:AddTitle("Piledriver Settings") + + local ClassList = Menu:AddComboBox() + local Caliber = Menu:AddSlider("Caliber", 0, 1, 2) + + local ClassBase = Menu:AddCollapsible("Piledriver Information") + local ClassName = ClassBase:AddTitle() + local ClassDesc = ClassBase:AddLabel() + local ClassPreview = ClassBase:AddModelPreview() + local ClassInfo = ClassBase:AddLabel() + local ClassStats = ClassBase:AddLabel() + + ClassBase:AddLabel("This entity can be fully parented.") + + ACF.SetClientData("PrimaryClass", "acf_piledriver") + ACF.SetClientData("SecondaryClass", "N/A") + ACF.SetClientData("Destiny", "Piledrivers") + ACF.SetClientData("AmmoType", "AP") + ACF.SetClientData("Propellant", 0) + ACF.SetClientData("Tracer", false) + + ACF.SetToolMode("acf_menu", "Spawner", "Weapon") + + function ClassList:OnSelect(Index, _, Data) + if self.Selected == Data then return end + + self.ListData.Index = Index + self.Selected = Data + + local Preview = Data.Preview + local Bounds = Data.Caliber + local Min, Max = Bounds.Min, Bounds.Max + local Current = math.Clamp(ACF.GetClientNumber("Caliber", Min), Min, Max) + + Ammo = AmmoTypes.AP() + + Caliber:SetMinMax(Min, Max) + + ClassDesc:SetText(Data.Description) + + ClassPreview:SetModel(Data.Model) + ClassPreview:SetCamPos(Preview and Preview.Offset or Vector(45, 60, 45)) + ClassPreview:SetLookAt(Preview and Preview.Position or Vector()) + ClassPreview:SetHeight(Preview and Preview.Height or 80) + ClassPreview:SetFOV(Preview and Preview.FOV or 75) + + ACF.SetClientData("Weapon", Data.ID) + ACF.SetClientData("Caliber", Current, true) + end + + Caliber:SetClientData("Caliber", "OnValueChanged") + Caliber:DefineSetter(function(Panel, _, _, Value) + if not ClassList.Selected then return Value end + + local Class = ClassList.Selected + local Scale = Value / Class.Caliber.Base + local Length = Class.Round.MaxLength * Scale + + Ammo.SpikeLength = Length + + ACF.SetClientData("Projectile", Length) + + BulletData = Ammo:ClientConvert(ACF.GetAllClientData()) + + Panel:SetValue(Value) + + return Value + end) + + ClassName:TrackClientData("Weapon", "SetText") + ClassName:TrackClientData("Caliber") + ClassName:DefineSetter(function() + local Current = math.Round(Caliber:GetValue(), 2) + local Name = ClassList.Selected.Name + + return Current .. "mm " .. Name + end) + + ClassInfo:TrackClientData("Weapon", "SetText") + ClassInfo:TrackClientData("Caliber") + ClassInfo:DefineSetter(function() + if not BulletData then return "" end + + local Class = ClassList.Selected + local Current = math.Round(Caliber:GetValue(), 2) + local Scale = Current / Class.Caliber.Base + local Mass = Class.Mass * Scale + local FireRate = Class.Cyclic + local Total = Class.MagSize + local Charge = Class.ChargeRate + + return Info:format(Mass, FireRate, Total, Charge) + end) + + ClassStats:TrackClientData("Weapon", "SetText") + ClassStats:TrackClientData("Caliber") + ClassStats:DefineSetter(function() + if not BulletData then return "" end + + local MaxPen = math.Round(BulletData.MaxPen, 2) + local MuzzleVel = math.Round(BulletData.MuzzleVel, 2) + local Length = BulletData.ProjLength + local Mass = ACF.GetProperMass(BulletData.ProjMass) + + return Stats:format(MaxPen, MuzzleVel, Length, Mass) + end) + + ACF.LoadSortedList(ClassList, Piledrivers, "Name") + end + + ACF.AddMenuItem(1, "Fun Stuff", "Piledrivers", "pencil", CreateMenu) +end + +hook.Add("ACF_AllowMenuOption", "Allow Fun Menu", function(_, Name) + if Name ~= "Fun Stuff" then return end + if not ACF.GetServerBool("ShowFunMenu") then return false end +end) diff --git a/lua/acf/client/spawn_menu.lua b/lua/acf/client/spawn_menu.lua index e3fa010c8..97ce759af 100644 --- a/lua/acf/client/spawn_menu.lua +++ b/lua/acf/client/spawn_menu.lua @@ -79,6 +79,7 @@ do -- Menu population functions ACF.AddMenuOption(101, "Settings", "wrench") ACF.AddMenuOption(201, "Entities", "brick") + ACF.AddMenuOption(9999, "Fun Stuff", "bricks") end do -- ACF Menu context panel From 6e6f23d8f87191150bde299eaedb5e45b69f726e Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sat, 9 Jan 2021 04:33:29 -0300 Subject: [PATCH 252/279] Added Piledriver entities - As requested by Jesus and a decent part of the community, piledrivers has been readded to ACF. They're not the first piece of scalable weaponry on ACF. --- lua/entities/acf_piledriver/cl_init.lua | 4 + lua/entities/acf_piledriver/init.lua | 438 ++++++++++++++++++++++++ lua/entities/acf_piledriver/shared.lua | 14 + 3 files changed, 456 insertions(+) create mode 100644 lua/entities/acf_piledriver/cl_init.lua create mode 100644 lua/entities/acf_piledriver/init.lua create mode 100644 lua/entities/acf_piledriver/shared.lua diff --git a/lua/entities/acf_piledriver/cl_init.lua b/lua/entities/acf_piledriver/cl_init.lua new file mode 100644 index 000000000..d445a2dce --- /dev/null +++ b/lua/entities/acf_piledriver/cl_init.lua @@ -0,0 +1,4 @@ +include("shared.lua") + +language.Add("Cleanup_acf_piledriver", "ACF Piledrivers") +language.Add("Cleaned_acf_piledriver", "Cleaned up all ACF Piledrivers") diff --git a/lua/entities/acf_piledriver/init.lua b/lua/entities/acf_piledriver/init.lua new file mode 100644 index 000000000..67b5d888e --- /dev/null +++ b/lua/entities/acf_piledriver/init.lua @@ -0,0 +1,438 @@ +AddCSLuaFile("cl_init.lua") +AddCSLuaFile("shared.lua") + +include("shared.lua") + +local ACF = ACF +local hook = hook + +do -- Spawning and Updating -------------------- + local Piledrivers = ACF.Classes.Piledrivers + local AmmoTypes = ACF.Classes.AmmoTypes + local CheckLegal = ACF_CheckLegal + + local function VerifyData(Data) + if isstring(Data.Id) then + local OldClass = ACF.GetClassGroup(Piledrivers, Data.Id) + + if OldClass then + Data.Weapon = OldClass.ID + Data.Caliber = OldClass.Lookup[Data.Id].Caliber + end + end + + if not (isstring(Data.Weapon) and Piledrivers[Data.Weapon]) then + Data.Weapon = "PD" + end + + if not isstring(Data.Destiny) then + Data.Destiny = ACF.FindWeaponrySource(Data.Weapon) or "Piledrivers" + end + + local Class = Piledrivers[Data.Weapon] + local Bounds = Class.Caliber + + if not isnumber(Data.Caliber) then + Data.Caliber = Bounds.Base + else + Data.Caliber = math.Clamp(math.Round(Data.Caliber, 2), Bounds.Min, Bounds.Max) + end + + do -- External verifications + if Class.VerifyData then + Class.VerifyData(Data, Class) + end + + hook.Run("ACF_VerifyData", "acf_piledriver", Data, Class) + end + end + + local function CreateInputs(Entity, Data, Class) + local List = { "Fire" } + + if Class.SetupInputs then + Class.SetupInputs(List, Entity, Data, Class) + end + + hook.Run("ACF_OnSetupInputs", "acf_piledriver", List, Entity, Data, Class) + + if Entity.Inputs then + Entity.Inputs = WireLib.AdjustInputs(Entity, List) + else + Entity.Inputs = WireLib.CreateInputs(Entity, List) + end + end + + local function CreateOutputs(Entity, Data, Class) + local List = { "Ready", "Status [STRING]", "Shots Left", "Reload Time", "Rate of Fire", "Spike Mass", "Muzzle Velocity", "Entity [ENTITY]" } + + if Class.SetupOutputs then + Class.SetupOutputs(List, Entity, Data, Class) + end + + hook.Run("ACF_OnSetupOutputs", "acf_piledriver", List, Entity, Data, Class) + + if Entity.Outputs then + Entity.Outputs = WireLib.AdjustOutputs(Entity, List) + else + Entity.Outputs = WireLib.CreateOutputs(Entity, List) + end + end + + local function UpdatePiledriver(Entity, Data, Class) + local Caliber = Data.Caliber + local Scale = Caliber / Class.Caliber.Base + local Mass = math.floor(Class.Mass * Scale) + + Entity:SetModel(Class.Model) + Entity:SetScale(Scale) + + Entity.Name = Caliber .. "mm " .. Class.Name + Entity.ShortName = Caliber .. "mm" .. Class.ID + Entity.EntType = Class.Name + Entity.ClassData = Class + Entity.Caliber = Caliber + Entity.Cyclic = 60 / Class.Cyclic + Entity.MagSize = Class.MagSize or 1 + Entity.ChargeRate = Class.ChargeRate or 0.1 + Entity.SpikeLength = Class.Round.MaxLength * Scale + Entity.Muzzle = Entity:WorldToLocal(Entity:GetAttachment(Entity:LookupAttachment("muzzle")).Pos) + + CreateInputs(Entity, Data, Class) + CreateOutputs(Entity, Data, Class) + + WireLib.TriggerOutput(Entity, "Reload Time", Entity.Cyclic) + WireLib.TriggerOutput(Entity, "Rate of Fire", 60 / Entity.Cyclic) + + do -- Updating bulletdata + local Ammo = Entity.RoundData + + Data.AmmoType = "AP" + Data.Projectile = Entity.SpikeLength + + Ammo.SpikeLength = Entity.SpikeLength + + local BulletData = Ammo:ServerConvert(Data) + BulletData.Crate = Entity:EntIndex() + BulletData.Filter = { Entity } + BulletData.Gun = Entity + BulletData.Hide = true + + -- Bullet dies on the next tick + function BulletData:PreCalcFlight() + if self.KillTime then return end + if not self.DeltaTime then return end + + self.KillTime = ACF.CurTime + end + + Entity.BulletData = BulletData + + if Ammo.OnFirst then + Ammo:OnFirst(Entity) + end + + hook.Run("ACF_OnAmmoFirst", Ammo, Entity, Data, Class) + + Ammo:Network(Entity, Entity.BulletData) + + WireLib.TriggerOutput(Entity, "Spike Mass", math.Round(BulletData.ProjMass * 1000, 2)) + WireLib.TriggerOutput(Entity, "Muzzle Velocity", math.Round(BulletData.MuzzleVel * ACF.Scale, 2)) + end + + -- Storing all the relevant information on the entity for duping + for _, V in ipairs(Entity.DataStore) do + Entity[V] = Data[V] + end + + -- Set NWvars + Entity:SetNWString("WireName", "ACF " .. Entity.Name) + + ACF.Activate(Entity, true) + + Entity.ACF.LegalMass = Mass + Entity.ACF.Model = Class.Model + + local Phys = Entity:GetPhysicsObject() + + if IsValid(Phys) then + Phys:SetMass(Mass) + end + end + + ------------------------------------------------------------------------------- + + function MakeACF_Piledriver(Player, Pos, Angle, Data) + VerifyData(Data) + + local Class = Piledrivers[Data.Weapon] + local Entity = ents.Create("acf_piledriver") + + if not IsValid(Entity) then return end + + Entity:SetModel(Class.Model) -- NOTE: ENT:SetScale didn't work properly without this + Entity:SetPlayer(Player) + Entity:SetAngles(Angle) + Entity:SetPos(Pos) + Entity:Spawn() + + Entity.Owner = Player -- MUST be stored on ent for PP + Entity.RoundData = AmmoTypes.AP() + Entity.LastThink = ACF.CurTime + Entity.State = "Loading" + Entity.Firing = false + Entity.Charge = 0 + Entity.SingleCharge = 0 + Entity.CurrentShot = 0 + Entity.DataStore = ACF.GetEntityArguments("acf_piledriver") + + UpdatePiledriver(Entity, Data, Class) + + WireLib.TriggerOutput(Entity, "State", "Loading") + WireLib.TriggerOutput(Entity, "Entity", Entity) + + Entity:UpdateOverlay(true) + + CheckLegal(Entity) + + return Entity + end + + ACF.RegisterEntityClass("acf_piledriver", MakeACF_Piledriver, "Weapon", "Caliber") + + ------------------- Updating --------------------- + + function ENT:Update(Data) + VerifyData(Data) + + local Class = Piledrivers[Data.Weapon] + local OldClass = self.ClassData + + if OldClass.OnLast then + OldClass.OnLast(self, OldClass) + end + + hook.Run("ACF_OnEntityLast", "acf_piledriver", self, OldClass) + + ACF.SaveEntity(self) + + UpdatePiledriver(self, Data, Class) + + ACF.RestoreEntity(self) + + if Class.OnUpdate then + Class.OnUpdate(self, Data, Class) + end + + hook.Run("ACF_OnEntityUpdate", "acf_piledriver", self, Data, Class) + + self:UpdateOverlay(true) + + net.Start("ACF_UpdateEntity") + net.WriteEntity(self) + net.Broadcast() + + return true, "Piledriver updated successfully!" + end +end -------------------------------------------- + +do -- Entity Activation ------------------------ + function ENT:ACF_Activate(Recalc) + local PhysObj = self.ACF.PhysObj + + if not self.ACF.Area then + self.ACF.Area = PhysObj:GetSurfaceArea() + end + + local Armour = self.Caliber + local Health = PhysObj:GetVolume() * 2 / ACF.Threshold + local Percent = 1 + + if Recalc and self.ACF.Health and self.ACF.MaxHealth then + Percent = self.ACF.Health / self.ACF.MaxHealth + end + + self.ACF.Health = Health * Percent + self.ACF.MaxHealth = Health + self.ACF.Armour = Armour * (0.5 + Percent * 0.5) + self.ACF.MaxArmour = Armour + self.ACF.Type = "Prop" + end +end -------------------------------------------- + +do -- Entity Inputs ---------------------------- + ACF.AddInputAction("acf_piledriver", "Fire", function(Entity, Value) + Entity.Firing = tobool(Value) + + Entity:Shoot() + end) +end --------------------------------------------- + +do -- Entity Overlay ---------------------------- + local Text = "%s\n\nCharges Left:\n%s / %s\n[%s]\n\nRecharge State:\n%s%%\n[%s]\n\nRecharge Rate: %s charges/s\nRate of Fire: %s rpm\n\nMax Penetration: %s mm\nSpike Velocity: %s m/s\nSpike Length: %s cm\nSpike Mass: %s" + local Empty = "â–¯" + local Full = "â–®" + + local function GetChargeBar(Percentage) + local Bar = "" + + for I = 0.05, 0.95, 0.1 do + Bar = Bar .. (I <= Percentage and Full or Empty) + end + + return Bar + end + + ------------------------------------------------------------------------------- + + ENT.OverlayDelay = 0.1 + + function ENT:UpdateOverlayText() + local Shots = GetChargeBar(self.Charge / self.MagSize) + local State = GetChargeBar(self.SingleCharge) + local Current = self.CurrentShot + local Total = self.MagSize + local Percent = math.floor(self.SingleCharge * 100) + local Rate = self.ChargeRate + local RoF = self.Cyclic * 60 + local Bullet = self.BulletData + local Display = self.RoundData:GetDisplayData(Bullet) + local MaxPen = math.Round(Display.MaxPen, 2) + local Mass = ACF.GetProperMass(Bullet.ProjMass) + local MuzVel = math.Round(Bullet.MuzzleVel, 2) + local Length = Bullet.ProjLength + + return Text:format(self.State, Current, Total, Shots, Percent, State, Rate, RoF, MaxPen, MuzVel, Length, Mass) + end +end --------------------------------------------- + +do -- Firing ------------------------------------ + local Impact = "physics/metal/metal_barrel_impact_hard%s.wav" + + -- The entity won't even attempt to shoot if this function returns false + function ENT:AllowShoot() + if self.Disabled then return false end + if self.RetryShoot then return false end + + return self.Firing + end + + -- The entity should produce a "click" sound if this function returns false + function ENT:CanShoot() + if not ACF.GetServerBool("GunfireEnabled") then return false end + if not ACF.GetServerBool("AllowFunEnts") then return false end + if hook.Run("ACF_FireShell", self) == false then return false end + + return self.CurrentShot > 0 + end + + function ENT:Shoot() + if not self:AllowShoot() then return end + + local Delay = self.Cyclic + + if self:CanShoot() then + local Sound = self.SoundPath or Impact:format(math.random(5, 6)) + local Bullet = self.BulletData + + self:EmitSound(Sound, 500, math.Rand(98, 102)) + self:SetSequence("load") + + Bullet.Owner = self:GetUser(self.Inputs.Fire.Src) -- Must be updated on every shot + Bullet.Pos = self:LocalToWorld(self.Muzzle) + Bullet.Flight = self:GetForward() * Bullet.MuzzleVel * 39.37 + + self.RoundData:Create(self, Bullet) + + self:Consume() + self:SetState("Loading") + + self.Loading = true + + timer.Simple(0.35, function() + if not IsValid(self) then return end + + self:SetSequence("idle") + end) + else + self:EmitSound("weapons/pistol/pistol_empty.wav", 500, math.Rand(98, 102)) + + Delay = 1 + end + + if not self.RetryShoot then + self.RetryShoot = true + + timer.Simple(Delay, function() + if not IsValid(self) then return end + + self.RetryShoot = nil + + if self.Loading then + self.Loading = nil + + if self.CurrentShot > 0 then + self:SetState("Loaded") + end + end + + self:Shoot() + end) + end + end +end --------------------------------------------- + +do -- Misc -------------------------------------- + function ENT:SetState(State) + self.State = State + + self:UpdateOverlay() + + WireLib.TriggerOutput(self, "Status", State) + WireLib.TriggerOutput(self, "Ready", State == "Loaded" and 1 or 0) + end + + function ENT:Consume(Num) + self.Charge = math.Clamp(self.Charge - (Num or 1), 0, self.MagSize) + self.CurrentShot = math.floor(self.Charge) + + WireLib.TriggerOutput(self, "Shots Left", self.CurrentShot) + + self:UpdateOverlay() + end + + function ENT:Think() + local Time = ACF.CurTime + + if not self.Disabled and self.CurrentShot < self.MagSize then + local Delta = Time - self.LastThink + local Amount = self.ChargeRate * Delta + + self:Consume(-Amount) -- Slowly recharging the piledriver + + self.SingleCharge = self.Charge - self.CurrentShot + + if not self.Loading and self.State == "Loading" and self.CurrentShot > 0 then + self:SetState("Loaded") + end + end + + self:NextThink(Time) + + self.LastThink = Time + + return true + end + + function ENT:OnRemove() + local Class = self.ClassData + + if Class.OnLast then + Class.OnLast(self, Class) + end + + hook.Run("ACF_OnEntityLast", "acf_piledriver", self, Class) + + WireLib.Remove(self) + end +end --------------------------------------------- diff --git a/lua/entities/acf_piledriver/shared.lua b/lua/entities/acf_piledriver/shared.lua new file mode 100644 index 000000000..659198715 --- /dev/null +++ b/lua/entities/acf_piledriver/shared.lua @@ -0,0 +1,14 @@ +DEFINE_BASECLASS("acf_base_scalable") + +ENT.PrintName = "ACF Piledriver" +ENT.WireDebugName = "ACF Piledriver" +ENT.PluralName = "ACF Piledrivers" +ENT.IsPiledriver = true + +cleanup.Register("acf_piledriver") + +hook.Add("ACF_UpdateRoundData", "ACF Piledriver Ammo", function(Ammo, _, Data) + if not Ammo.SpikeLength then return end + + Data.MuzzleVel = Ammo.SpikeLength * 0.0254 / engine.TickInterval() +end) From 27302d25ed21241ff2a775c0db9e2726a9bba5f3 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sat, 9 Jan 2021 04:56:52 -0300 Subject: [PATCH 253/279] Added missing behavior to piledrivers - Piledriver charges will be emptied if it gets disabled. --- lua/entities/acf_piledriver/init.lua | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lua/entities/acf_piledriver/init.lua b/lua/entities/acf_piledriver/init.lua index 67b5d888e..9f8dda0f1 100644 --- a/lua/entities/acf_piledriver/init.lua +++ b/lua/entities/acf_piledriver/init.lua @@ -383,6 +383,14 @@ do -- Firing ------------------------------------ end --------------------------------------------- do -- Misc -------------------------------------- + function ENT:Disable() + self.Charge = 0 + self.SingleCharge = 0 + self.CurrentShot = 0 + + self:SetState("Loading") + end + function ENT:SetState(State) self.State = State From 0da16a68df22f4a5574e48600263cdebe2331d63 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sun, 10 Jan 2021 05:54:11 -0300 Subject: [PATCH 254/279] Fixed edge case on worldpen functions - Fixed an edge case on worldpen and world entity pen functions when the hit texture has no valid surface properties. --- lua/acf/server/ballistics.lua | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lua/acf/server/ballistics.lua b/lua/acf/server/ballistics.lua index 740f1e69b..811c67064 100644 --- a/lua/acf/server/ballistics.lua +++ b/lua/acf/server/ballistics.lua @@ -494,7 +494,8 @@ do -- Terminal ballistics -------------------------- function ACF_PenetrateMapEntity(Bullet, Trace) local Energy = ACF_Kinetic(Bullet.Flight:Length() / ACF.Scale, Bullet.ProjMass, Bullet.LimitVel) - local Density = (util.GetSurfaceData(Trace.SurfaceProps).density * 0.5 * math.Rand(0.9, 1.1)) ^ 0.9 / 10000 + local Surface = util.GetSurfaceData(Trace.SurfaceProps) + local Density = ((Surface and Surface.density * 0.5 or 500) * math.Rand(0.9, 1.1)) ^ 0.9 / 10000 local Pen = Energy.Penetration / Bullet.PenArea * ACF.KEtoRHA -- Base RHA penetration of the projectile local RHAe = math.max(Pen / Density, 1) -- RHA equivalent thickness of the target material @@ -536,7 +537,8 @@ do -- Terminal ballistics -------------------------- function ACF_PenetrateGround(Bullet, Trace) local Energy = ACF_Kinetic(Bullet.Flight:Length() / ACF.Scale, Bullet.ProjMass, Bullet.LimitVel) - local Density = (util.GetSurfaceData(Trace.SurfaceProps).density * 0.5 * math.Rand(0.9, 1.1)) ^ 0.9 / 10000 + local Surface = util.GetSurfaceData(Trace.SurfaceProps) + local Density = ((Surface and Surface.density * 0.5 or 500) * math.Rand(0.9, 1.1)) ^ 0.9 / 10000 local Pen = Energy.Penetration / Bullet.PenArea * ACF.KEtoRHA -- Base RHA penetration of the projectile local RHAe = math.max(Pen / Density, 1) -- RHA equivalent thickness of the target material From a0d21ebe77308a4dfe63c201f20ab87e197b68f0 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Tue, 12 Jan 2021 05:32:44 -0300 Subject: [PATCH 255/279] Piledrivers will now push entities on impact - Replaced the ammo used by piledrivers to hollow point, making it so they can push whatever entity they hit. - Fixed piledriver ammo not considering that bullet length is also on centimeters, thus having a way smaller projectile than what they should have. --- lua/acf/client/menu_items/fun_menu.lua | 4 ++-- lua/acf/shared/fun_stuff/piledriver.lua | 2 +- lua/entities/acf_piledriver/init.lua | 4 ++-- lua/entities/acf_piledriver/shared.lua | 14 ++++++++++++-- 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/lua/acf/client/menu_items/fun_menu.lua b/lua/acf/client/menu_items/fun_menu.lua index 08fab5209..ccdb4d597 100644 --- a/lua/acf/client/menu_items/fun_menu.lua +++ b/lua/acf/client/menu_items/fun_menu.lua @@ -25,7 +25,7 @@ do -- Piledrivers menu ACF.SetClientData("PrimaryClass", "acf_piledriver") ACF.SetClientData("SecondaryClass", "N/A") ACF.SetClientData("Destiny", "Piledrivers") - ACF.SetClientData("AmmoType", "AP") + ACF.SetClientData("AmmoType", "HP") ACF.SetClientData("Propellant", 0) ACF.SetClientData("Tracer", false) @@ -42,7 +42,7 @@ do -- Piledrivers menu local Min, Max = Bounds.Min, Bounds.Max local Current = math.Clamp(ACF.GetClientNumber("Caliber", Min), Min, Max) - Ammo = AmmoTypes.AP() + Ammo = AmmoTypes.HP() Caliber:SetMinMax(Min, Max) diff --git a/lua/acf/shared/fun_stuff/piledriver.lua b/lua/acf/shared/fun_stuff/piledriver.lua index b1224b635..eddba0bb5 100644 --- a/lua/acf/shared/fun_stuff/piledriver.lua +++ b/lua/acf/shared/fun_stuff/piledriver.lua @@ -13,7 +13,7 @@ ACF.RegisterPiledriverClass("PD", { Max = 300, }, Round = { - MaxLength = 45, -- Relative to the Base caliber + MaxLength = 114.3, -- Relative to the Base caliber, in cm PropMass = 0, }, Preview = { diff --git a/lua/entities/acf_piledriver/init.lua b/lua/entities/acf_piledriver/init.lua index 9f8dda0f1..4e1b3db8b 100644 --- a/lua/entities/acf_piledriver/init.lua +++ b/lua/entities/acf_piledriver/init.lua @@ -107,7 +107,7 @@ do -- Spawning and Updating -------------------- do -- Updating bulletdata local Ammo = Entity.RoundData - Data.AmmoType = "AP" + Data.AmmoType = "HP" Data.Projectile = Entity.SpikeLength Ammo.SpikeLength = Entity.SpikeLength @@ -177,7 +177,7 @@ do -- Spawning and Updating -------------------- Entity:Spawn() Entity.Owner = Player -- MUST be stored on ent for PP - Entity.RoundData = AmmoTypes.AP() + Entity.RoundData = AmmoTypes.HP() Entity.LastThink = ACF.CurTime Entity.State = "Loading" Entity.Firing = false diff --git a/lua/entities/acf_piledriver/shared.lua b/lua/entities/acf_piledriver/shared.lua index 659198715..23e0dc1f0 100644 --- a/lua/entities/acf_piledriver/shared.lua +++ b/lua/entities/acf_piledriver/shared.lua @@ -7,8 +7,18 @@ ENT.IsPiledriver = true cleanup.Register("acf_piledriver") -hook.Add("ACF_UpdateRoundData", "ACF Piledriver Ammo", function(Ammo, _, Data) +hook.Add("ACF_UpdateRoundData", "ACF Piledriver Ammo", function(Ammo, _, Data, GUIData) if not Ammo.SpikeLength then return end - Data.MuzzleVel = Ammo.SpikeLength * 0.0254 / engine.TickInterval() + local HollowCavity = GUIData.MaxCavVol * math.min(0.1 + Data.Caliber * 0.01, 1) + local ExpRatio = HollowCavity / GUIData.ProjVolume + + Data.MuzzleVel = Ammo.SpikeLength * 0.01 / engine.TickInterval() + Data.CavVol = HollowCavity + Data.ProjMass = (Data.FrArea * Data.ProjLength - HollowCavity) * 0.0079 + Data.ShovePower = 0.2 + ExpRatio * 0.5 + Data.ExpCaliber = Data.Caliber + ExpRatio * Data.ProjLength + Data.PenArea = (3.1416 * Data.ExpCaliber * 0.5) ^ 2 ^ ACF.PenAreaMod + Data.DragCoef = Data.FrArea * 0.0001 / Data.ProjMass + Data.CartMass = Data.PropMass + Data.ProjMass end) From 7009271bd7d50aa1127b355cf27ae6c474bc6477 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Tue, 12 Jan 2021 05:57:40 -0300 Subject: [PATCH 256/279] Fixed piledriver projectile deletion - Fixed piledriver projectiles being instantly removed due to the excellent way the ACF bullet iterator works. --- lua/entities/acf_piledriver/init.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/lua/entities/acf_piledriver/init.lua b/lua/entities/acf_piledriver/init.lua index 4e1b3db8b..b8ca58079 100644 --- a/lua/entities/acf_piledriver/init.lua +++ b/lua/entities/acf_piledriver/init.lua @@ -122,6 +122,7 @@ do -- Spawning and Updating -------------------- function BulletData:PreCalcFlight() if self.KillTime then return end if not self.DeltaTime then return end + if self.LastThink == ACF.CurTime then return end self.KillTime = ACF.CurTime end From cead290e1cd46aff88240030acbba3eac482328b Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Tue, 12 Jan 2021 05:58:32 -0300 Subject: [PATCH 257/279] Added piledriver recoil on world impact - Hitting the world with a piledriver will now apply recoil to the entity. --- lua/entities/acf_piledriver/init.lua | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/lua/entities/acf_piledriver/init.lua b/lua/entities/acf_piledriver/init.lua index b8ca58079..13eaab09d 100644 --- a/lua/entities/acf_piledriver/init.lua +++ b/lua/entities/acf_piledriver/init.lua @@ -10,6 +10,7 @@ do -- Spawning and Updating -------------------- local Piledrivers = ACF.Classes.Piledrivers local AmmoTypes = ACF.Classes.AmmoTypes local CheckLegal = ACF_CheckLegal + local ACF_RECOIL = GetConVar("acf_recoilpush") local function VerifyData(Data) if isstring(Data.Id) then @@ -127,6 +128,19 @@ do -- Spawning and Updating -------------------- self.KillTime = ACF.CurTime end + function BulletData:OnEndFlight(Trace) + if not ACF_RECOIL:GetBool() then return end + if not IsValid(Entity) then return end + if not Trace.HitWorld then return end + if Trace.Fraction == 0 then return end + + local Fraction = 1 - Trace.Fraction + local MassCenter = Entity:LocalToWorld(Entity:GetPhysicsObject():GetMassCenter()) + local Energy = self.ProjMass * self.MuzzleVel * 39.37 * Fraction + + ACF.KEShove(Entity, MassCenter, -Entity:GetForward(), Energy) + end + Entity.BulletData = BulletData if Ammo.OnFirst then From 8468882538a0a6cbad11422bdf69ee0726e7ded4 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Wed, 13 Jan 2021 04:31:05 -0300 Subject: [PATCH 258/279] Fixed spread value on weapons menu - Fixed spread value on weapons menu being multiplied by 100. --- lua/acf/client/menu_items/weapons_menu.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/acf/client/menu_items/weapons_menu.lua b/lua/acf/client/menu_items/weapons_menu.lua index 65f318739..58231ef60 100644 --- a/lua/acf/client/menu_items/weapons_menu.lua +++ b/lua/acf/client/menu_items/weapons_menu.lua @@ -75,7 +75,7 @@ local function CreateMenu(Menu) local Firerate = Data.Cyclic or 60 / ReloadTime local Magazine = Data.MagSize and MagText:format(Data.MagSize, Data.MagReload) or "" - return EntText:format(Data.Mass, math.Round(Firerate, 2), Class.Spread * 100, Magazine) + return EntText:format(Data.Mass, math.Round(Firerate, 2), Class.Spread, Magazine) end) ACF.LoadSortedList(ClassList, Weapons, "Name") From 61f69eeee3302c03297f306cd9d664f969b6657a Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Wed, 13 Jan 2021 04:33:23 -0300 Subject: [PATCH 259/279] Improved datavar refresh on panel functions - Improved Server and Client data variable refreshing on panel functions, these will be forced a tick after whenever a setter panel is defined. - Moved datavar panel functions to their own file. - Removed the best patch 2021. --- lua/acf/base/data_vars/cl_data_vars.lua | 231 ------------------ lua/acf/base/data_vars/cl_panel_functions.lua | 231 ++++++++++++++++++ lua/acf/client/ammo_menu.lua | 3 - 3 files changed, 231 insertions(+), 234 deletions(-) create mode 100644 lua/acf/base/data_vars/cl_panel_functions.lua diff --git a/lua/acf/base/data_vars/cl_data_vars.lua b/lua/acf/base/data_vars/cl_data_vars.lua index 4d5640146..8c716c94b 100644 --- a/lua/acf/base/data_vars/cl_data_vars.lua +++ b/lua/acf/base/data_vars/cl_data_vars.lua @@ -164,234 +164,3 @@ do -- Server data setter function end end end - -do -- Panel functions - ACF.DataPanels = ACF.DataPanels or { - Server = {}, - Client = {}, - Panels = {}, - } - - local PanelMeta = FindMetaTable("Panel") - local DataPanels = ACF.DataPanels - - local function GetSubtable(Table, Key) - local Result = Table[Key] - - if not Result then - Result = {} - Table[Key] = Result - end - - return Result - end - - local function StoreData(Destiny, Key, Type, Value, Store) - local BaseData = GetSubtable(DataPanels[Destiny], Key) - local TypeData = GetSubtable(BaseData, Type) - - TypeData[Value] = Store or true - end - - local function ClearFromType(Data, Type, Panel) - local Saved = Data[Type] - - if not Saved then return end - - for Name, Mode in pairs(Saved) do - DataPanels[Type][Name][Mode][Panel] = nil -- Weed lmao - end - end - - local function ClearData(Panel) - local Panels = DataPanels.Panels - local Data = Panels[Panel] - - -- Apparently this can be called twice - if Data then - ClearFromType(Data, "Server", Panel) - ClearFromType(Data, "Client", Panel) - end - - Panels[Panel] = nil - end - - local function HijackThink(Panel) - local OldThink = Panel.Think - local Player = LocalPlayer() - - Panel.Enabled = Panel:IsEnabled() - - function Panel:Think(...) - if self.ServerVar then - local Enabled = ACF.CanSetServerData(Player) - - if self.Enabled ~= Enabled then - self.Enabled = Enabled - - self:SetEnabled(Enabled) - end - end - - if OldThink then - return OldThink(self, ...) - end - end - end - - local function HijackRemove(Panel) - local OldRemove = Panel.Remove - - function Panel:Remove(...) - ClearData(self) - - return OldRemove(self, ...) - end - end - - local function HijackFunctions(Panel, SetFunction) - if Panel.Hijacked then return end - - local Setter = Panel[SetFunction] and SetFunction or "SetValue" - - Panel.OldSet = Panel[Setter] - Panel.Hijacked = true - - Panel[Setter] = function(This, Value, Forced) - local ServerVar = This.ServerVar - local ClientVar = This.ClientVar - - if not (ServerVar or ClientVar) then - if This.SetCustomValue then - Value = This:SetCustomValue(nil, nil, Value) or Value - end - - return This:OldSet(Value) - end - - if ServerVar then - ACF.SetServerData(ServerVar, Value, Forced) - end - - if ClientVar then - ACF.SetClientData(ClientVar, Value, Forced) - end - end - - Panel.Setter = Panel[Setter] - - -- We'll give a basic GetCustomValue function by default - -- I'll only work with setter panels though - if not Panel.GetCustomValue then - function Panel:GetCustomValue(Value) - if self.ClientVar then - return ACF.GetClientData(self.ClientVar, Value) - end - - if self.ServerVar then - return ACF.GetServerData(self.ServerVar, Value) - end - - return Value - end - end - - HijackThink(Panel) - HijackRemove(Panel) - end - - local function UpdatePanels(Panels, Type, Key, Value, IsTracked) - if not Panels then return end - - for Panel in pairs(Panels) do - if not IsValid(Panel) then - ClearData(Panel) -- Somehow Panel:Remove is not being called - continue - end - - local Result = Value - - if Panel.SetCustomValue then - Result = Panel:SetCustomValue(Type, Key, Value, IsTracked) - end - - if Result ~= nil then - Panel:OldSet(Result) - end - end - end - - function PanelMeta:DefineSetter(Function) - if not isfunction(Function) then return end - - self.SetCustomValue = Function - - self:RefreshValue() - end - - function PanelMeta:DefineGetter(Function) - if not isfunction(Function) then return end - - self.GetCustomValue = Function - - self:RefreshValue() - end - - function PanelMeta:RefreshValue(Value) - if self.GetCustomValue then - Value = self:GetCustomValue(Value) - end - - if Value ~= nil then - self:Setter(Value, true) - end - end - - --- Generates the following functions: - -- Panel:SetClientData(Key, Setter) - -- Panel:TrackClientData(Key, Setter) - -- Panel:SetServerData(Key, Setter) - -- Panel:TrackServerData(Key, Setter) - - for Type in pairs(Queued) do - PanelMeta["Set" .. Type .. "Data"] = function(Panel, Key, Setter) - if not isstring(Key) then return end - - local Variables = ACF[Type .. "Data"] - local SetFunction = ACF["Set" .. Type .. "Data"] - - StoreData("Panels", Panel, Type, Key, "Setter") - StoreData(Type, Key, "Setter", Panel) - - HijackFunctions(Panel, Setter or "SetValue") - - Panel[Type .. "Var"] = Key - - if Variables[Key] == nil then - SetFunction(Key, Panel:GetValue()) - end - - Panel:RefreshValue() - end - - PanelMeta["Track" .. Type .. "Data"] = function(Panel, Key, Setter) - if not isstring(Key) then return end - - StoreData("Panels", Panel, Type, Key, "Tracker") - StoreData(Type, Key, "Tracker", Panel) - - HijackFunctions(Panel, Setter or "SetValue") - - Panel:RefreshValue() - end - - hook.Add("ACF_On" .. Type .. "DataUpdate", "ACF Update Panel Values", function(_, Key, Value) - local Data = DataPanels[Type][Key] - - if not Data then return end -- This variable is not being set or tracked by panels - - UpdatePanels(Data.Setter, Type, Key, Value, IsTracked) - UpdatePanels(Data.Tracker, Type, Key, Value, IsTracked) - end) - end -end diff --git a/lua/acf/base/data_vars/cl_panel_functions.lua b/lua/acf/base/data_vars/cl_panel_functions.lua new file mode 100644 index 000000000..fb72bf2f4 --- /dev/null +++ b/lua/acf/base/data_vars/cl_panel_functions.lua @@ -0,0 +1,231 @@ +local ACF = ACF +local PanelMeta = FindMetaTable("Panel") + +function PanelMeta:DefineSetter(Function) + if not isfunction(Function) then return end + + self.SetCustomValue = Function +end + +do -- Tracker and Setter panel functions + ACF.DataPanels = ACF.DataPanels or { + Server = {}, + Client = {}, + Panels = {}, + } + + --------------------------------------------------------------------------- + + local DataPanels = ACF.DataPanels + local Queued = { Client = {}, Server = {} } + local IsQueued + + local function RefreshValues() + for Realm, Data in pairs(Queued) do + local SetFunction = ACF["Set" .. Realm .. "Data"] + local Variables = ACF[Realm .. "Data"] + + for Key in pairs(Data) do + SetFunction(Key, Variables[Key], true) + + Data[Key] = nil + end + end + + IsQueued = nil + end + + local function QueueRefresh(Realm, Key) + local Data = Queued[Realm] + + if Data[Key] then return end + + Data[Key] = true + + if not IsQueued then + timer.Create("ACF Refresh Data Vars", 0, 1, RefreshValues) + + IsQueued = true + end + end + + --------------------------------------------------------------------------- + + local function GetSubtable(Table, Key) + local Result = Table[Key] + + if not Result then + Result = {} + Table[Key] = Result + end + + return Result + end + + local function StoreData(Destiny, Key, Realm, Value, Store) + local BaseData = GetSubtable(DataPanels[Destiny], Key) + local TypeData = GetSubtable(BaseData, Realm) + + TypeData[Value] = Store or true + end + + local function ClearFromType(Data, Realm, Panel) + local Saved = Data[Realm] + + if not Saved then return end + + for Name, Mode in pairs(Saved) do + DataPanels[Realm][Name][Mode][Panel] = nil -- Weed lmao + end + end + + local function ClearData(Panel) + local Panels = DataPanels.Panels + local Data = Panels[Panel] + + -- Apparently this can be called twice + if Data then + ClearFromType(Data, "Server", Panel) + ClearFromType(Data, "Client", Panel) + end + + Panels[Panel] = nil + end + + local function DefaultSetter(Panel, Value, Forced) + local ServerVar = Panel.ServerVar + local ClientVar = Panel.ClientVar + + if not (ServerVar or ClientVar) then + if Panel.SetCustomValue then + Value = Panel:SetCustomValue(nil, nil, Value) or Value + end + + return Panel:OldSet(Value) + end + + if ServerVar then + ACF.SetServerData(ServerVar, Value, Forced) + end + + if ClientVar then + ACF.SetClientData(ClientVar, Value, Forced) + end + end + + local function HijackThink(Panel) + local OldThink = Panel.Think + local Player = LocalPlayer() + + Panel.Enabled = Panel:IsEnabled() + + function Panel:Think(...) + if self.ServerVar then + local Enabled = ACF.CanSetServerData(Player) + + if self.Enabled ~= Enabled then + self.Enabled = Enabled + + self:SetEnabled(Enabled) + end + end + + if OldThink then + return OldThink(self, ...) + end + end + end + + local function HijackRemove(Panel) + local OldRemove = Panel.Remove + + function Panel:Remove(...) + ClearData(self) + + return OldRemove(self, ...) + end + end + + local function HijackFunctions(Panel, SetFunction) + if Panel.Hijacked then return end + + local Setter = Panel[SetFunction] and SetFunction or "SetValue" + + Panel.OldSet = Panel[Setter] + Panel[Setter] = DefaultSetter + Panel.Setter = DefaultSetter + Panel.Hijacked = true + + HijackThink(Panel) + HijackRemove(Panel) + end + + local function UpdatePanels(Panels, Realm, Key, Value, IsTracked) + if not Panels then return end + + for Panel in pairs(Panels) do + if not IsValid(Panel) then + ClearData(Panel) -- Somehow Panel:Remove is not being called + continue + end + + local Result = Value + + if Panel.SetCustomValue then + Result = Panel:SetCustomValue(Realm, Key, Value, IsTracked) + end + + if Result ~= nil then + Panel:OldSet(Result) + end + end + end + + --------------------------------------------------------------------------- + + --- Generates the following functions: + -- Panel:SetClientData(Key, Setter) + -- Panel:TrackClientData(Key, Setter) + -- Panel:SetServerData(Key, Setter) + -- Panel:TrackServerData(Key, Setter) + + for Realm in pairs(Queued) do + PanelMeta["Set" .. Realm .. "Data"] = function(Panel, Key, Setter) + if not isstring(Key) then return end + + local Variables = ACF[Realm .. "Data"] + local SetFunction = ACF["Set" .. Realm .. "Data"] + + StoreData("Panels", Panel, Realm, Key, "Setter") + StoreData(Realm, Key, "Setter", Panel) + + HijackFunctions(Panel, Setter or "SetValue") + + Panel[Realm .. "Var"] = Key + + if Variables[Key] == nil then + SetFunction(Key, Panel:GetValue()) + end + + QueueRefresh(Realm, Key) + end + + PanelMeta["Track" .. Realm .. "Data"] = function(Panel, Key, Setter) + if not isstring(Key) then return end + + StoreData("Panels", Panel, Realm, Key, "Tracker") + StoreData(Realm, Key, "Tracker", Panel) + + HijackFunctions(Panel, Setter or "SetValue") + end + + hook.Add("ACF_On" .. Realm .. "DataUpdate", "ACF Update Panel Values", function(_, Key, Value) + local Data = DataPanels[Realm][Key] + + if not Data then return end -- This variable is not being set or tracked by panels + + UpdatePanels(Data.Setter, Realm, Key, Value, IsTracked) + UpdatePanels(Data.Tracker, Realm, Key, Value, IsTracked) + end) + end +end diff --git a/lua/acf/client/ammo_menu.lua b/lua/acf/client/ammo_menu.lua index fe01f6114..11cdf15d8 100644 --- a/lua/acf/client/ammo_menu.lua +++ b/lua/acf/client/ammo_menu.lua @@ -214,9 +214,6 @@ function ACF.CreateAmmoMenu(Menu, Settings) Desc:SetText(Data.Description) ACF.UpdateAmmoMenu(Menu, Settings) - - -- Best patch 2021 - ACF.SetClientData("Projectile", ACF.GetClientNumber("Projectile"), true) end Menu.AmmoBase = Base From 9f2dc5b2f3aa36463ad9887fca4b3f94214c282e Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Fri, 15 Jan 2021 18:17:08 -0300 Subject: [PATCH 260/279] Fixed piledriver spawn limit and cleanup - Fixed piledrivers ignoring their entity limit. - Fixed piledrivers not being registered for cleanup. --- lua/acf/base/sh_classes.lua | 4 ++++ lua/entities/acf_piledriver/init.lua | 9 ++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/lua/acf/base/sh_classes.lua b/lua/acf/base/sh_classes.lua index 78365a670..a093e3f38 100644 --- a/lua/acf/base/sh_classes.lua +++ b/lua/acf/base/sh_classes.lua @@ -455,6 +455,10 @@ do -- Piledriver registration functions } end + if not Group.Cleanup then + Group.Cleanup = "acf_piledriver" + end + AddSboxLimit(Group.LimitConVar) return Group diff --git a/lua/entities/acf_piledriver/init.lua b/lua/entities/acf_piledriver/init.lua index 13eaab09d..1023aeb1a 100644 --- a/lua/entities/acf_piledriver/init.lua +++ b/lua/entities/acf_piledriver/init.lua @@ -180,11 +180,18 @@ do -- Spawning and Updating -------------------- function MakeACF_Piledriver(Player, Pos, Angle, Data) VerifyData(Data) - local Class = Piledrivers[Data.Weapon] + local Class = Piledrivers[Data.Weapon] + local Limit = Class.LimitConVar.Name + + if not Player:CheckLimit(Limit) then return end + local Entity = ents.Create("acf_piledriver") if not IsValid(Entity) then return end + Player:AddCleanup(Class.Cleanup, Entity) + Player:AddCount(Limit, Entity) + Entity:SetModel(Class.Model) -- NOTE: ENT:SetScale didn't work properly without this Entity:SetPlayer(Player) Entity:SetAngles(Angle) From d7da42d025249c4d4ab3c17bc6f82c2fb452f279 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Fri, 15 Jan 2021 22:35:03 -0300 Subject: [PATCH 261/279] Moved ACF_SendNotify to the ACF namespace - Moved ACF_SendNotify function to the ACF namespace. It was, therefore, renamed to ACF.SendNotify, although it's still available under the old name for backwards compatibility. --- lua/acf/base/acf_globals.lua | 22 ++++++++++--------- lua/acf/base/sv_validation.lua | 4 ++-- lua/entities/acf_ammo/init.lua | 2 +- .../core/custom/acffunctions.lua | 12 +++++----- lua/starfall/libs_sv/acffunctions.lua | 4 ++-- lua/weapons/gmod_tool/stools/acfsound.lua | 4 ++-- 6 files changed, 25 insertions(+), 23 deletions(-) diff --git a/lua/acf/base/acf_globals.lua b/lua/acf/base/acf_globals.lua index 323c0506a..b14638e4c 100644 --- a/lua/acf/base/acf_globals.lua +++ b/lua/acf/base/acf_globals.lua @@ -247,26 +247,28 @@ end do -- ACF Notify ----------------------------------- if SERVER then - function ACF_SendNotify(ply, success, msg) + function ACF.SendNotify(Player, Success, Message) net.Start("ACF_Notify") - net.WriteBit(success) - net.WriteString(msg or "") - net.Send(ply) + net.WriteBool(Success or true) + net.WriteString(Message or "") + net.Send(Player) end + + ACF_SendNotify = ACF.SendNotify -- Backwards compatibility else - local function ACF_Notify() + local notification = notification + + net.Receive("ACF_Notify", function() local Type = NOTIFY_ERROR - if tobool(net.ReadBit()) then + if net.ReadBool() then Type = NOTIFY_GENERIC else surface.PlaySound("buttons/button10.wav") end - GAMEMODE:AddNotify(net.ReadString(), Type, 7) - end - - net.Receive("ACF_Notify", ACF_Notify) + notification.AddLegacy(net.ReadString(), Type, 7) + end) end end ------------------------------------------------ diff --git a/lua/acf/base/sv_validation.lua b/lua/acf/base/sv_validation.lua index df9f6bbba..69e828755 100644 --- a/lua/acf/base/sv_validation.lua +++ b/lua/acf/base/sv_validation.lua @@ -76,10 +76,10 @@ local function CheckLegal(Entity) timer.Simple(1.1, function() -- Remover tool sets nodraw and removes 1 second later, causing annoying alerts if not IsValid(Entity) then return end - ACF_SendNotify(Owner, false, Name .. " has been disabled: " .. Description) + ACF.SendNotify(Owner, false, Name .. " has been disabled: " .. Description) end) else - ACF_SendNotify(Owner, false, Name .. " has been disabled: " .. Description) + ACF.SendNotify(Owner, false, Name .. " has been disabled: " .. Description) end end end diff --git a/lua/entities/acf_ammo/init.lua b/lua/entities/acf_ammo/init.lua index 875f0f6e5..3d15b3dcd 100644 --- a/lua/entities/acf_ammo/init.lua +++ b/lua/entities/acf_ammo/init.lua @@ -360,7 +360,7 @@ do -- Spawning and Updating -------------------- end if Unloaded then - ACF_SendNotify(Entity.Owner, false, "Crate updated while weapons were loaded with it's ammo. Weapons unloaded.") + ACF.SendNotify(Entity.Owner, false, "Crate updated while weapons were loaded with it's ammo. Weapons unloaded.") end end diff --git a/lua/entities/gmod_wire_expression2/core/custom/acffunctions.lua b/lua/entities/gmod_wire_expression2/core/custom/acffunctions.lua index ff55c90fc..748946d1e 100644 --- a/lua/entities/gmod_wire_expression2/core/custom/acffunctions.lua +++ b/lua/entities/gmod_wire_expression2/core/custom/acffunctions.lua @@ -312,7 +312,7 @@ e2function number entity:acfLinkTo(entity Target, number Notify) if not validPhysics(Target) then return 0 end if not (isOwner(self, this) and isOwner(self, Target)) then if Notify ~= 0 then - ACF_SendNotify(self.player, 0, "Must be called on entities you own.") + ACF.SendNotify(self.player, 0, "Must be called on entities you own.") end return 0 @@ -320,7 +320,7 @@ e2function number entity:acfLinkTo(entity Target, number Notify) if not this.Link then if Notify ~= 0 then - ACF_SendNotify(self.player, 0, "This entity is not linkable.") + ACF.SendNotify(self.player, 0, "This entity is not linkable.") end return 0 @@ -329,7 +329,7 @@ e2function number entity:acfLinkTo(entity Target, number Notify) local Sucess, Message = this:Link(Target) if Notify ~= 0 then - ACF_SendNotify(self.player, Sucess, Message) + ACF.SendNotify(self.player, Sucess, Message) end return Sucess and 1 or 0 @@ -341,7 +341,7 @@ e2function number entity:acfUnlinkFrom(entity Target, number Notify) if not validPhysics(Target) then return 0 end if not (isOwner(self, this) and isOwner(self, Target)) then if Notify ~= 0 then - ACF_SendNotify(self.player, 0, "Must be called on entities you own.") + ACF.SendNotify(self.player, 0, "Must be called on entities you own.") end return 0 @@ -349,7 +349,7 @@ e2function number entity:acfUnlinkFrom(entity Target, number Notify) if not this.Unlink then if Notify ~= 0 then - ACF_SendNotify(self.player, 0, "This entity is not linkable.") + ACF.SendNotify(self.player, 0, "This entity is not linkable.") end return 0 @@ -358,7 +358,7 @@ e2function number entity:acfUnlinkFrom(entity Target, number Notify) local Sucess, Message = this:Unlink(Target) if Notify > 0 then - ACF_SendNotify(self.player, Sucess, Message) + ACF.SendNotify(self.player, Sucess, Message) end return Sucess and 1 or 0 diff --git a/lua/starfall/libs_sv/acffunctions.lua b/lua/starfall/libs_sv/acffunctions.lua index 1bf9c6a3c..7a5c7d4f5 100644 --- a/lua/starfall/libs_sv/acffunctions.lua +++ b/lua/starfall/libs_sv/acffunctions.lua @@ -996,7 +996,7 @@ function ents_methods:acfLinkTo(target, notify) local Success, Message = This:Link(Target) if notify then - ACF_SendNotify(instance.player, Success, Message) + ACF.SendNotify(instance.player, Success, Message) end return Success, Message @@ -1023,7 +1023,7 @@ function ents_methods:acfUnlinkFrom(target, notify) local Success, Message = This:Unlink(Target) if notify then - ACF_SendNotify(instance.player, Success, Message) + ACF.SendNotify(instance.player, Success, Message) end return Success, Message diff --git a/lua/weapons/gmod_tool/stools/acfsound.lua b/lua/weapons/gmod_tool/stools/acfsound.lua index 59e7e8303..3dff2b141 100644 --- a/lua/weapons/gmod_tool/stools/acfsound.lua +++ b/lua/weapons/gmod_tool/stools/acfsound.lua @@ -91,9 +91,9 @@ local function IsReallyValid(trace, ply) if not ACF.SoundToolSupport[class] then if string.StartWith(class, "acf_") then - ACF_SendNotify(ply, false, class .. " is not supported by the sound tool!") + ACF.SendNotify(ply, false, class .. " is not supported by the sound tool!") else - ACF_SendNotify(ply, false, "Only ACF entities are supported by the ACF sound tool!") + ACF.SendNotify(ply, false, "Only ACF entities are supported by the ACF sound tool!") end return false From 0c6e82aaf15844c83fdd7a4a14c4f8297d92e258 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sat, 16 Jan 2021 02:22:16 -0300 Subject: [PATCH 262/279] Updated repository structure and update checker - Repositories will now store their information on folders for each realm. - Added several shared helper functions. - The commit for each branch will now store their author. - Moved ACF.StartRequest to the serverside utilities file. - Starting a request before the server is fully loaded will queue it for later. --- lua/acf/base/util/sv_util.lua | 88 +++++++++++++ lua/acf/base/version/cl_version.lua | 82 +++++++----- lua/acf/base/version/sh_version.lua | 192 +++++++++++++++++----------- lua/acf/base/version/sv_version.lua | 134 +++++++------------ 4 files changed, 296 insertions(+), 200 deletions(-) diff --git a/lua/acf/base/util/sv_util.lua b/lua/acf/base/util/sv_util.lua index 0b4e8fd5d..73d4db603 100644 --- a/lua/acf/base/util/sv_util.lua +++ b/lua/acf/base/util/sv_util.lua @@ -61,6 +61,94 @@ do -- Clientside message delivery end end +do -- HTTP Request + local NoRequest = true + local http = http + local Queue = {} + local Count = 0 + + local function SuccessfulRequest(Code, Body, OnSuccess, OnFailure) + local Data = Body and util.JSONToTable(Body) + local Error + + if not Body then + Error = "No data found on request." + elseif Code ~= 200 then + Error = "Request unsuccessful (Code " .. Code .. ")." + elseif not (Data and next(Data)) then + Error = "Empty request result." + end + + if Error then + ACF.PrintLog("HTTP_Error", Error) + + if OnFailure then + OnFailure(Error) + end + elseif OnSuccess then + OnSuccess(Body, Data) + end + end + + function ACF.StartRequest(Link, OnSuccess, OnFailure, Headers) + if not isstring(Link) then return end + if not isfunction(OnSuccess) then OnSuccess = nil end + if not isfunction(OnFailure) then OnFailure = nil end + if not istable(Headers) then Headers = nil end + + if NoRequest then + Count = Count + 1 + + Queue[Count] = { + Link = Link, + OnSuccess = OnSuccess, + OnFailure = OnFailure, + Headers = Headers, + } + + return + end + + http.Fetch( + Link, + function(Body, _, _, Code) + SuccessfulRequest(Code, Body, OnSuccess, OnFailure) + end, + function(Error) + ACF.PrintLog("HTTP_Error", Error) + + if OnFailure then + OnFailure(Error) + end + end, + Headers) + end + + hook.Add("Initialize", "ACF Allow Requests", function() + timer.Simple(0, function() + NoRequest = nil + + if Count > 0 then + for _, Request in ipairs(Queue) do + ACF.StartRequest( + Request.Link, + Request.OnSuccess, + Request.OnFailure, + Request.Headers + ) + end + end + + Count = nil + Queue = nil + end) + + hook.Remove("Initialize", "ACF Allow Requests") + end) + + ACF.AddLogType("HTTP_Error", "HTTP", Color(241, 80, 47)) +end + do -- Entity saving and restoring local Constraints = duplicator.ConstraintType local Saved = {} diff --git a/lua/acf/base/version/cl_version.lua b/lua/acf/base/version/cl_version.lua index 58b4d4fd1..9bcbcca48 100644 --- a/lua/acf/base/version/cl_version.lua +++ b/lua/acf/base/version/cl_version.lua @@ -1,11 +1,9 @@ -local Repos = ACF.Repositories +local ACF = ACF do -- Server syncronization and status printing - local PrintToChat = ACF.PrintToChat - - local Unique = { - Branches = true, - } + local Repos = ACF.Repositories + local Queue = {} + local Standby local Messages = { ["Unable to check"] = { @@ -22,50 +20,68 @@ do -- Server syncronization and status printing }, } - local function GenerateCopy(Name, Data) - local Version = ACF.GetVersion(Name) + local function StoreInfo(Name, Data, Destiny) + local NewData = Data[Destiny] - if not Version.Server then - Version.Server = {} - end + if not NewData then return end - for K, V in pairs(Data) do - if not Unique[K] then - Version.Server[K] = V - else - Version[K] = V - end - end + local Repo = ACF.GetRepository(Name) + local Source = Repo[Destiny] - ACF.GetVersionStatus(Name) + for K, V in pairs(NewData) do + Source[K] = V + end end local function PrintStatus(Server) - local Branch = ACF.GetBranch(Server.Name, Server.Head) - local Lapse = Branch and ACF.GetTimeLapse(Branch.Date) - - local Data = Messages[Server.Status or "Unable to check"] - local Message = Data.Message + local Branch = ACF.GetBranch(Server.Name, Server.Head) + local Lapse = Branch and ACF.GetTimeLapse(Branch.Date) + local Data = Messages[Server.Status or "Unable to check"] - PrintToChat(Data.Type, Message:format(Server.Name, Server.Code, Lapse)) + ACF.PrintToChat(Data.Type, Data.Message:format(Server.Name, Server.Code, Lapse)) end - net.Receive("ACF_VersionSync", function() - local Table = net.ReadTable() - - for Name, Data in pairs(Table) do - GenerateCopy(Name, Data) - end + local function PrepareStatus() + if Standby then return end hook.Add("CreateMove", "ACF Print Version", function(Move) if Move:GetButtons() ~= 0 then - for _, Data in pairs(Repos) do - PrintStatus(Data.Server) + for Name, Repo in pairs(Queue) do + PrintStatus(Repo.Server) + + Queue[Name] = nil end + Standby = nil + hook.Remove("CreateMove", "ACF Print Version") end end) + + Standby = true + end + + local function QueueStatusMessage(Name) + if Queue[Name] then return end + + Queue[Name] = ACF.GetRepository(Name) + + PrepareStatus() + end + + net.Receive("ACF_VersionSync", function() + local Values = util.JSONToTable(net.ReadString()) + + for Name, Repo in pairs(Values) do + StoreInfo(Name, Repo, "Branches") + StoreInfo(Name, Repo, "Server") + + ACF.CheckLocalStatus(Name) + + QueueStatusMessage(Name) + + hook.Run("ACF_UpdatedRepository", Name, Repos[Name]) + end end) ACF.AddMessageType("Update_Ok", "Updates") diff --git a/lua/acf/base/version/sh_version.lua b/lua/acf/base/version/sh_version.lua index 9bd3f163d..b57027668 100644 --- a/lua/acf/base/version/sh_version.lua +++ b/lua/acf/base/version/sh_version.lua @@ -1,30 +1,29 @@ +local ACF = ACF local Repos = ACF.Repositories +local Realm = SERVER and "Server" or "Client" -do -- Repository tracking - function ACF.AddRepository(Owner, Name, Path) - if not Owner then return end - if not Name then return end - if not Path then return end - if Repos[Name] then return end - Repos[Name] = { - Owner = Owner, - Name = Name, - Path = "addons/%s/" .. Path, - Code = false, - Date = false, - } - end - - ACF.AddRepository("Stooberton", "ACF-3", "lua/autorun/acf_loader.lua") -end +do -- Local repository version checking + local file = file + local os = os -do -- ACF.GetVersion function local function LocalToUTC(Time) return os.time(os.date("!*t", Time)) end - local function SetRealOwner(Path, Version) + local function GetPath(Data) + local _, Folders = file.Find("addons/*", "GAME") + local Pattern = Data.Pattern + + for _, Folder in ipairs(Folders) do + if file.Exists(Pattern:format(Folder), "GAME") then + return "addons/" .. Folder + end + end + end + + -- Makes sure the owner of the repo is correct, deals with forks + local function UpdateOwner(Path, Data) if not file.Exists(Path .. "/.git/FETCH_HEAD", "GAME") then return end local Fetch = file.Read(Path .. "/.git/FETCH_HEAD", "GAME") @@ -32,21 +31,19 @@ do -- ACF.GetVersion function if not Start then return end -- File is empty - Version.Owner = Fetch:sub(Start + 11, End - 1) + Data.Owner = Fetch:sub(Start + 11, End - 1) end - local function GetGitData(Path, Version) + local function GetGitData(Path, Data) local _, _, Head = file.Read(Path .. "/.git/HEAD", "GAME"):find("heads/(.+)$") local Heads = Path .. "/.git/refs/heads/" local Files = file.Find(Heads .. "*", "GAME") local Code, Date - SetRealOwner(Path, Version) - - Version.Head = Head:Trim() + Data.Head = Head:Trim() for _, Name in ipairs(Files) do - if Name == Version.Head then + if Name == Data.Head then local SHA = file.Read(Heads .. Name, "GAME"):Trim() Code = Name .. "-" .. SHA:sub(1, 7) @@ -59,83 +56,126 @@ do -- ACF.GetVersion function return Code, Date end - function ACF.GetVersion(Name) - local Version = Repos[Name] + ------------------------------------------------------------------- - if not Version then return end - if Version.Code then return Version end + function ACF.CheckLocalVersion(Name) + if not isstring(Name) then return end - local _, Folders = file.Find("addons/*", "GAME") - local Pattern = Version.Path - local Path, Code, Date + local Data = ACF.GetLocalRepo(Name) - for _, Folder in ipairs(Folders) do - if file.Exists(Pattern:format(Folder), "GAME") then - Path = "addons/" .. Folder - break - end - end + if not Data then return end + + local Path = GetPath(Data) if not Path then - Version.Code = "Not Installed" - Version.Date = 0 + Data.Code = "Not Installed" + Data.Date = 0 + Data.NoFiles = true elseif file.Exists(Path .. "/.git/HEAD", "GAME") then - Code, Date = GetGitData(Path, Version) + local Code, Date = GetGitData(Path, Data) - Version.Code = "Git-" .. Code - Version.Date = LocalToUTC(Date) + UpdateOwner(Path, Data) + + Data.Code = "Git-" .. Code + Data.Date = LocalToUTC(Date) elseif file.Exists(Path .. "/LICENSE", "GAME") then - Date = file.Time(Path .. "/LICENSE", "GAME") + local Date = file.Time(Path .. "/LICENSE", "GAME") - Version.Code = "ZIP-Unknown" - Version.Date = LocalToUTC(Date) + Data.Code = "ZIP-Unknown" + Data.Date = LocalToUTC(Date) end - if not Version.Head then - Version.Head = "master" + if not Data.Head then + Data.Head = "master" end - - return Version end end -function ACF.GetBranch(Name, Branch) - local Version = Repos[Name] +do -- Local repository status checking + local function IsUpdated(Data, Branch) + if not isnumber(Data.Date) then return false end - if not Version then return end - if not Version.Branches then return end + return Data.Date >= Branch.Date + end - Branch = Branch or Version.Head + function ACF.CheckLocalStatus(Name) + if not isstring(Name) then return end - -- Just in case both server and client are using different forks with different branches - return Version.Branches[Branch] or Version.Branches.master -end + local Repo = ACF.GetRepository(Name) + + if not Repo then return end -local function CheckVersionDate(Version, Branch) - if not isnumber(Version.Date) then return false end - if not isnumber(Branch.Date) then return false end + local Data = Repo[Realm] + local Branches = Repo.Branches + local Branch = Branches[Data.Head] or Branches.master - return Version.Date >= Branch.Date + if not (Branch and Branch.Date) or Data.NoFiles then + Data.Status = "Unable to check" + elseif Data.Code == Branch.Code or IsUpdated(Data, Branch) then + Data.Status = "Up to date" + else + Data.Status = "Out of date" + end + end end -function ACF.GetVersionStatus(Name) - local Version = Repos[Name] +do -- Repository functions + function ACF.AddRepository(Owner, Name, File) + if not isstring(Owner) then return end + if not isstring(Name) then return end + if not isstring(File) then return end + if Repos[Name] then return end - if not Version then return end - if Version.Status then return Version.Status end + Repos[Name] = { + [Realm] = { + Pattern = "addons/%s/" .. File, + Owner = Owner, + Name = Name, + }, + Branches = {}, + } - local Branch = ACF.GetBranch(Name) - local Status + if CLIENT then + Repos[Name].Server = {} + end + + ACF.CheckLocalVersion(Name) + end - if not Branch or Version.Code == "Not Installed" then - Status = "Unable to check" - elseif Version.Code == Branch.Code or CheckVersionDate(Version, Branch) then - Status = "Up to date" - else - Status = "Out of date" + function ACF.GetRepository(Name) + if not isstring(Name) then return end + + return Repos[Name] end - Version.Status = Status + function ACF.GetLocalRepo(Name) + if not isstring(Name) then return end + + local Data = Repos[Name] - return Status + return Data and Data[Realm] + end + + ACF.AddRepository("Stooberton", "ACF-3", "lua/autorun/acf_loader.lua") +end + +do -- Branch functions + function ACF.GetBranches(Name) + if not isstring(Name) then return end + + local Data = Repos[Name] + + return Data and Data.Branches + end + + function ACF.GetBranch(Name, Branch) + if not isstring(Name) then return end + if not isstring(Branch) then return end + + local Data = Repos[Name] + + if not Data then return end + + return Data.Branches[Branch] + end end diff --git a/lua/acf/base/version/sv_version.lua b/lua/acf/base/version/sv_version.lua index 8d8fc1c35..ce0623ba8 100644 --- a/lua/acf/base/version/sv_version.lua +++ b/lua/acf/base/version/sv_version.lua @@ -1,60 +1,25 @@ +local ACF = ACF local Repos = ACF.Repositories -local PrintLog = ACF.PrintLog - -do -- HTTP Request - local function SuccessfulRequest(Code, Body, OnSuccess, OnFailure) - local Data = Body and util.JSONToTable(Body) - local Error - - if not Body then - Error = "No data found on request." - elseif Code ~= 200 then - Error = "Request unsuccessful (Code " .. Code .. ")." - elseif not (Data and next(Data)) then - Error = "Empty request result." - end - - if Error then - PrintLog("Error", Error) - return OnFailure(Error) - end +do -- Github data conversion + local string = string + local os = os - OnSuccess(Body, Data) - end + local DateData = { year = true, month = true, day = true, hour = true, min = true, sec = true } - function ACF.StartRequest(Link, OnSuccess, OnFailure, Headers) - OnSuccess = OnSuccess or function() end - OnFailure = OnFailure or function() end - - http.Fetch( - Link, - function(Body, _, _, Code) - SuccessfulRequest(Code, Body, OnSuccess, OnFailure) - end, - function(Error) - PrintLog("Error", Error) - - OnFailure(Error) - end, - Headers) - end -end - -do -- Github data conversion function ACF.GetDateEpoch(GitDate) local Date, Time = unpack(string.Explode("T", GitDate)) local Year, Month, Day = unpack(string.Explode("-", Date)) local Hour, Min, Sec = unpack(string.Explode(":", Time)) - return os.time({ - year = Year, - month = Month, - day = Day, - hour = Hour, - min = Min, - sec = Sec:sub(1, 2), - }) + DateData.year = Year + DateData.month = Month + DateData.day = Day + DateData.hour = Hour + DateData.min = Min + DateData.sec = Sec:sub(1, 2) + + return os.time(DateData) end function ACF.GetCommitMessage(Message) @@ -72,7 +37,7 @@ do -- Github data conversion end do -- Branch version retrieval and version printing - local Branches = "https://api.github.com/repos/%s/%s/branches" + local BranchLink = "https://api.github.com/repos/%s/%s/branches" local Commits = "https://api.github.com/repos/%s/%s/commits?per_page=1&sha=%s" local Messages = { @@ -90,77 +55,62 @@ do -- Branch version retrieval and version printing }, } - local function PrintStatus(Version) - local Branch = ACF.GetBranch(Version.Name) - local Lapse = ACF.GetTimeLapse(Branch.Date) - - local Data = Messages[Version.Status] - local Message = Data.Message + local function PrintStatus(Data) + local Branch = ACF.GetBranch(Data.Name, Data.Head) + local Lapse = ACF.GetTimeLapse(Branch.Date) + local LogData = Messages[Data.Status] - PrintLog(Data.Type, Message:format(Version.Name, Version.Code, Lapse)) + ACF.PrintLog(LogData.Type, LogData.Message:format(Data.Name, Data.Code, Lapse)) end local function GetBranchData(Data, Branch, Commit) local Title, Body = ACF.GetCommitMessage(Commit.commit.message) local Date = ACF.GetDateEpoch(Commit.commit.author.date) - Branch.Title = Title - Branch.Body = Body - Branch.Date = Date - Branch.Link = Commit.html_url + Branch.Title = Title + Branch.Body = Body + Branch.Date = Date + Branch.Author = Commit.commit.author.name + Branch.Link = Commit.html_url - if Data.Head == Branch.Name then - ACF.GetVersionStatus(Data.Name) + if Branch.Name == Data.Head then + ACF.CheckLocalStatus(Data.Name) PrintStatus(Data) end end - local function GetBranches(Name, Data, List) - local Request = ACF.StartRequest - - Data.Branches = {} - + local function LoadBranches(Data, Branches, List) for _, Branch in ipairs(List) do local SHA = Branch.commit.sha - - Data.Branches[Branch.name] = { + local Current = { Name = Branch.name, Code = "Git-" .. Branch.name .. "-" .. SHA:sub(1, 7), - Title = false, - Body = false, - Date = false, - Link = false, } - local Current = Data.Branches[Branch.name] + Branches[Branch.name] = Current - Request( - Commits:format(Data.Owner, Name, SHA), + ACF.StartRequest( + Commits:format(Data.Owner, Data.Name, SHA), function(_, Commit) GetBranchData(Data, Current, unpack(Commit)) - end) + end + ) end end - local function CheckAllRepos() - local Request = ACF.StartRequest - - for Name, Data in pairs(Repos) do - ACF.GetVersion(Name) + hook.Add("Initialize", "ACF Request Git Data", function() + for Name, Repo in pairs(Repos) do + local Data = Repo.Server - Request( - Branches:format(Data.Owner, Name), + ACF.StartRequest( + BranchLink:format(Data.Owner, Name), function(_, List) - GetBranches(Name, Data, List) + LoadBranches(Data, Repo.Branches, List) end) end - end - hook.Add("Initialize", "ACF Request Git Data", function() - timer.Simple(0, CheckAllRepos) - - hook.Add("Initialize", "ACF Request Git Data") + hook.Remove("Initialize", "ACF Request Git Data") end) ACF.AddLogType("Update_Ok", "Updates") @@ -172,8 +122,10 @@ do -- Client syncronization util.AddNetworkString("ACF_VersionSync") hook.Add("ACF_OnPlayerLoaded", "ACF_VersionSync", function(Player) + local JSON = util.TableToJSON(Repos) + net.Start("ACF_VersionSync") - net.WriteTable(Repos) + net.WriteString(JSON) net.Send(Player) end) end From a5d073b29c35d71d0e6e6a2c382f52e4b334cb6f Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sat, 16 Jan 2021 02:25:27 -0300 Subject: [PATCH 263/279] Added Updates menu - Populated the Updates menu item, it'll show the latest version of both the server and the client. --- lua/acf/client/menu_items/updates_menu.lua | 90 ++++++++++++++++++++++ lua/acf/client/spawn_menu.lua | 2 - 2 files changed, 90 insertions(+), 2 deletions(-) create mode 100644 lua/acf/client/menu_items/updates_menu.lua diff --git a/lua/acf/client/menu_items/updates_menu.lua b/lua/acf/client/menu_items/updates_menu.lua new file mode 100644 index 000000000..69e6a55c5 --- /dev/null +++ b/lua/acf/client/menu_items/updates_menu.lua @@ -0,0 +1,90 @@ +local ACF = ACF +local Repository, MenuBase + +local function LoadCommit(Base, Commit) + local Date = Commit.Date + + Base:AddTitle(Commit.Title or "No Title") + Base:AddLabel("Author: " .. (Commit.Author or "Unknown")) + Base:AddLabel("Date: " .. (Date and os.date("%D", Date) or "Unknown")) + Base:AddLabel("Time: " .. (Date and os.date("%T", Date) or "Unknown")) + Base:AddLabel(Commit.Body or "No commit message.") + + local View = Base:AddButton("View this commit") + function View:DoClickInternal() + gui.OpenURL(Commit.Link) + end +end + +local function AddStatus(Name, Branches) + local Data = Repository[Name] + local Branch = Branches[Data.Head] or Branches.master + local Base = MenuBase:AddCollapsible(Name .. " Status") + + Base:SetTooltip("Left-click to copy the " .. Name .. " version to your clipboard!") + + function Base:OnMousePressed(Code) + if Code ~= MOUSE_LEFT then return end + + SetClipboardText(Data.Code or "Unknown") + end + + Base:AddTitle("Status: " .. (Data.Status or "Unknown")) + Base:AddLabel("Version: " .. (Data.Code or "Unknown")) + + if Branch and Data.Status ~= "Up to date" then + Base:AddLabel("Latest: " .. Branch.Code) + end + + Base:AddLabel("Branch: " .. (Data.Head or "Unknown")) + + if Branch then + local Commit, Header = Base:AddCollapsible("Latest Commit", false) + + function Header:OnToggle(Expanded) + if not Expanded then return end + if self.Loaded then return end + + LoadCommit(Commit, Branch) + + self.Loaded = true + end + else + Base:AddTitle("Unable to retrieve the latest commit.") + end + + MenuBase:AddLabel("") -- Empty space +end + +local function UpdateMenu() + if not IsValid(MenuBase) then return end + if not Repository then return end + + local Branches = Repository.Branches + + MenuBase:ClearTemporal() + MenuBase:StartTemporal() + + AddStatus("Server", Branches) + AddStatus("Client", Branches) + + MenuBase:EndTemporal() +end + +local function CreateMenu(Menu) + Menu:AddTitle("ACF Version Status") + + MenuBase = Menu:AddPanel("ACF_Panel") + + UpdateMenu() +end + +ACF.AddMenuItem(101, "About the Addon", "Updates", "newspaper", CreateMenu) + +hook.Add("ACF_UpdatedRepository", "ACF Updates Menu", function(Name, Repo) + if Name ~= "ACF-3" then return end + + Repository = Repo + + UpdateMenu() +end) diff --git a/lua/acf/client/spawn_menu.lua b/lua/acf/client/spawn_menu.lua index 97ce759af..2c4596714 100644 --- a/lua/acf/client/spawn_menu.lua +++ b/lua/acf/client/spawn_menu.lua @@ -75,8 +75,6 @@ do -- Menu population functions end ACF.AddMenuOption(1, "About the Addon", "information") - ACF.AddMenuItem(101, "About the Addon", "Updates", "newspaper") -- TODO: Add Updates item - ACF.AddMenuOption(101, "Settings", "wrench") ACF.AddMenuOption(201, "Entities", "brick") ACF.AddMenuOption(9999, "Fun Stuff", "bricks") From 32ac5592b6bffc8c51d399090521cfd148e412bf Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sat, 16 Jan 2021 08:18:58 -0300 Subject: [PATCH 264/279] Optimized clientside debris networking - Optimized debris by sending a single JSON string for every networked entity. - Converted serverside convars used for debris to server datavars. - Moved all the clientside debris convars to the ACF globals file. - Small reorganization on server damage file. - Fixed default success value on ACF.SendNotify. - Added shared ACF.RandomVector function. --- lua/acf/base/acf_globals.lua | 7 +- lua/acf/base/util/sh_util.lua | 8 + lua/acf/client/damage.lua | 287 +++++----- lua/acf/server/damage.lua | 901 +++++++++++++++--------------- lua/acf/server/persisted_vars.lua | 5 + 5 files changed, 610 insertions(+), 598 deletions(-) diff --git a/lua/acf/base/acf_globals.lua b/lua/acf/base/acf_globals.lua index b14638e4c..1cf9aed98 100644 --- a/lua/acf/base/acf_globals.lua +++ b/lua/acf/base/acf_globals.lua @@ -184,6 +184,11 @@ elseif CLIENT then CreateClientConVar("acf_maxroundsdisplay", 16, true, false, "Maximum rounds to display before using bulk display (0 to only display bulk)", 0, 5000) CreateClientConVar("acf_drawboxes", 1, true, false, "Whether or not to draw hitboxes on ACF entities", 0, 1) CreateClientConVar("acf_legalhints", 1, true, true, "If enabled, ACF will throw a warning hint whenever an entity gets disabled.", 0, 1) + CreateClientConVar("acf_debris", 1, true, false, "Toggles ACF Debris.", 0, 1) + CreateClientConVar("acf_debris_collision", 0, true, false, "Toggles debris collisions with other entities.", 0, 1) + CreateClientConVar("acf_debris_gibmultiplier", 1, true, false, "The amount of gibs spawned when created by ACF debris.", 0, 1) + CreateClientConVar("acf_debris_giblifetime", 60, true, false, "Defines lifetime in seconds of each debris gib.", 1, 300) + CreateClientConVar("acf_debris_lifetime", 60, true, false, "Defines lifetime in seconds of each debris entity.", 1, 300) -- Display Info Bubble ---------------------- local ShowInfo = GetConVar("acf_show_entity_info") @@ -249,7 +254,7 @@ do -- ACF Notify ----------------------------------- if SERVER then function ACF.SendNotify(Player, Success, Message) net.Start("ACF_Notify") - net.WriteBool(Success or true) + net.WriteBool(Success or false) net.WriteString(Message or "") net.Send(Player) end diff --git a/lua/acf/base/util/sh_util.lua b/lua/acf/base/util/sh_util.lua index 6c5040441..b34c12627 100644 --- a/lua/acf/base/util/sh_util.lua +++ b/lua/acf/base/util/sh_util.lua @@ -196,6 +196,14 @@ function switch(cases, arg) return cases.default end +function ACF.RandomVector(Min, Max) + local X = math.Rand(Min.x, Max.x) + local Y = math.Rand(Min.y, Max.y) + local Z = math.Rand(Min.z, Max.z) + + return Vector(X, Y, Z) +end + do -- Native type verification functions function ACF.CheckNumber(Value, Default) if not Value then return Default end diff --git a/lua/acf/client/damage.lua b/lua/acf/client/damage.lua index ec4cedab7..6a28e1f6b 100644 --- a/lua/acf/client/damage.lua +++ b/lua/acf/client/damage.lua @@ -1,8 +1,4 @@ -local RandFloat = math.Rand -local RandInt = math.random -local Clamp = math.Clamp -local MathMax = math.max - +local ACF = ACF local Damaged = { CreateMaterial("ACF_Damaged1", "VertexLitGeneric", { ["$basetexture"] = "damaged/damaged1" @@ -73,152 +69,169 @@ net.Receive("ACF_RenderDamage", function() end end) --- Debris & Burning Debris Effects -- - -game.AddParticles("particles/fire_01.pcf") -PrecacheParticleSystem("burning_gib_01") -PrecacheParticleSystem("env_fire_small_smoke") -PrecacheParticleSystem("smoke_gib_01") -PrecacheParticleSystem("smoke_exhaust_01a") -PrecacheParticleSystem("smoke_small_01b") -PrecacheParticleSystem("embers_medium_01") - -local function Particle(Entity, pEffect) - return CreateParticleSystem(Entity, pEffect, PATTACH_ABSORIGIN_FOLLOW) -end - -local DebrisMasterCVar = CreateClientConVar("acf_debris", "1", true, false, - "Toggles ACF Debris." -) -local CollisionCVar = CreateClientConVar("acf_debris_collision", "0", true, false, - "Toggles whether debris created by ACF collides with objects. Disabling can prevent certain types of spam-induced lag & crashes." -) -local GibCVar = CreateClientConVar("acf_debris_gibmultiplier", "1", true, false, - "The amount of gibs spawned when created by ACF debris." -) -local GibSizeCVar = CreateClientConVar("acf_debris_gibsize", "1", true, false, - "The size of the gibs created by ACF debris." -) -local CVarGibLife = CreateClientConVar("acf_debris_giblifetime", "60", true, false, - "How long a gib will live in the world before fading. Default 30 to 60 seconds." -) -local CVarDebrisLife = CreateClientConVar("acf_debris_lifetime", "60", true, false, - "How long solid debris will live in the world before fading. Default 30 to 60 seconds." -) - -local function RandomPos( vecMin, vecMax ) - randomX = RandFloat(vecMin.x, vecMax.x) - randomY = RandFloat(vecMin.y, vecMax.y) - randomZ = RandFloat(vecMin.z, vecMax.z) - return Vector(randomX, randomY, randomZ) -end - -local function FadeAway( Ent ) -- local function Entity:FadeAway() is incorrect syntax????????? Am I referencing a hook somehow? - if not IsValid(Ent) then return end - Ent:SetRenderMode(RENDERMODE_TRANSCOLOR) - Ent:SetRenderFX(kRenderFxFadeSlow) -- interestingly, not synced to CurTime(). - local Smk, Emb = Ent.ACFSmokeParticle, Ent.ACFEmberParticle - if Smk then Smk:StopEmission() end - if Emb then Emb:StopEmission() end - timer.Simple(5, function() Ent:StopAndDestroyParticles() Ent:Remove() end) -end - -local function IgniteCL( Ent, Lifetime, Gib ) -- Lifetime describes fire life, smoke lasts until the entity is removed. - if Gib then - Particle(Ent, "burning_gib_01") - timer.Simple(Lifetime * 0.2, function() - if IsValid(Ent) then - Ent:StopParticlesNamed("burning_gib_01") - end - end) - else - Particle(Ent, "env_fire_small_smoke") - Ent.ACFSmokeParticle = Particle(Ent, "smoke_small_01b") - timer.Simple(Lifetime * 0.4, function() - if IsValid(Ent) then - Ent:StopParticlesNamed("env_fire_small_smoke") - end +do -- Debris Effects ------------------------ + local AllowDebris = GetConVar("acf_debris") + local CollideAll = GetConVar("acf_debris_collision") + local DebrisLife = GetConVar("acf_debris_lifetime") + local GibMult = GetConVar("acf_debris_gibmultiplier") + local GibLife = GetConVar("acf_debris_giblifetime") + local GibModel = "models/gibs/metal_gib%s.mdl" + + local function Particle(Entity, Effect) + return CreateParticleSystem(Entity, Effect, PATTACH_ABSORIGIN_FOLLOW) + end + + local function FadeAway(Entity) + if not IsValid(Entity) then return end + + local Smoke = Entity.SmokeParticle + local Ember = Entity.EmberParticle + + Entity:SetRenderMode(RENDERMODE_TRANSCOLOR) + Entity:SetRenderFX(kRenderFxFadeSlow) -- NOTE: Not synced to CurTime() + + if Smoke then Smoke:StopEmission() end + if Ember then Ember:StopEmission() end + + timer.Simple(5, function() + Entity:StopAndDestroyParticles() + Entity:Remove() end) end -end - -net.Receive("ACF_Debris", function() - - if DebrisMasterCVar:GetInt() < 1 then return end - - local HitVec = net.ReadVector() - local Power = net.ReadFloat() - local Mass = net.ReadFloat() - local Mdl = net.ReadString() - local Mat = net.ReadString() - local Col = net.ReadColor() - local Pos = net.ReadVector() - local Ang = net.ReadAngle() - local WillGib = net.ReadFloat() - local WillIgnite = net.ReadFloat() - - local Min, Max = Vector(), Vector() - local Radius = 1 - - local Debris = ents.CreateClientProp(Mdl) - Debris:SetPos(Pos) - Debris:SetAngles(Ang) - Debris:SetColor(Col) - if Mat then Debris:SetMaterial(Mat) end - if CollisionCVar:GetInt() < 1 then Debris:SetCollisionGroup(COLLISION_GROUP_WORLD) end - Debris:Spawn() - local DebrisLifetime = RandFloat(0.5, 1) * MathMax(CVarDebrisLife:GetFloat(), 1) - timer.Simple(DebrisLifetime, function() FadeAway(Debris) end) - - if IsValid(Debris) then - - Min, Max = Debris:OBBMins(), Debris:OBBMaxs() --for gibs - Radius = Debris:BoundingRadius() - - Debris.ACFEmberParticle = Particle(Debris, "embers_medium_01") - if WillIgnite > 0 and RandFloat(0, 1) * 0.2 < ACF.DebrisIgniteChance then - IgniteCL(Debris, DebrisLifetime, false) + + local function Ignite(Entity, Lifetime, IsGib) + if IsGib then + Particle(Entity, "burning_gib_01") + + timer.Simple(Lifetime * 0.2, function() + if not IsValid(Entity) then return end + + Entity:StopParticlesNamed("burning_gib_01") + end) + else + Entity.SmokeParticle = Particle(Entity, "smoke_small_01b") + + Particle(Entity, "env_fire_small_smoke") + + timer.Simple(Lifetime * 0.4, function() + if not IsValid(Entity) then return end + + Entity:StopParticlesNamed("env_fire_small_smoke") + end) + end + end + + local function CreateDebris(Data) + local Debris = ents.CreateClientProp(Data.Model) + + if not IsValid(Debris) then return end + + local Lifetime = DebrisLife:GetFloat() * math.Rand(0.5, 1) + + Debris:SetPos(Data.Position) + Debris:SetAngles(Data.Angles) + Debris:SetColor(Data.Color) + Debris:SetMaterial(Data.Material) + + if not CollideAll:GetBool() then + Debris:SetCollisionGroup(COLLISION_GROUP_WORLD) + end + + Debris:Spawn() + + Debris.EmberParticle = Particle(Debris, "embers_medium_01") + + if Data.Ignite and math.Rand(0, 0.5) < ACF.DebrisIgniteChance then + Ignite(Debris, Lifetime) else - Debris.ACFSmokeParticle = Particle(Debris, "smoke_exhaust_01a") + Debris.SmokeParticle = Particle(Debris, "smoke_exhaust_01a") end - -- Debris (not gibs) has a 5 times higher chance of igniting since we're already saying that the debris will ignite. - local Phys = Debris:GetPhysicsObject() - if IsValid(Phys) then - Phys:SetMass(Mass * 0.1) - Phys:ApplyForceOffset(HitVec:GetNormalized() * Power * 70, Debris:GetPos() + VectorRand() * 20) + local PhysObj = Debris:GetPhysicsObject() + + if IsValid(PhysObj) then + PhysObj:ApplyForceOffset(Data.Normal * Data.Power, Data.Position + VectorRand() * 20) end + timer.Simple(Lifetime, function() + FadeAway(Debris) + end) + + return Debris end - if WillGib > 0 and GibCVar:GetFloat() > 0 then - local GibCount = Clamp(Radius * 0.05, 1, MathMax(20 * GibCVar:GetFloat(), 1)) - for _ = 1, GibCount do -- should we base this on prop volume? + local function CreateGib(Data, Min, Max) + local Gib = ents.CreateClientProp(GibModel:format(math.random(1, 5))) + + if not IsValid(Gib) then return end + + local Lifetime = GibLife:GetFloat() * math.Rand(0.5, 1) + local Offset = ACF.RandomVector(Min, Max) + + Offset:Rotate(Data.Angles) + + Gib:SetPos(Data.Position + Offset) + Gib:SetAngles(AngleRand(-180, 180)) + Gib:SetModelScale(math.Rand(0.5, 2)) + Gib:SetMaterial(Data.Material) + Gib:SetColor(Data.Color) + Gib:Spawn() - local Gib = ents.CreateClientProp("models/gibs/metal_gib" .. RandInt(1,5) .. ".mdl") - if not IsValid(Gib) then break end -- we probably hit edict limit, stop looping - local RandomBox = RandomPos(Min, Max) - RandomBox:Rotate(Ang) - Gib:SetPos(Pos + RandomBox) - Gib:SetAngles(AngleRand(-180,180)) - Gib:SetModelScale(Clamp(Radius * 0.01 * GibSizeCVar:GetFloat(), 1, 20)) - Gib.ACFSmokeParticle = Particle(Gib, "smoke_gib_01") - Gib:Spawn() - Gib:Activate() + Gib.SmokeParticle = Particle(Gib, "smoke_gib_01") - local GibLifetime = RandFloat(0.5, 1) * MathMax(CVarGibLife:GetFloat(), 1) - timer.Simple(GibLifetime, function() FadeAway(Gib) end) - if RandFloat(0,1) < ACF.DebrisIgniteChance then IgniteCL(Gib, GibLifetime, true) end -- Gibs always ignite but still follow IgniteChance + if math.random() < ACF.DebrisIgniteChance then + Ignite(Gib, Lifetime, true) + end - local GibPhys = Gib:GetPhysicsObject() - GibPhys:ApplyForceOffset(HitVec:GetNormalized() * Power, GibPhys:GetPos() + VectorRand() * 20) + local PhysObj = Gib:GetPhysicsObject() + if IsValid(PhysObj) then + PhysObj:ApplyForceOffset(Data.Normal * Data.Power, Gib:GetPos() + VectorRand() * 20) end + + timer.Simple(Lifetime, function() + FadeAway(Gib) + end) + + return true end - local BreakEffect = EffectData() - BreakEffect:SetOrigin(Pos) -- TODO: Change this to the hit vector, but we need to redefine HitVec as HitNorm - BreakEffect:SetScale(20) - util.Effect("cball_explode", BreakEffect) + net.Receive("ACF_Debris", function() + local Data = util.JSONToTable(net.ReadString()) + + if not AllowDebris:GetBool() then return end + + local Debris = CreateDebris(Data) + + if IsValid(Debris) then + local Multiplier = GibMult:GetFloat() + local Radius = Debris:BoundingRadius() + local Min = Debris:OBBMins() + local Max = Debris:OBBMaxs() + + if Data.CanGib and Multiplier > 0 then + local GibCount = math.Clamp(Radius * 0.1, 1, math.max(10 * Multiplier, 1)) + + for _ = 1, GibCount do + if not CreateGib(Data, Min, Max) then + break + end + end + end + end -end) \ No newline at end of file + local Effect = EffectData() + Effect:SetOrigin(Data.Position) -- TODO: Change this to the hit vector, but we need to redefine HitVec as HitNorm + Effect:SetScale(20) + util.Effect("cball_explode", Effect) + end) + + game.AddParticles("particles/fire_01.pcf") + + PrecacheParticleSystem("burning_gib_01") + PrecacheParticleSystem("env_fire_small_smoke") + PrecacheParticleSystem("smoke_gib_01") + PrecacheParticleSystem("smoke_exhaust_01a") + PrecacheParticleSystem("smoke_small_01b") + PrecacheParticleSystem("embers_medium_01") +end ----------------------------------------- \ No newline at end of file diff --git a/lua/acf/server/damage.lua b/lua/acf/server/damage.lua index 4c1810d18..77560659c 100644 --- a/lua/acf/server/damage.lua +++ b/lua/acf/server/damage.lua @@ -4,14 +4,12 @@ local ACF_HEPUSH = GetConVar("acf_hepush") local TimerCreate = timer.Create local TraceRes = {} local TraceData = { output = TraceRes, mask = MASK_SOLID, filter = false } -local Check = ACF.Check local HookRun = hook.Run local Trace = ACF.TraceF local ValidDebris = ACF.ValidDebris local ChildDebris = ACF.ChildDebris local DragDiv = ACF.DragDiv -util.AddNetworkString("ACF_Debris") -- Local Funcs ---------------------------------- local function CalcDamage(Entity, Energy, FrArea, Angle) @@ -76,602 +74,585 @@ ACF.KEShove = Shove ------------------------------------------------- -do - do -- Squishy tracking - ACF.Squishies = ACF.Squishies or {} +do -- Explosions ---------------------------- + local function GetRandomPos(Entity, IsChar) + if IsChar then + local Mins, Maxs = Entity:OBBMins() * 0.65, Entity:OBBMaxs() * 0.65 -- Scale down the "hitbox" since most of the character is in the middle + local Rand = Vector(math.Rand(Mins[1], Maxs[1]), math.Rand(Mins[2], Maxs[2]), math.Rand(Mins[3], Maxs[3])) - local Squishies = ACF.Squishies + return Entity:LocalToWorld(Rand) + else + local Mesh = Entity:GetPhysicsObject():GetMesh() - hook.Add("PlayerSpawnedNPC", "ACF Squishies", function(_, Ent) - Squishies[Ent] = true - end) - - hook.Add("OnNPCKilled", "ACF Squishies", function(Ent) - Squishies[Ent] = nil - end) - - hook.Add("PlayerSpawn", "ACF Squishies", function(Ent) - Squishies[Ent] = true - end) - - hook.Add("PostPlayerDeath", "ACF Squishies", function(Ent) - Squishies[Ent] = nil - end) - - hook.Add("EntityRemoved", "ACF Squishies", function(Ent) - Squishies[Ent] = nil - end) - end - - do -- Explosions ---------------------------- - local function GetRandomPos(Entity, IsChar) - if IsChar then - local Mins, Maxs = Entity:OBBMins() * 0.65, Entity:OBBMaxs() * 0.65 -- Scale down the "hitbox" since most of the character is in the middle + if not Mesh then -- Is Make-Sphericaled + local Mins, Maxs = Entity:OBBMins(), Entity:OBBMaxs() local Rand = Vector(math.Rand(Mins[1], Maxs[1]), math.Rand(Mins[2], Maxs[2]), math.Rand(Mins[3], Maxs[3])) - return Entity:LocalToWorld(Rand) + return Entity:LocalToWorld(Rand:GetNormalized() * math.Rand(1, Entity:BoundingRadius() * 0.5)) -- Attempt to a random point in the sphere else - local Mesh = Entity:GetPhysicsObject():GetMesh() - - if not Mesh then -- Is Make-Sphericaled - local Mins, Maxs = Entity:OBBMins(), Entity:OBBMaxs() - local Rand = Vector(math.Rand(Mins[1], Maxs[1]), math.Rand(Mins[2], Maxs[2]), math.Rand(Mins[3], Maxs[3])) - - return Entity:LocalToWorld(Rand:GetNormalized() * math.Rand(1, Entity:BoundingRadius() * 0.5)) -- Attempt to a random point in the sphere - else - local Rand = math.random(3, #Mesh / 3) * 3 - local P = Vector(0, 0, 0) + local Rand = math.random(3, #Mesh / 3) * 3 + local P = Vector(0, 0, 0) - for I = Rand - 2, Rand do P = P + Mesh[I].pos end + for I = Rand - 2, Rand do P = P + Mesh[I].pos end - return Entity:LocalToWorld(P / 3) -- Attempt to hit a point on a face of the mesh - end + return Entity:LocalToWorld(P / 3) -- Attempt to hit a point on a face of the mesh end end + end - function ACF_HE(Origin, FillerMass, FragMass, Inflictor, Filter, Gun) - debugoverlay.Cross(Origin, 15, 15, Color( 255, 255, 255 ), true) - Filter = Filter or {} - - local Power = FillerMass * ACF.HEPower --Power in KiloJoules of the filler mass of TNT - local Radius = FillerMass ^ 0.33 * 8 * 39.37 -- Scaling law found on the net, based on 1PSI overpressure from 1 kg of TNT at 15m - local MaxSphere = 4 * 3.1415 * (Radius * 2.54) ^ 2 --Surface Area of the sphere at maximum radius - local Amp = math.min(Power / 2000, 50) - local Fragments = math.max(math.floor((FillerMass / FragMass) * ACF.HEFrag), 2) - local FragWeight = FragMass / Fragments - local BaseFragV = (Power * 50000 / FragWeight / Fragments) ^ 0.5 - local FragArea = (FragWeight / 7.8) ^ 0.33 - local Damaged = {} - local Ents = ents.FindInSphere(Origin, Radius) - local Loop = true -- Find more props to damage whenever a prop dies - - TraceData.filter = Filter - TraceData.start = Origin + function ACF.HE(Origin, FillerMass, FragMass, Inflictor, Filter, Gun) + debugoverlay.Cross(Origin, 15, 15, Color( 255, 255, 255 ), true) + Filter = Filter or {} - util.ScreenShake(Origin, Amp, Amp, Amp / 15, Radius * 10) + local Power = FillerMass * ACF.HEPower --Power in KiloJoules of the filler mass of TNT + local Radius = FillerMass ^ 0.33 * 8 * 39.37 -- Scaling law found on the net, based on 1PSI overpressure from 1 kg of TNT at 15m + local MaxSphere = 4 * 3.1415 * (Radius * 2.54) ^ 2 --Surface Area of the sphere at maximum radius + local Amp = math.min(Power / 2000, 50) + local Fragments = math.max(math.floor((FillerMass / FragMass) * ACF.HEFrag), 2) + local FragWeight = FragMass / Fragments + local BaseFragV = (Power * 50000 / FragWeight / Fragments) ^ 0.5 + local FragArea = (FragWeight / 7.8) ^ 0.33 + local Damaged = {} + local Ents = ents.FindInSphere(Origin, Radius) + local Loop = true -- Find more props to damage whenever a prop dies - while Loop and Power > 0 do - Loop = false + TraceData.filter = Filter + TraceData.start = Origin - local PowerSpent = 0 - local Damage = {} + util.ScreenShake(Origin, Amp, Amp, Amp / 15, Radius * 10) - for K, Ent in ipairs(Ents) do -- Find entities to deal damage to - if not Check(Ent) then -- Entity is not valid to ACF + while Loop and Power > 0 do + Loop = false - Ents[K] = nil -- Remove from list - Filter[#Filter + 1] = Ent -- Filter from traces + local PowerSpent = 0 + local Damage = {} - continue - end + for K, Ent in ipairs(Ents) do -- Find entities to deal damage to + if not ACF.Check(Ent) then -- Entity is not valid to ACF - if Damage[Ent] then continue end -- A trace sent towards another prop already hit this one instead, no need to check if we can see it + Ents[K] = nil -- Remove from list + Filter[#Filter + 1] = Ent -- Filter from traces - if Ent.Exploding then -- Detonate explody things immediately if they're already cooking off + continue + end - Ents[K] = nil - Filter[#Filter + 1] = Ent + if Damage[Ent] then continue end -- A trace sent towards another prop already hit this one instead, no need to check if we can see it - --Ent:Detonate() - continue - end + if Ent.Exploding then -- Detonate explody things immediately if they're already cooking off + Ents[K] = nil + Filter[#Filter + 1] = Ent - local IsChar = Ent:IsPlayer() or Ent:IsNPC() - if IsChar and Ent:Health() <= 0 then - Ents[K] = nil - Filter[#Filter + 1] = Ent -- Shouldn't need to filter a dead player but we'll do it just in case + --Ent:Detonate() + continue + end - continue - end + local IsChar = Ent:IsPlayer() or Ent:IsNPC() + if IsChar and Ent:Health() <= 0 then + Ents[K] = nil + Filter[#Filter + 1] = Ent -- Shouldn't need to filter a dead player but we'll do it just in case - local Target = GetRandomPos(Ent, IsChar) -- Try to hit a random spot on the entity - local Displ = Target - Origin + continue + end - TraceData.endpos = Origin + Displ:GetNormalized() * (Displ:Length() + 24) - Trace(TraceData) -- Outputs to TraceRes + local Target = GetRandomPos(Ent, IsChar) -- Try to hit a random spot on the entity + local Displ = Target - Origin - if TraceRes.HitNonWorld then - Ent = TraceRes.Entity + TraceData.endpos = Origin + Displ:GetNormalized() * (Displ:Length() + 24) + Trace(TraceData) -- Outputs to TraceRes - if Check(Ent) then - if not Ent.Exploding and not Damage[Ent] and not Damaged[Ent] then -- Hit an entity that we haven't already damaged yet (Note: Damaged != Damage) - local Mul = IsChar and 0.65 or 1 -- Scale down boxes for players/NPCs because the bounding box is way bigger than they actually are + if TraceRes.HitNonWorld then + Ent = TraceRes.Entity - debugoverlay.Line(Origin, TraceRes.HitPos, 30, Color(0, 255, 0), true) -- Green line for a hit trace - debugoverlay.BoxAngles(Ent:GetPos(), Ent:OBBMins() * Mul, Ent:OBBMaxs() * Mul, Ent:GetAngles(), 30, Color(255, 0, 0, 1)) + if ACF.Check(Ent) then + if not Ent.Exploding and not Damage[Ent] and not Damaged[Ent] then -- Hit an entity that we haven't already damaged yet (Note: Damaged != Damage) + local Mul = IsChar and 0.65 or 1 -- Scale down boxes for players/NPCs because the bounding box is way bigger than they actually are - local Pos = Ent:GetPos() - local Distance = Origin:Distance(Pos) - local Sphere = math.max(4 * 3.1415 * (Distance * 2.54) ^ 2, 1) -- Surface Area of the sphere at the range of that prop - local Area = math.min(Ent.ACF.Area / Sphere, 0.5) * MaxSphere -- Project the Area of the prop to the Area of the shadow it projects at the explosion max radius + debugoverlay.Line(Origin, TraceRes.HitPos, 30, Color(0, 255, 0), true) -- Green line for a hit trace + debugoverlay.BoxAngles(Ent:GetPos(), Ent:OBBMins() * Mul, Ent:OBBMaxs() * Mul, Ent:GetAngles(), 30, Color(255, 0, 0, 1)) - Damage[Ent] = { - Dist = Distance, - Vec = (Pos - Origin):GetNormalized(), - Area = Area, - Index = K - } + local Pos = Ent:GetPos() + local Distance = Origin:Distance(Pos) + local Sphere = math.max(4 * 3.1415 * (Distance * 2.54) ^ 2, 1) -- Surface Area of the sphere at the range of that prop + local Area = math.min(Ent.ACF.Area / Sphere, 0.5) * MaxSphere -- Project the Area of the prop to the Area of the shadow it projects at the explosion max radius - Ents[K] = nil -- Removed from future damage searches (but may still block LOS) - end - else -- If check on new ent fails - --debugoverlay.Line(Origin, TraceRes.HitPos, 30, Color(255, 0, 0)) -- Red line for a invalid ent + Damage[Ent] = { + Dist = Distance, + Vec = (Pos - Origin):GetNormalized(), + Area = Area, + Index = K + } - Ents[K] = nil -- Remove from list - Filter[#Filter + 1] = Ent -- Filter from traces + Ents[K] = nil -- Removed from future damage searches (but may still block LOS) end - else - -- Not removed from future damage sweeps so as to provide multiple chances to be hit - debugoverlay.Line(Origin, TraceRes.HitPos, 30, Color(0, 0, 255)) -- Blue line for a miss - end - end + else -- If check on new ent fails + --debugoverlay.Line(Origin, TraceRes.HitPos, 30, Color(255, 0, 0)) -- Red line for a invalid ent - for Ent, Table in pairs(Damage) do -- Deal damage to the entities we found - local Feathering = (1 - math.min(1, Table.Dist / Radius)) ^ ACF.HEFeatherExp - local AreaFraction = Table.Area / MaxSphere - local PowerFraction = Power * AreaFraction -- How much of the total power goes to that prop - local AreaAdjusted = (Ent.ACF.Area / ACF.Threshold) * Feathering - local Blast = { Penetration = PowerFraction ^ ACF.HEBlastPen * AreaAdjusted } - local BlastRes = ACF_Damage(Ent, Blast, AreaAdjusted, 0, Inflictor, 0, Gun, "HE") - local FragHit = math.floor(Fragments * AreaFraction) - local FragVel = math.max(BaseFragV - ((Table.Dist / BaseFragV) * BaseFragV ^ 2 * FragWeight ^ 0.33 / 10000) / DragDiv, 0) - local FragKE = ACF_Kinetic(FragVel, FragWeight * FragHit, 1500) - local Losses = BlastRes.Loss * 0.5 - local FragRes - - if FragHit > 0 then - FragRes = ACF_Damage(Ent, FragKE, FragArea * FragHit, 0, Inflictor, 0, Gun, "Frag") - Losses = Losses + FragRes.Loss * 0.5 + Ents[K] = nil -- Remove from list + Filter[#Filter + 1] = Ent -- Filter from traces end + else + -- Not removed from future damage sweeps so as to provide multiple chances to be hit + debugoverlay.Line(Origin, TraceRes.HitPos, 30, Color(0, 0, 255)) -- Blue line for a miss + end + end - if (BlastRes and BlastRes.Kill) or (FragRes and FragRes.Kill) then -- We killed something - Filter[#Filter + 1] = Ent -- Filter out the dead prop - Ents[Table.Index] = nil -- Don't bother looking for it in the future + for Ent, Table in pairs(Damage) do -- Deal damage to the entities we found + local Feathering = (1 - math.min(1, Table.Dist / Radius)) ^ ACF.HEFeatherExp + local AreaFraction = Table.Area / MaxSphere + local PowerFraction = Power * AreaFraction -- How much of the total power goes to that prop + local AreaAdjusted = (Ent.ACF.Area / ACF.Threshold) * Feathering + local Blast = { Penetration = PowerFraction ^ ACF.HEBlastPen * AreaAdjusted } + local BlastRes = ACF.Damage(Ent, Blast, AreaAdjusted, 0, Inflictor, 0, Gun, "HE") + local FragHit = math.floor(Fragments * AreaFraction) + local FragVel = math.max(BaseFragV - ((Table.Dist / BaseFragV) * BaseFragV ^ 2 * FragWeight ^ 0.33 / 10000) / DragDiv, 0) + local FragKE = ACF_Kinetic(FragVel, FragWeight * FragHit, 1500) + local Losses = BlastRes.Loss * 0.5 + local FragRes + + if FragHit > 0 then + FragRes = ACF.Damage(Ent, FragKE, FragArea * FragHit, 0, Inflictor, 0, Gun, "Frag") + Losses = Losses + FragRes.Loss * 0.5 + end - local Debris = ACF_HEKill(Ent, Table.Vec, PowerFraction, Origin) -- Make some debris + if (BlastRes and BlastRes.Kill) or (FragRes and FragRes.Kill) then -- We killed something + Filter[#Filter + 1] = Ent -- Filter out the dead prop + Ents[Table.Index] = nil -- Don't bother looking for it in the future - for _,v in ipairs(Debris) do - if IsValid(v) then Filter[#Filter + 1] = v end -- Filter that out too - end + local Debris = ACF.HEKill(Ent, Table.Vec, PowerFraction, Origin) -- Make some debris - Loop = true -- Check for new targets since something died, maybe we'll find something new - elseif ACF_HEPUSH:GetBool() then -- Just damaged, not killed, so push on it some - Shove(Ent, Origin, Table.Vec, PowerFraction * 33.3) -- Assuming about 1/30th of the explosive energy goes to propelling the target prop (Power in KJ * 1000 to get J then divided by 33) + for Fireball in pairs(Debris) do + if IsValid(Fireball) then Filter[#Filter + 1] = Fireball end -- Filter that out too end - PowerSpent = PowerSpent + PowerFraction * Losses -- Removing the energy spent killing props - Damaged[Ent] = true -- This entity can no longer recieve damage from this explosion + Loop = true -- Check for new targets since something died, maybe we'll find something new + elseif ACF_HEPUSH:GetBool() then -- Just damaged, not killed, so push on it some + Shove(Ent, Origin, Table.Vec, PowerFraction * 33.3) -- Assuming about 1/30th of the explosive energy goes to propelling the target prop (Power in KJ * 1000 to get J then divided by 33) end - Power = math.max(Power - PowerSpent, 0) + PowerSpent = PowerSpent + PowerFraction * Losses -- Removing the energy spent killing props + Damaged[Ent] = true -- This entity can no longer recieve damage from this explosion end + + Power = math.max(Power - PowerSpent, 0) end + end - local function CanSee(Target, Data) - local R = Trace(Data) + ACF_HE = ACF.HE +end ----------------------------------------- - return R.Entity == Target or not R.Hit or (Target:InVehicle() and R.Entity == Target:GetVehicle()) - end +do -- Overpressure -------------------------- + ACF.Squishies = ACF.Squishies or {} - function ACF.Overpressure(Origin, Energy, Inflictor, Source, Forward, Angle) - local Radius = Energy ^ 0.33 * 0.025 * 39.37 -- Radius in meters (Completely arbitrary stuff, scaled to have 120s have a radius of about 20m) - local Data = { start = Origin, endpos = true, mask = MASK_SHOT } + local Squishies = ACF.Squishies - if Source then -- Filter out guns - if Source.BarrelFilter then - Data.filter = {} + local function CanSee(Target, Data) + local R = Trace(Data) - for K, V in pairs(Source.BarrelFilter) do Data.filter[K] = V end -- Quick copy of gun barrel filter - else - Data.filter = { Source } - end + return R.Entity == Target or not R.Hit or (Target:InVehicle() and R.Entity == Target:GetVehicle()) + end + + hook.Add("PlayerSpawnedNPC", "ACF Squishies", function(_, Ent) + Squishies[Ent] = true + end) + + hook.Add("OnNPCKilled", "ACF Squishies", function(Ent) + Squishies[Ent] = nil + end) + + hook.Add("PlayerSpawn", "ACF Squishies", function(Ent) + Squishies[Ent] = true + end) + + hook.Add("PostPlayerDeath", "ACF Squishies", function(Ent) + Squishies[Ent] = nil + end) + + hook.Add("EntityRemoved", "ACF Squishies", function(Ent) + Squishies[Ent] = nil + end) + + function ACF.Overpressure(Origin, Energy, Inflictor, Source, Forward, Angle) + local Radius = Energy ^ 0.33 * 0.025 * 39.37 -- Radius in meters (Completely arbitrary stuff, scaled to have 120s have a radius of about 20m) + local Data = { start = Origin, endpos = true, mask = MASK_SHOT } + + if Source then -- Filter out guns + if Source.BarrelFilter then + Data.filter = {} + + for K, V in pairs(Source.BarrelFilter) do Data.filter[K] = V end -- Quick copy of gun barrel filter + else + Data.filter = { Source } end + end - util.ScreenShake(Origin, Energy, 1, 0.25, Radius * 3 * 39.37 ) + util.ScreenShake(Origin, Energy, 1, 0.25, Radius * 3 * 39.37 ) - if Forward and Angle then -- Blast direction and angle are specified - Angle = math.rad(Angle * 0.5) -- Convert deg to rads + if Forward and Angle then -- Blast direction and angle are specified + Angle = math.rad(Angle * 0.5) -- Convert deg to rads - for V in pairs(ACF.Squishies) do - if math.acos(Forward:Dot((V:GetShootPos() - Origin):GetNormalized())) < Angle then - local D = V:GetShootPos():Distance(Origin) + for V in pairs(ACF.Squishies) do + if math.acos(Forward:Dot((V:GetShootPos() - Origin):GetNormalized())) < Angle then + local D = V:GetShootPos():Distance(Origin) - if D / 39.37 <= Radius then + if D / 39.37 <= Radius then - Data.endpos = V:GetShootPos() + VectorRand() * 5 + Data.endpos = V:GetShootPos() + VectorRand() * 5 - if CanSee(V, Data) then - local Damage = Energy * 175000 * (1 / D^3) + if CanSee(V, Data) then + local Damage = Energy * 175000 * (1 / D^3) - V:TakeDamage(Damage, Inflictor, Source) - end + V:TakeDamage(Damage, Inflictor, Source) end end end - else -- Spherical blast - for V in pairs(ACF.Squishies) do - if CanSee(Origin, V) then - local D = V:GetShootPos():Distance(Origin) + end + else -- Spherical blast + for V in pairs(ACF.Squishies) do + if CanSee(Origin, V) then + local D = V:GetShootPos():Distance(Origin) - if D / 39.37 <= Radius then + if D / 39.37 <= Radius then - Data.endpos = V:GetShootPos() + VectorRand() * 5 + Data.endpos = V:GetShootPos() + VectorRand() * 5 - if CanSee(V, Data) then - local Damage = Energy * 150000 * (1 / D^3) + if CanSee(V, Data) then + local Damage = Energy * 150000 * (1 / D^3) - V:TakeDamage(Damage, Inflictor, Source) - end + V:TakeDamage(Damage, Inflictor, Source) end end end end end end - - do -- Deal Damage --------------------------- - local function SquishyDamage(Entity, Energy, FrArea, Angle, Inflictor, Bone, Gun) - local Size = Entity:BoundingRadius() - local Mass = Entity:GetPhysicsObject():GetMass() - local HitRes = {} - local Damage = 0 - - --We create a dummy table to pass armour values to the calc function - local Target = { - ACF = { - Armour = 0.1 - } +end ----------------------------------------- + +do -- Deal Damage --------------------------- + local function SquishyDamage(Entity, Energy, FrArea, Angle, Inflictor, Bone, Gun) + local Size = Entity:BoundingRadius() + local Mass = Entity:GetPhysicsObject():GetMass() + local HitRes = {} + local Damage = 0 + + --We create a dummy table to pass armour values to the calc function + local Target = { + ACF = { + Armour = 0.1 } + } + + if Bone then + --This means we hit the head + if Bone == 1 then + Target.ACF.Armour = Mass * 0.02 --Set the skull thickness as a percentage of Squishy weight, this gives us 2mm for a player, about 22mm for an Antlion Guard. Seems about right + HitRes = CalcDamage(Target, Energy, FrArea, Angle) --This is hard bone, so still sensitive to impact angle + Damage = HitRes.Damage * 20 + + --If we manage to penetrate the skull, then MASSIVE DAMAGE + if HitRes.Overkill > 0 then + Target.ACF.Armour = Size * 0.25 * 0.01 --A quarter the bounding radius seems about right for most critters head size + HitRes = CalcDamage(Target, Energy, FrArea, 0) + Damage = Damage + HitRes.Damage * 100 + end - if (Bone) then - --This means we hit the head - if (Bone == 1) then - Target.ACF.Armour = Mass * 0.02 --Set the skull thickness as a percentage of Squishy weight, this gives us 2mm for a player, about 22mm for an Antlion Guard. Seems about right - HitRes = CalcDamage(Target, Energy, FrArea, Angle) --This is hard bone, so still sensitive to impact angle - Damage = HitRes.Damage * 20 - - --If we manage to penetrate the skull, then MASSIVE DAMAGE - if HitRes.Overkill > 0 then - Target.ACF.Armour = Size * 0.25 * 0.01 --A quarter the bounding radius seems about right for most critters head size - HitRes = CalcDamage(Target, Energy, FrArea, 0) - Damage = Damage + HitRes.Damage * 100 - end - - Target.ACF.Armour = Mass * 0.065 --Then to check if we can get out of the other side, 2x skull + 1x brains - HitRes = CalcDamage(Target, Energy, FrArea, Angle) - Damage = Damage + HitRes.Damage * 20 - elseif (Bone == 0 or Bone == 2 or Bone == 3) then - --This means we hit the torso. We are assuming body armour/tough exoskeleton/zombie don't give fuck here, so it's tough - Target.ACF.Armour = Mass * 0.08 --Set the armour thickness as a percentage of Squishy weight, this gives us 8mm for a player, about 90mm for an Antlion Guard. Seems about right - HitRes = CalcDamage(Target, Energy, FrArea, Angle) --Armour plate,, so sensitive to impact angle - Damage = HitRes.Damage * 5 - - if HitRes.Overkill > 0 then - Target.ACF.Armour = Size * 0.5 * 0.02 --Half the bounding radius seems about right for most critters torso size - HitRes = CalcDamage(Target, Energy, FrArea, 0) - Damage = Damage + HitRes.Damage * 50 --If we penetrate the armour then we get into the important bits inside, so DAMAGE - end - - Target.ACF.Armour = Mass * 0.185 --Then to check if we can get out of the other side, 2x armour + 1x guts - HitRes = CalcDamage(Target, Energy, FrArea, Angle) - elseif (Bone == 4 or Bone == 5) then - --This means we hit an arm or appendage, so ormal damage, no armour - Target.ACF.Armour = Size * 0.2 * 0.02 --A fitht the bounding radius seems about right for most critters appendages - HitRes = CalcDamage(Target, Energy, FrArea, 0) --This is flesh, angle doesn't matter - Damage = HitRes.Damage * 30 --Limbs are somewhat less important - elseif (Bone == 6 or Bone == 7) then - Target.ACF.Armour = Size * 0.2 * 0.02 --A fitht the bounding radius seems about right for most critters appendages - HitRes = CalcDamage(Target, Energy, FrArea, 0) --This is flesh, angle doesn't matter - Damage = HitRes.Damage * 30 --Limbs are somewhat less important - elseif (Bone == 10) then - --This means we hit a backpack or something - Target.ACF.Armour = Size * 0.1 * 0.02 --Arbitrary size, most of the gear carried is pretty small - HitRes = CalcDamage(Target, Energy, FrArea, 0) --This is random junk, angle doesn't matter - Damage = HitRes.Damage * 2 --Damage is going to be fright and shrapnel, nothing much - else --Just in case we hit something not standard - Target.ACF.Armour = Size * 0.2 * 0.02 + Target.ACF.Armour = Mass * 0.065 --Then to check if we can get out of the other side, 2x skull + 1x brains + HitRes = CalcDamage(Target, Energy, FrArea, Angle) + Damage = Damage + HitRes.Damage * 20 + elseif Bone == 0 or Bone == 2 or Bone == 3 then + --This means we hit the torso. We are assuming body armour/tough exoskeleton/zombie don't give fuck here, so it's tough + Target.ACF.Armour = Mass * 0.08 --Set the armour thickness as a percentage of Squishy weight, this gives us 8mm for a player, about 90mm for an Antlion Guard. Seems about right + HitRes = CalcDamage(Target, Energy, FrArea, Angle) --Armour plate,, so sensitive to impact angle + Damage = HitRes.Damage * 5 + + if HitRes.Overkill > 0 then + Target.ACF.Armour = Size * 0.5 * 0.02 --Half the bounding radius seems about right for most critters torso size HitRes = CalcDamage(Target, Energy, FrArea, 0) - Damage = HitRes.Damage * 30 + Damage = Damage + HitRes.Damage * 50 --If we penetrate the armour then we get into the important bits inside, so DAMAGE end + + Target.ACF.Armour = Mass * 0.185 --Then to check if we can get out of the other side, 2x armour + 1x guts + HitRes = CalcDamage(Target, Energy, FrArea, Angle) + elseif Bone == 4 or Bone == 5 then + --This means we hit an arm or appendage, so ormal damage, no armour + Target.ACF.Armour = Size * 0.2 * 0.02 --A fitht the bounding radius seems about right for most critters appendages + HitRes = CalcDamage(Target, Energy, FrArea, 0) --This is flesh, angle doesn't matter + Damage = HitRes.Damage * 30 --Limbs are somewhat less important + elseif Bone == 6 or Bone == 7 then + Target.ACF.Armour = Size * 0.2 * 0.02 --A fitht the bounding radius seems about right for most critters appendages + HitRes = CalcDamage(Target, Energy, FrArea, 0) --This is flesh, angle doesn't matter + Damage = HitRes.Damage * 30 --Limbs are somewhat less important + elseif (Bone == 10) then + --This means we hit a backpack or something + Target.ACF.Armour = Size * 0.1 * 0.02 --Arbitrary size, most of the gear carried is pretty small + HitRes = CalcDamage(Target, Energy, FrArea, 0) --This is random junk, angle doesn't matter + Damage = HitRes.Damage * 2 --Damage is going to be fright and shrapnel, nothing much else --Just in case we hit something not standard Target.ACF.Armour = Size * 0.2 * 0.02 HitRes = CalcDamage(Target, Energy, FrArea, 0) - Damage = HitRes.Damage * 10 + Damage = HitRes.Damage * 30 end - - --if Ammo == true then - -- Entity.KilledByAmmo = true - --end - Entity:TakeDamage(Damage, Inflictor, Gun) - --if Ammo == true then - -- Entity.KilledByAmmo = false - --end - HitRes.Kill = false - --print(Damage) - --print(Bone) - - return HitRes + else --Just in case we hit something not standard + Target.ACF.Armour = Size * 0.2 * 0.02 + HitRes = CalcDamage(Target, Energy, FrArea, 0) + Damage = HitRes.Damage * 10 end - local function VehicleDamage(Entity, Energy, FrArea, Angle, Inflictor, _, Gun) - local HitRes = CalcDamage(Entity, Energy, FrArea, Angle) - local Driver = Entity:GetDriver() + Entity:TakeDamage(Damage, Inflictor, Gun) - if IsValid(Driver) then - SquishyDamage(Driver, Energy, FrArea, Angle, Inflictor, math.Rand(0, 7), Gun) - end + HitRes.Kill = false - HitRes.Kill = false + return HitRes + end - if HitRes.Damage >= Entity.ACF.Health then - HitRes.Kill = true - else - Entity.ACF.Health = Entity.ACF.Health - HitRes.Damage - Entity.ACF.Armour = Entity.ACF.Armour * (0.5 + Entity.ACF.Health / Entity.ACF.MaxHealth / 2) --Simulating the plate weakening after a hit - end + local function VehicleDamage(Entity, Energy, FrArea, Angle, Inflictor, _, Gun) + local HitRes = CalcDamage(Entity, Energy, FrArea, Angle) + local Driver = Entity:GetDriver() - return HitRes + if IsValid(Driver) then + SquishyDamage(Driver, Energy, FrArea, Angle, Inflictor, math.Rand(0, 7), Gun) end - local function PropDamage(Entity, Energy, FrArea, Angle) - local HitRes = CalcDamage(Entity, Energy, FrArea, Angle) - HitRes.Kill = false + HitRes.Kill = false - if HitRes.Damage >= Entity.ACF.Health then - HitRes.Kill = true - else - Entity.ACF.Health = Entity.ACF.Health - HitRes.Damage - Entity.ACF.Armour = math.Clamp(Entity.ACF.MaxArmour * (0.5 + Entity.ACF.Health / Entity.ACF.MaxHealth / 2) ^ 1.7, Entity.ACF.MaxArmour * 0.25, Entity.ACF.MaxArmour) --Simulating the plate weakening after a hit - - --math.Clamp( Entity.ACF.Ductility, -0.8, 0.8 ) - if Entity.ACF.PrHealth and Entity.ACF.PrHealth ~= Entity.ACF.Health then - if not ACF_HealthUpdateList then - ACF_HealthUpdateList = {} - - -- We should send things slowly to not overload traffic. - TimerCreate("ACF_HealthUpdateList", 1, 1, function() - local Table = {} - - for _, v in pairs(ACF_HealthUpdateList) do - if IsValid(v) then - table.insert(Table, { - ID = v:EntIndex(), - Health = v.ACF.Health, - MaxHealth = v.ACF.MaxHealth - }) - end - end + if HitRes.Damage >= Entity.ACF.Health then + HitRes.Kill = true + else + Entity.ACF.Health = Entity.ACF.Health - HitRes.Damage + Entity.ACF.Armour = Entity.ACF.Armour * (0.5 + Entity.ACF.Health / Entity.ACF.MaxHealth / 2) --Simulating the plate weakening after a hit + end + + return HitRes + end - net.Start("ACF_RenderDamage") - net.WriteTable(Table) - net.Broadcast() + local function PropDamage(Entity, Energy, FrArea, Angle) + local HitRes = CalcDamage(Entity, Energy, FrArea, Angle) + + HitRes.Kill = false + + if HitRes.Damage >= Entity.ACF.Health then + HitRes.Kill = true + else + Entity.ACF.Health = Entity.ACF.Health - HitRes.Damage + Entity.ACF.Armour = math.Clamp(Entity.ACF.MaxArmour * (0.5 + Entity.ACF.Health / Entity.ACF.MaxHealth / 2) ^ 1.7, Entity.ACF.MaxArmour * 0.25, Entity.ACF.MaxArmour) --Simulating the plate weakening after a hit + + --math.Clamp( Entity.ACF.Ductility, -0.8, 0.8 ) + if Entity.ACF.PrHealth and Entity.ACF.PrHealth ~= Entity.ACF.Health then + if not ACF_HealthUpdateList then + ACF_HealthUpdateList = {} + + -- We should send things slowly to not overload traffic. + TimerCreate("ACF_HealthUpdateList", 1, 1, function() + local Table = {} + + for _, v in pairs(ACF_HealthUpdateList) do + if IsValid(v) then + table.insert(Table, { + ID = v:EntIndex(), + Health = v.ACF.Health, + MaxHealth = v.ACF.MaxHealth + }) + end + end - ACF_HealthUpdateList = nil - end) - end + net.Start("ACF_RenderDamage") + net.WriteTable(Table) + net.Broadcast() - table.insert(ACF_HealthUpdateList, Entity) + ACF_HealthUpdateList = nil + end) end - Entity.ACF.PrHealth = Entity.ACF.Health + table.insert(ACF_HealthUpdateList, Entity) end - return HitRes + Entity.ACF.PrHealth = Entity.ACF.Health end - ACF.PropDamage = PropDamage + return HitRes + end - function ACF_Damage(Entity, Energy, FrArea, Angle, Inflictor, Bone, Gun, Type) - local Activated = Check(Entity) + ACF.PropDamage = PropDamage - if HookRun("ACF_BulletDamage", Activated, Entity, Energy, FrArea, Angle, Inflictor, Bone, Gun) == false or Activated == false then - return { - Damage = 0, - Overkill = 0, - Loss = 0, - Kill = false - } - end + function ACF.Damage(Entity, Energy, FrArea, Angle, Inflictor, Bone, Gun, Type) + local Activated = ACF.Check(Entity) - if Entity.ACF_OnDamage then -- Use special damage function if target entity has one - return Entity:ACF_OnDamage(Energy, FrArea, Angle, Inflictor, Bone, Type) - elseif Activated == "Prop" then - return PropDamage(Entity, Energy, FrArea, Angle, Inflictor, Bone) - elseif Activated == "Vehicle" then - return VehicleDamage(Entity, Energy, FrArea, Angle, Inflictor, Bone, Gun) - elseif Activated == "Squishy" then - return SquishyDamage(Entity, Energy, FrArea, Angle, Inflictor, Bone, Gun) - end + if HookRun("ACF_BulletDamage", Activated, Entity, Energy, FrArea, Angle, Inflictor, Bone, Gun) == false or Activated == false then + return { + Damage = 0, + Overkill = 0, + Loss = 0, + Kill = false + } end - end ----------------------------------------- - do -- Remove Props ------------------------------ - local function KillChildProps( Entity, BlastPos, Energy ) - - local Explosives = {} - local Children = ACF_GetAllChildren(Entity) - local Count = 0 + if Entity.ACF_OnDamage then -- Use special damage function if target entity has one + return Entity:ACF_OnDamage(Energy, FrArea, Angle, Inflictor, Bone, Type) + elseif Activated == "Prop" then + return PropDamage(Entity, Energy, FrArea, Angle, Inflictor, Bone) + elseif Activated == "Vehicle" then + return VehicleDamage(Entity, Energy, FrArea, Angle, Inflictor, Bone, Gun) + elseif Activated == "Squishy" then + return SquishyDamage(Entity, Energy, FrArea, Angle, Inflictor, Bone, Gun) + end + end - -- do an initial processing pass on children, separating out explodey things to handle last - for Ent in pairs( Children ) do - Ent.ACF_Killed = true -- mark that it's already processed + ACF_Damage = ACF.Damage +end ----------------------------------------- - if not ValidDebris[Ent:GetClass()] then - Children[Ent] = nil -- ignoring stuff like holos, wiremod components, etc. - else - Ent:SetParent(nil) +do -- Remove Props ------------------------------ + util.AddNetworkString("ACF_Debris") - if Ent.IsExplosive and not Ent.Exploding then - Explosives[Ent] = true - Children[Ent] = nil - else - Count = Count + 1 - end - end - end + local Queue = {} - -- HE kill the children of this ent, instead of disappearing them by removing parent - if next(Children) then - local DebrisChance = math.Clamp(ChildDebris / Count, 0, 1) - local Power = Energy / math.min(Count,3) - - for Ent in pairs( Children ) do - if math.random() < DebrisChance then - ACF_HEKill(Ent, (Ent:GetPos() - BlastPos):GetNormalized(), Power) - else - constraint.RemoveAll(Ent) - Ent:Remove() - end - end - end + local function SendQueue() + for Entity, Data in pairs(Queue) do + local JSON = util.TableToJSON(Data) - -- explode stuff last, so we don't re-process all that junk again in a new explosion - if next(Explosives) then - for Ent in pairs(Explosives) do - if Ent.Exploding then continue end + net.Start("ACF_Debris") + net.WriteString(JSON) + net.SendPVS(Data.Position) - Ent.Exploding = true - Ent.Inflictor = Entity.Inflictor - Ent:Detonate() - end - end + Queue[Entity] = nil end + end - ACF_KillChildProps = KillChildProps + local function DebrisNetter(Entity, Normal, Power, CanGib, Ignite) + if not ACF.GetServerBool("CreateDebris") then return end + if Queue[Entity] then return end - -- Debris -- + local Current = Entity:GetColor() + local New = Vector(Current.r, Current.g, Current.b) * math.Rand(0.3, 0.6) - local CVarDisableDebris = CreateConVar( - "acf_debris", 1, 0, -- Default 1, No flags - "Setting this to 0 disables debris from being sent to clients. Reduces server network overhead." - ) + if not next(Queue) then + timer.Create("ACF_DebrisQueue", 0, 1, SendQueue) + end - local function DebrisNetter(Entity, HitVector, Power, Gib, Ignite) + Queue[Entity] = { + Position = Entity:GetPos(), + Angles = Entity:GetAngles(), + Material = Entity:GetMaterial(), + Model = Entity:GetModel(), + Color = Color(New.x, New.y, New.z, Current.a), + Normal = Normal, + Power = Power, + CanGib = CanGib or nil, + Ignite = Ignite or nil, + } + end - if CVarDisableDebris:GetInt() < 1 then return end + function ACF.KillChildProps(Entity, BlastPos, Energy) + local Explosives = {} + local Children = ACF_GetAllChildren(Entity) + local Count = 0 - local Mdl = Entity:GetModel() - local Mat = Entity:GetMaterial() - local Col = Entity:GetColor() - local ColR, ColG, ColB, ColA = Col.r, Col.g, Col.b, Col.a -- https://github.com/Facepunch/garrysmod-issues/issues/2407 - Col = Color(ColR * 0.5, ColG * 0.5, ColB * 0.5, ColA) -- how bout i do anyway - local Pos = Entity:GetPos() - local Ang = Entity:GetAngles() - local Mass = Entity:GetPhysicsObject():GetMass() or 1 + -- do an initial processing pass on children, separating out explodey things to handle last + for Ent in pairs(Children) do + Ent.ACF_Killed = true -- mark that it's already processed - net.Start("ACF_Debris") - net.WriteVector(HitVector) - net.WriteFloat(Power) - net.WriteFloat(Mass) - net.WriteString(Mdl) - net.WriteString(Mat) - net.WriteColor(Col) - net.WriteVector(Pos) - net.WriteAngle(Ang) - net.WriteFloat(Gib) - net.WriteFloat(Ignite) - net.SendPVS(Pos) + if not ValidDebris[Ent:GetClass()] then + Children[Ent] = nil -- ignoring stuff like holos, wiremod components, etc. + else + Ent:SetParent() + + if Ent.IsExplosive and not Ent.Exploding then + Explosives[Ent] = true + Children[Ent] = nil + else + Count = Count + 1 + end + end end - local CreateFireballs = CreateConVar( - "acf_fireballs", 0, 0, -- Default 0, No flags - "Create serverside fireballs. Allows compatibility with mods like vFire, but is more taxing on server resources." - ) - - local FireballMultiplier = CreateConVar( - "acf_fireballmult", 1, 0, -- Default 1, No flags - "When fireballs are enabled, multiplies the amount created from a prop." - ) - - local function RandomPos( vecMin, vecMax ) - randomX = math.Rand(vecMin.x, vecMax.x) - randomY = math.Rand(vecMin.y, vecMax.y) - randomZ = math.Rand(vecMin.z, vecMax.z) - return Vector(randomX, randomY, randomZ) + -- HE kill the children of this ent, instead of disappearing them by removing parent + if next(Children) then + local DebrisChance = math.Clamp(ChildDebris / Count, 0, 1) + local Power = Energy / math.min(Count,3) + + for Ent in pairs( Children ) do + if math.random() < DebrisChance then + ACF.HEKill(Ent, (Ent:GetPos() - BlastPos):GetNormalized(), Power) + else + constraint.RemoveAll(Ent) + Ent:Remove() + end + end end - function ACF_HEKill(Entity, HitVector, Energy, BlastPos) -- blast pos is an optional world-pos input for flinging away children props more realistically - -- if it hasn't been processed yet, check for children - if not Entity.ACF_Killed then KillChildProps(Entity, BlastPos or Entity:GetPos(), Energy) end + -- explode stuff last, so we don't re-process all that junk again in a new explosion + if next(Explosives) then + for Ent in pairs(Explosives) do + if Ent.Exploding then continue end - local DebrisTable = {} - local Radius = Entity:BoundingRadius() + Ent.Exploding = true + Ent.Inflictor = Entity.Inflictor + Ent:Detonate() + end + end + end - --if Radius < ACF.DebrisScale then constraint.RemoveAll(Entity) Entity:Remove() else -- undersize? just delete it and move on. + function ACF.HEKill(Entity, Normal, Energy, BlastPos) -- blast pos is an optional world-pos input for flinging away children props more realistically + -- if it hasn't been processed yet, check for children + if not Entity.ACF_Killed then + ACF.KillChildProps(Entity, BlastPos or Entity:GetPos(), Energy) + end - local Power = Energy - DebrisNetter(Entity, HitVector, Power, 0, 1) + local Radius = Entity:BoundingRadius() + local Debris = {} - if CreateFireballs:GetInt() > 0 then + DebrisNetter(Entity, Normal, Energy, false, true) - local Pos = Entity:GetPos() - local Ang = Entity:GetAngles() - local Min, Max = Entity:OBBMins(), Entity:OBBMaxs() + if ACF.GetServerBool("CreateFireballs") then + local Fireballs = math.Clamp(Radius * 0.01, 1, math.max(10 * ACF.GetServerNumber("FireballMult", 1), 1)) + local Min, Max = Entity:OBBMins(), Entity:OBBMaxs() + local Pos = Entity:GetPos() + local Ang = Entity:GetAngles() - local FireballCount = math.Clamp(Radius * 0.01, 1, math.max(10 * FireballMultiplier:GetFloat(), 1)) - for _ = 1, FireballCount do -- should we base this on prop volume? + for _ = 1, Fireballs do -- should we base this on prop volume? + local Fireball = ents.Create("acf_debris") - local Fireball = ents.Create("acf_debris") - if IsValid(Fireball) then -- we probably hit edict limit, stop looping - local RandomBox = RandomPos(Min, Max) - RandomBox:Rotate(Ang) - Fireball:SetPos(Pos + RandomBox) - Fireball:Spawn() + if not IsValid(Fireball) then break end -- we probably hit edict limit, stop looping - local FireLifetime = math.Rand(5,15) -- fireball lifetime - Fireball:Ignite(FireLifetime) - timer.Simple(FireLifetime, function() if IsValid(Fireball) then Fireball:Remove() end end) -- check validity on last + local Lifetime = math.Rand(5, 15) + local Offset = ACF.RandomVector(Min, Max) - local Phys = Fireball:GetPhysicsObject() - if IsValid(Phys) then Phys:ApplyForceOffset(HitVector:GetNormalized() * Power * 15, Fireball:GetPos() + VectorRand() * 10) end + Offset:Rotate(Ang) - table.insert(DebrisTable,Fireball) - end + Fireball:SetPos(Pos + Offset) + Fireball:Spawn() + Fireball:Ignite(Lifetime) - end + timer.Simple(Lifetime, function() + if not IsValid(Fireball) then return end - end + Fireball:Remove() + end) - constraint.RemoveAll(Entity) - Entity:Remove() + local Phys = Fireball:GetPhysicsObject() - --end - return DebrisTable + if IsValid(Phys) then + Phys:ApplyForceOffset(Normal * Energy / Fireballs, Fireball:GetPos() + VectorRand()) + end + Debris[Fireball] = true + end end - function ACF_APKill(Entity, HitVector, Power) - KillChildProps(Entity, Entity:GetPos(), Power) -- kill the children of this ent, instead of disappearing them from removing parent + constraint.RemoveAll(Entity) + Entity:Remove() - --if Radius > ACF.DebrisScale then DebrisNetter(Entity, HitVector, Power, true, false) end - -- Entity, HitNormal, Number, ShouldGib, ShouldIgnite - DebrisNetter(Entity, HitVector, Power, 1, 0) - -- Entity, HitNormal, Number, ShouldGib, ShouldIgnite + return Debris + end - constraint.RemoveAll(Entity) - Entity:Remove() + function ACF.APKill(Entity, Normal, Power) + ACF.KillChildProps(Entity, Entity:GetPos(), Power) -- kill the children of this ent, instead of disappearing them from removing parent - end + DebrisNetter(Entity, Normal, Power, true, false) + constraint.RemoveAll(Entity) + Entity:Remove() end -end \ No newline at end of file + + ACF_KillChildProps = ACF.KillChildProps + ACF_HEKill = ACF.HEKill + ACF_APKill = ACF.APKill +end diff --git a/lua/acf/server/persisted_vars.lua b/lua/acf/server/persisted_vars.lua index 07c98cd96..679996b79 100644 --- a/lua/acf/server/persisted_vars.lua +++ b/lua/acf/server/persisted_vars.lua @@ -5,3 +5,8 @@ ACF.PersistServerData("GunfireEnabled", true) ACF.PersistServerData("AllowFunEnts", true) ACF.PersistServerData("UseKillicons", true) ACF.PersistServerData("ShowFunMenu", true) + +-- Debris +ACF.PersistServerData("CreateDebris", true) +ACF.PersistServerData("CreateFireballs", false) +ACF.PersistServerData("FireballMult", 1) From 64b481dff84cf5f2facba863dddb90af96748523 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sat, 16 Jan 2021 08:19:26 -0300 Subject: [PATCH 265/279] Added debris settings to the menu - Added both serverside and clientside debris settings to the ACF menu. --- lua/acf/client/menu_items/settings_menu.lua | 65 ++++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/lua/acf/client/menu_items/settings_menu.lua b/lua/acf/client/menu_items/settings_menu.lua index 1b4958bbf..d2d9753b3 100644 --- a/lua/acf/client/menu_items/settings_menu.lua +++ b/lua/acf/client/menu_items/settings_menu.lua @@ -68,6 +68,31 @@ do -- Clientside settings Base:AddHelp("You will need to rejoin the server for this option to apply.") end) + + ACF.AddClientSettings("Debris", function(Base) + local Debris = Base:AddCheckBox("Allow creation of clientside debris.") + Debris:SetConVar("acf_debris") + + local Collisions = Base:AddCheckBox("Allow debris to collide with entities.") + Collisions:SetConVar("acf_debris_collision") + + Base:AddHelp("Disabling this can prevent certain types of spam-induced lag and crashes.") + + local Lifetime = Base:AddSlider("Debris Lifetime", 1, 300) + Lifetime:SetConVar("acf_debris_lifetime") + + Base:AddHelp("Defines how long each debris will live before fading out.") + + local Multiplier = Base:AddSlider("Debris Gib Amount", 0.01, 1, 2) + Multiplier:SetConVar("acf_debris_gibmultiplier") + + Base:AddHelp("Multiplier for the amount of clientside debris gibs to be created.") + + local GibLifetime = Base:AddSlider("Debris Gib Lifetime", 1, 300) + GibLifetime:SetConVar("acf_debris_giblifetime") + + Base:AddHelp("Defines how long each debris gib will live before fading out.") + end) end do -- Serverside settings @@ -106,4 +131,42 @@ do -- Serverside settings Base:AddHelp("Changing this option will require a server restart.") end) -end \ No newline at end of file + + ACF.AddServerSettings("Debris", function(Base) + local Debris = Base:AddCheckBox("Allow networking of debris to clients.") + Debris:SetServerData("CreateDebris", "OnChange") + Debris:DefineSetter(function(Panel, _, _, Value) + Panel:SetValue(Value) + + return Value + end) + + local Fireballs = Base:AddCheckBox("Allow creation of serverside debris fireballs.") + Fireballs:SetServerData("CreateFireballs", "OnChange") + Fireballs:DefineSetter(function(Panel, _, _, Value) + Panel:SetValue(Value) + + return Value + end) + + Base:AddHelp("Allows compatibility with addons such as vFire, but is more taxing on server resources.") + + local Multiplier = Base:AddSlider("Fireball Amount", 0.01, 1, 2) + Multiplier:SetServerData("FireballMult", "OnValueChanged") + Multiplier:DefineSetter(function(Panel, _, _, Value) + Panel:SetValue(Value) + + return Value + end) + + Base:AddHelp("Multiplier for the amount of serverside fireballs to be created.") + end) +end + +-- TODO +-- Replace acf_healthmod and ACF.Threshold +-- Replace acf_armormod and ACF.ArmorMod +-- Replace or deprecate acf_ammomod and ACF.AmmoMod +-- Replace acf_fuelrate and ACF.FuelRate +-- Replace acf_spalling +-- Replace acf_gunfire and ACF.GunfireEnabled From ed2a07841f64aacb045f12bfaaf261ae37868156 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sun, 17 Jan 2021 08:16:46 -0300 Subject: [PATCH 266/279] Moved some stuff out of globals - Moved both parts of ACF.SendNotify to utilities. - Moved the player loaded hook for damage rendering to the serverside damage file. --- lua/acf/base/acf_globals.lua | 51 ----------------------------------- lua/acf/base/util/cl_util.lua | 16 +++++++++++ lua/acf/base/util/sv_util.lua | 13 +++++++++ lua/acf/server/damage.lua | 24 +++++++++++++++++ 4 files changed, 53 insertions(+), 51 deletions(-) diff --git a/lua/acf/base/acf_globals.lua b/lua/acf/base/acf_globals.lua index 1cf9aed98..7181302fe 100644 --- a/lua/acf/base/acf_globals.lua +++ b/lua/acf/base/acf_globals.lua @@ -150,8 +150,6 @@ end if SERVER then util.AddNetworkString("ACF_UpdateEntity") - util.AddNetworkString("ACF_RenderDamage") - util.AddNetworkString("ACF_Notify") CreateConVar("acf_enable_workshop_content", 1, FCVAR_ARCHIVE, "Enable workshop content download for clients. Requires server restart on change.", 0, 1) CreateConVar("acf_enable_workshop_extras", 0, FCVAR_ARCHIVE, "Enable extra workshop content download for clients. Requires server restart on change.", 0, 1) @@ -250,55 +248,6 @@ do -- Player loaded hook end end -do -- ACF Notify ----------------------------------- - if SERVER then - function ACF.SendNotify(Player, Success, Message) - net.Start("ACF_Notify") - net.WriteBool(Success or false) - net.WriteString(Message or "") - net.Send(Player) - end - - ACF_SendNotify = ACF.SendNotify -- Backwards compatibility - else - local notification = notification - - net.Receive("ACF_Notify", function() - local Type = NOTIFY_ERROR - - if net.ReadBool() then - Type = NOTIFY_GENERIC - else - surface.PlaySound("buttons/button10.wav") - end - - notification.AddLegacy(net.ReadString(), Type, 7) - end) - end -end ------------------------------------------------ - -do -- Render Damage -------------------------------- - hook.Add("ACF_OnPlayerLoaded", "ACF Render Damage", function(ply) - local Table = {} - - for _, v in pairs(ents.GetAll()) do - if v.ACF and v.ACF.PrHealth then - table.insert(Table, { - ID = v:EntIndex(), - Health = v.ACF.Health, - MaxHealth = v.ACF.MaxHealth - }) - end - end - - if next(Table) then - net.Start("ACF_RenderDamage") - net.WriteTable(Table) - net.Send(ply) - end - end) -end ------------------------------------------------ - --Stupid workaround red added to precache timescaling. hook.Add("Think", "Update ACF Internal Clock", function() ACF.CurTime = CurTime() diff --git a/lua/acf/base/util/cl_util.lua b/lua/acf/base/util/cl_util.lua index 9a9d6d7ea..ac5bd5318 100644 --- a/lua/acf/base/util/cl_util.lua +++ b/lua/acf/base/util/cl_util.lua @@ -69,6 +69,22 @@ do -- Custom fonts }) end +do -- Networked notifications + local notification = notification + + net.Receive("ACF_Notify", function() + local Type = NOTIFY_ERROR + + if net.ReadBool() then + Type = NOTIFY_GENERIC + else + surface.PlaySound("buttons/button10.wav") + end + + notification.AddLegacy(net.ReadString(), Type, 7) + end) +end + do -- Clientside visclip check local function CheckClip(Entity, Clip, Center, Pos) if Clip.physics then return false end -- Physical clips will be ignored, we can't hit them anyway diff --git a/lua/acf/base/util/sv_util.lua b/lua/acf/base/util/sv_util.lua index 73d4db603..9b13be9ad 100644 --- a/lua/acf/base/util/sv_util.lua +++ b/lua/acf/base/util/sv_util.lua @@ -61,6 +61,19 @@ do -- Clientside message delivery end end +do -- Networked notifications + util.AddNetworkString("ACF_Notify") + + function ACF.SendNotify(Player, Success, Message) + net.Start("ACF_Notify") + net.WriteBool(Success or false) + net.WriteString(Message or "") + net.Send(Player) + end + + ACF_SendNotify = ACF.SendNotify -- Backwards compatibility +end + do -- HTTP Request local NoRequest = true local http = http diff --git a/lua/acf/server/damage.lua b/lua/acf/server/damage.lua index 77560659c..8118baa0d 100644 --- a/lua/acf/server/damage.lua +++ b/lua/acf/server/damage.lua @@ -74,6 +74,30 @@ ACF.KEShove = Shove ------------------------------------------------- +do -- Player syncronization + util.AddNetworkString("ACF_RenderDamage") + + hook.Add("ACF_OnPlayerLoaded", "ACF Render Damage", function(ply) + local Table = {} + + for _, v in pairs(ents.GetAll()) do + if v.ACF and v.ACF.PrHealth then + table.insert(Table, { + ID = v:EntIndex(), + Health = v.ACF.Health, + MaxHealth = v.ACF.MaxHealth + }) + end + end + + if next(Table) then + net.Start("ACF_RenderDamage") + net.WriteTable(Table) + net.Send(ply) + end + end) +end + do -- Explosions ---------------------------- local function GetRandomPos(Entity, IsChar) if IsChar then From 9e157fb882fedbcd415a901b4e59c5bed3815fd3 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sun, 17 Jan 2021 09:53:49 -0300 Subject: [PATCH 267/279] Added data variable callbacks - Added shared callbacks for both server and client data variables. The callbacks will be called once per tick per changed variable, giving the last values received as arguments. --- lua/acf/base/data_vars/sh_data_vars.lua | 80 +++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/lua/acf/base/data_vars/sh_data_vars.lua b/lua/acf/base/data_vars/sh_data_vars.lua index bb0dca301..dcd5d3ac2 100644 --- a/lua/acf/base/data_vars/sh_data_vars.lua +++ b/lua/acf/base/data_vars/sh_data_vars.lua @@ -137,3 +137,83 @@ do -- Data persisting hook.Remove("Initialize", "ACF Load Persisted Data") end) end + +do -- Data callbacks + ACF.DataCallbacks = ACF.DataCallbacks or { + Server = {}, + Client = {}, + } + + local Callbacks = ACF.DataCallbacks + + --- Generates the following functions: + -- ACF.AddServerDataCallback(Key, Name, Function) + -- ACF.RemoveServerDataCallback(Key, Name) + -- ACF.AddClientDataCallback(Key, Name, Function) + -- ACF.RemoveClientDataCallback(Key, Name) + + for Realm, Callback in pairs(Callbacks) do + local Queue = {} + + local function ProcessQueue() + for Key, Data in pairs(Queue) do + local Store = Callback[Key] + local Player = Data.Player + local Value = Data.Value + + for _, Function in pairs(Store) do + Function(Player, Key, Value) + end + + Queue[Key] = nil + end + end + + ACF["Add" .. Realm .. "DataCallback"] = function(Key, Name, Function) + if not isstring(Key) then return end + if not isstring(Name) then return end + if not isfunction(Function) then return end + + local Store = Callback[Key] + + if not Store then + Callback[Key] = { + [Name] = Function + } + else + Store[Name] = Function + end + end + + ACF["Remove" .. Realm .. "DataCallback"] = function(Key, Name) + if not isstring(Key) then return end + if not isstring(Name) then return end + + local Store = Callback[Key] + + if not Store then return end + + Store[Name] = nil + end + + hook.Add("ACF_On" .. Realm .. "DataUpdate", "ACF Data Callbacks", function(Player, Key, Value) + if not Callback[Key] then return end + + local Data = Queue[Key] + + if not next(Queue) then + timer.Create("ACF Data Callback", 0, 1, ProcessQueue) + end + + if not Data then + Queue[Key] = { + Player = Player, + Value = Value, + } + else + Data.Player = Player + Data.Value = Value + end + end) + end +end From 3be2c31284c1fbb0f5950e0b88ef73f7f0b49a9f Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sun, 17 Jan 2021 18:34:08 -0300 Subject: [PATCH 268/279] Fixed server data variable networking - Fixed server data variables not being networked properly to the clients when set on the server due to a redundant hook call. --- lua/acf/base/data_vars/sv_data_vars.lua | 8 -------- 1 file changed, 8 deletions(-) diff --git a/lua/acf/base/data_vars/sv_data_vars.lua b/lua/acf/base/data_vars/sv_data_vars.lua index c04293e04..ee21bdc52 100644 --- a/lua/acf/base/data_vars/sv_data_vars.lua +++ b/lua/acf/base/data_vars/sv_data_vars.lua @@ -118,14 +118,6 @@ do -- Data syncronization Client[Player] = nil Queued[Player] = nil end) - - hook.Add("ACF_OnServerDataUpdate", "ACF Network Server Data", function(Player, Key) - for K in pairs(Client) do - if Player ~= K then - NetworkData(Key, K) - end - end - end) end do -- Client data getter functions From fc35ea084515b9327c3182e6d64decb59bd7f0e0 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sun, 17 Jan 2021 21:47:12 -0300 Subject: [PATCH 269/279] Improved settings menu functions, replaced some convars - ACF.AddServerSettings and ACF.AddClientSettings will now take a number a first argument to defien the order at which each settings section will appear on the menu. - Replaced several serverside convars with server data variables and added them to the settings menu. - Added several callbacks for the newly added server data variables. - Removed ACF_CVarChangeCallback function as it's not longer used. --- lua/acf/base/acf_globals.lua | 167 ++++++++------------ lua/acf/base/sv_validation.lua | 5 +- lua/acf/client/menu_items/settings_menu.lua | 117 ++++++++++---- lua/acf/client/spawn_menu.lua | 19 ++- lua/acf/server/persisted_vars.lua | 6 + lua/acf/shared/data_callbacks.lua | 90 +++++++++++ lua/entities/acf_engine/init.lua | 5 +- lua/entities/acf_piledriver/init.lua | 4 +- 8 files changed, 264 insertions(+), 149 deletions(-) create mode 100644 lua/acf/shared/data_callbacks.lua diff --git a/lua/acf/base/acf_globals.lua b/lua/acf/base/acf_globals.lua index 7181302fe..b1348851e 100644 --- a/lua/acf/base/acf_globals.lua +++ b/lua/acf/base/acf_globals.lua @@ -1,35 +1,40 @@ do -- ACF global vars - ACF.AmmoCrates = ACF.AmmoCrates or {} - ACF.Classes = ACF.Classes or {} - ACF.FuelTanks = ACF.FuelTanks or {} - ACF.Repositories = ACF.Repositories or {} - ACF.ClientData = ACF.ClientData or {} - ACF.ServerData = ACF.ServerData or {} + ACF.AmmoCrates = ACF.AmmoCrates or {} + ACF.Classes = ACF.Classes or {} + ACF.FuelTanks = ACF.FuelTanks or {} + ACF.Repositories = ACF.Repositories or {} + ACF.ClientData = ACF.ClientData or {} + ACF.ServerData = ACF.ServerData or {} -- Misc - ACF.Year = 1945 - ACF.IllegalDisableTime = 30 -- Time in seconds for an entity to be disabled when it fails ACF_IsLegal - ACF.GunfireEnabled = true - ACF.SmokeWind = 5 + math.random() * 35 --affects the ability of smoke to be used for screening effect + ACF.Gamemode = 2 -- Gamemode of the server. 1 = Sandbox, 2 = Classic, 3 = Competitive + ACF.Year = 1945 + ACF.IllegalDisableTime = 30 -- Time in seconds for an entity to be disabled when it fails ACF_IsLegal + ACF.GunfireEnabled = true + ACF.AllowAdminData = false -- Allows admins to mess with a few server settings and data variables + ACF.AllowFunEnts = true -- Allows entities listed under the Fun Stuff option to be used + ACF.SmokeWind = 5 + math.random() * 35 --affects the ability of smoke to be used for screening effect -- Fuzes - ACF.MinFuzeCaliber = 20 -- Minimum caliber in millimeters that can be fuzed + ACF.MinFuzeCaliber = 20 -- Minimum caliber in millimeters that can be fuzed -- Reload Mechanics - ACF.BaseReload = 1 -- Minimum reload time. Time it takes to move around a weightless projectile - ACF.MassToTime = 0.2 -- Conversion of projectile mass to time be moved around - ACF.LengthToTime = 0.1 -- Conversion of projectile length to time -- Emulating the added difficulty of manipulating a longer projectile + ACF.BaseReload = 1 -- Minimum reload time. Time it takes to move around a weightless projectile + ACF.MassToTime = 0.2 -- Conversion of projectile mass to time be moved around + ACF.LengthToTime = 0.1 -- Conversion of projectile length to time -- Emulating the added difficulty of manipulating a longer projectile -- External and Terminal Ballistics - ACF.DragDiv = 80 --Drag fudge factor - ACF.Scale = 1 --Scale factor for ACF in the game world - ACF.Threshold = 264.7 --Health Divisor (don"t forget to update cvar function down below) - ACF.PenAreaMod = 0.85 - ACF.KinFudgeFactor = 2.1 --True kinetic would be 2, over that it's speed biased, below it's mass biased - ACF.KEtoRHA = 0.25 --Empirical conversion from (kinetic energy in KJ)/(Area in Cm2) to RHA penetration - ACF.GroundtoRHA = 0.15 --How much mm of steel is a mm of ground worth (Real soil is about 0.15) - ACF.ArmorMod = 1 - ACF.SlopeEffectFactor = 1.1 -- Sloped armor effectiveness: armor / cos(angle)^factor + ACF.DragDiv = 80 --Drag fudge factor + ACF.Scale = 1 --Scale factor for ACF in the game world + ACF.HealthFactor = 1 + ACF.Threshold = 264.7 -- Health Divisor, directly tied to ACF.HealthFactor + ACF.PenAreaMod = 0.85 + ACF.KinFudgeFactor = 2.1 --True kinetic would be 2, over that it's speed biased, below it's mass biased + ACF.KEtoRHA = 0.25 --Empirical conversion from (kinetic energy in KJ)/(Area in Cm2) to RHA penetration + ACF.GroundtoRHA = 0.15 --How much mm of steel is a mm of ground worth (Real soil is about 0.15) + ACF.ArmorMod = 1 + ACF.ArmorFactor = 1 -- Multiplier for ACF.ArmorMod + ACF.SlopeEffectFactor = 1.1 -- Sloped armor effectiveness: armor / cos(angle)^factor ACF.GlobalFilter = { -- Global ACF filter gmod_ghost = true, acf_debris = true, @@ -43,35 +48,34 @@ do -- ACF global vars } -- Ammo - ACF.AmmoArmor = 5 -- How many millimeters of armor ammo crates have - ACF.AmmoPadding = 2 -- Millimeters of wasted space between rounds - ACF.AmmoMod = 1.05 -- Ammo modifier. 1 is 1x the amount of ammo. 0.6 default - ACF.AmmoCaseScale = 1.4 -- How much larger the diameter of the case is versus the projectile (necked cartridges, M829 is 1.4, .50 BMG is 1.6) - ACF.PBase = 875 --1KG of propellant produces this much KE at the muzzle, in kj - ACF.PScale = 1 --Gun Propellant power expotential - ACF.MVScale = 0.5 --Propellant to MV convertion expotential - ACF.PDensity = 0.95 -- Propellant loading density (Density of propellant + volume lost due to packing density) + ACF.AmmoArmor = 5 -- How many millimeters of armor ammo crates have + ACF.AmmoPadding = 2 -- Millimeters of wasted space between rounds + ACF.AmmoMod = 1.05 -- DEPRECATED. Ammo modifier. 1 is 1x the amount of ammo. 0.6 default + ACF.AmmoCaseScale = 1.4 -- How much larger the diameter of the case is versus the projectile (necked cartridges, M829 is 1.4, .50 BMG is 1.6) + ACF.PBase = 875 --1KG of propellant produces this much KE at the muzzle, in kj + ACF.PScale = 1 --Gun Propellant power expotential + ACF.MVScale = 0.5 --Propellant to MV convertion expotential + ACF.PDensity = 0.95 -- Propellant loading density (Density of propellant + volume lost due to packing density) -- HE - ACF.HEPower = 8000 --HE Filler power per KG in KJ - ACF.HEDensity = 1.65 --HE Filler density (That's TNT density) - ACF.HEFrag = 1000 --Mean fragment number for equal weight TNT and casing - ACF.HEBlastPen = 0.4 --Blast penetration exponent based of HE power - ACF.HEFeatherExp = 0.5 --exponent applied to HE dist/maxdist feathering, <1 will increasingly bias toward max damage until sharp falloff at outer edge of range - ACF.HEATMVScale = 0.75 --Filler KE to HEAT slug KE conversion expotential - ACF.HEATMulAmmo = 30 --HEAT slug damage multiplier; 13.2x roughly equal to AP damage - ACF.HEATMulFuel = 4 --needs less multiplier, much less health than ammo - ACF.HEATMulEngine = 10 --likewise - ACF.HEATPenLayerMul = 0.75 --HEAT base energy multiplier - ACF.HEATBoomConvert = 1 / 3 -- percentage of filler that creates HE damage at detonation - ACF.HEATMinCrush = 800 -- vel where crush starts, progressively converting round to raw HE - ACF.HEATMaxCrush = 1200 -- vel where fully crushed + ACF.HEPower = 8000 --HE Filler power per KG in KJ + ACF.HEDensity = 1.65 --HE Filler density (That's TNT density) + ACF.HEFrag = 1000 --Mean fragment number for equal weight TNT and casing + ACF.HEBlastPen = 0.4 --Blast penetration exponent based of HE power + ACF.HEFeatherExp = 0.5 --exponent applied to HE dist/maxdist feathering, <1 will increasingly bias toward max damage until sharp falloff at outer edge of range + ACF.HEATMVScale = 0.75 --Filler KE to HEAT slug KE conversion expotential + ACF.HEATMulAmmo = 30 --HEAT slug damage multiplier; 13.2x roughly equal to AP damage + ACF.HEATMulFuel = 4 --needs less multiplier, much less health than ammo + ACF.HEATMulEngine = 10 --likewise + ACF.HEATPenLayerMul = 0.75 --HEAT base energy multiplier + ACF.HEATBoomConvert = 1 / 3 -- percentage of filler that creates HE damage at detonation + ACF.HEATMinCrush = 800 -- vel where crush starts, progressively converting round to raw HE + ACF.HEATMaxCrush = 1200 -- vel where fully crushed -- Debris - ACF.ChildDebris = 50 -- higher is more debris props; Chance = ACF.ChildDebris / num_children; Only applies to children of acf-killed parent props - ACF.DebrisIgniteChance = 0.25 - ACF.DebrisScale = 999999 -- Ignore debris that is less than this bounding radius. - ACF.ValidDebris = { -- Whitelist for things that can be turned into debris + ACF.ChildDebris = 50 -- higher is more debris props; Chance = ACF.ChildDebris / num_children; Only applies to children of acf-killed parent props + ACF.DebrisIgniteChance = 0.25 + ACF.ValidDebris = { -- Whitelist for things that can be turned into debris acf_ammo = true, acf_gun = true, acf_gearbox = true, @@ -82,67 +86,26 @@ do -- ACF global vars } -- Weapon Accuracy - ACF.SpreadScale = 4 -- The maximum amount that damage can decrease a gun"s accuracy. Default 4x - ACF.GunInaccuracyScale = 0.5 -- A multiplier for gun accuracy. Must be between 0.5 and 4 - ACF.GunInaccuracyBias = 2 -- Higher numbers make shots more likely to be inaccurate. Choose between 0.5 to 4. Default is 2 (unbiased). + ACF.SpreadScale = 4 -- The maximum amount that damage can decrease a gun"s accuracy. Default 4x + ACF.GunInaccuracyScale = 0.5 -- A multiplier for gun accuracy. Must be between 0.5 and 4 + ACF.GunInaccuracyBias = 2 -- Higher numbers make shots more likely to be inaccurate. Choose between 0.5 to 4. Default is 2 (unbiased). -- Fuel - ACF.FuelRate = 1 --multiplier for fuel usage, 1.0 is approx real world - ACF.CompFuelRate = 27.8 --Extra multiplier for fuel consumption on servers with acf_gamemode set to 2 (Competitive) - ACF.TankVolumeMul = 1 -- multiplier for fuel tank capacity, 1.0 is approx real world - ACF.LiIonED = 0.458 -- li-ion energy density: kw hours / liter - ACF.CuIToLiter = 0.0163871 -- cubic inches to liters - ACF.RefillDistance = 300 --Distance in which ammo crate starts refilling. - ACF.RefillSpeed = 700 -- (ACF.RefillSpeed / RoundMass) / Distance - ACF.RefuelSpeed = 20 -- Liters per second * ACF.FuelRate + ACF.FuelRate = 1 --multiplier for fuel usage, 1.0 is approx real world + ACF.FuelFactor = 1 -- Multiplier for ACF.FuelRate + ACF.CompFuelRate = 27.8 -- Extra multiplier for fuel consumption on servers with ACF Gamemode set to Competitive + ACF.CompFuelFactor = 1 -- Multiplier for ACF.CompFuelRate + ACF.TankVolumeMul = 1 -- multiplier for fuel tank capacity, 1.0 is approx real world + ACF.LiIonED = 0.458 -- li-ion energy density: kw hours / liter + ACF.CuIToLiter = 0.0163871 -- cubic inches to liters + ACF.RefillDistance = 300 --Distance in which ammo crate starts refilling. + ACF.RefillSpeed = 700 -- (ACF.RefillSpeed / RoundMass) / Distance + ACF.RefuelSpeed = 20 -- Liters per second * ACF.FuelRate end do -- ACF Convars/Callbacks ------------------------ CreateConVar("sbox_max_acf_ammo", 32, FCVAR_ARCHIVE + FCVAR_NOTIFY, "Maximum amount of ACF ammo crates a player can create.") - function ACF_CVarChangeCallback(CVar, _, New) - if CVar == "acf_healthmod" then - ACF.Threshold = 264.7 / math.max(New, 0.01) - print("Health Mod changed to a factor of " .. New) - elseif CVar == "acf_armormod" then - ACF.ArmorMod = 1 * math.max(New, 0) - print("Armor Mod changed to a factor of " .. New) - elseif CVar == "acf_ammomod" then - ACF.AmmoMod = 1 * math.max(New, 0.01) - print("Ammo Mod changed to a factor of " .. New) - elseif CVar == "acf_fuelrate" then - local Value = tonumber(New) or 1 - - ACF.FuelRate = math.max(Value, 0.01) - - print("Fuel Rate changed to a factor of " .. Value) - elseif CVar == "acf_gunfire" then - ACF.GunfireEnabled = tobool(New) - local text = "disabled" - - if ACF.GunfireEnabled then - text = "enabled" - end - - print("ACF Gunfire has been " .. text) - end - end - - -- New healthmod/armormod/ammomod cvars - CreateConVar("acf_healthmod", 1) - CreateConVar("acf_armormod", 1) - CreateConVar("acf_ammomod", 1) - CreateConVar("acf_fuelrate", 1) - CreateConVar("acf_spalling", 0) - CreateConVar("acf_gunfire", 1) - - cvars.AddChangeCallback("acf_healthmod", ACF_CVarChangeCallback) - cvars.AddChangeCallback("acf_armormod", ACF_CVarChangeCallback) - cvars.AddChangeCallback("acf_ammomod", ACF_CVarChangeCallback) - cvars.AddChangeCallback("acf_fuelrate", ACF_CVarChangeCallback) - cvars.AddChangeCallback("acf_spalling", ACF_CVarChangeCallback) - cvars.AddChangeCallback("acf_gunfire", ACF_CVarChangeCallback) - game.AddParticles("particles/acf_muzzleflashes.pcf") game.AddParticles("particles/explosion1.pcf") game.AddParticles("particles/rocket_motor.pcf") diff --git a/lua/acf/base/sv_validation.lua b/lua/acf/base/sv_validation.lua index 69e828755..ea8a7db16 100644 --- a/lua/acf/base/sv_validation.lua +++ b/lua/acf/base/sv_validation.lua @@ -2,7 +2,6 @@ -- Local Vars ----------------------------------- local ACF = ACF -local Gamemode = GetConVar("acf_gamemode") local StringFind = string.find local TimerSimple = timer.Simple local Baddies = ACF.GlobalFilter @@ -24,7 +23,7 @@ local Baddies = ACF.GlobalFilter end ]]-- local function IsLegal(Entity) - if Gamemode:GetInt() == 0 then return true end -- Gamemode is set to Sandbox, legal checks don't apply + if ACF.Gamemode == 1 then return true end -- Gamemode is set to Sandbox, legal checks don't apply local Phys = Entity:GetPhysicsObject() @@ -99,7 +98,7 @@ local function CheckLegal(Entity) return false end - if Gamemode:GetInt() ~= 0 then + if ACF.Gamemode ~= 1 then TimerSimple(math.Rand(1, 3), function() -- Entity is legal... test again in random 1 to 3 seconds if IsValid(Entity) then CheckLegal(Entity) diff --git a/lua/acf/client/menu_items/settings_menu.lua b/lua/acf/client/menu_items/settings_menu.lua index d2d9753b3..ad56d5852 100644 --- a/lua/acf/client/menu_items/settings_menu.lua +++ b/lua/acf/client/menu_items/settings_menu.lua @@ -10,17 +10,7 @@ do -- Clientside settings ACF.AddMenuItem(1, "Settings", "Clientside Settings", "user", ACF.GenerateClientSettings) - ACF.AddClientSettings("Effects and Visual Elements", function(Base) - local Ropes = Base:AddCheckBox("Create mobility rope links.") - Ropes:SetConVar("acf_mobilityropelinks") - - local Particles = Base:AddSlider("Particle Mult.", 0.1, 1, 2) - Particles:SetConVar("acf_cl_particlemul") - - Base:AddHelp("Defines the clientside particle multiplier, reduce it if you're experiencing lag when ACF effects are created.") - end) - - ACF.AddClientSettings("Entity Information", function(Base) + ACF.AddClientSettings(1, "Entity Information", function(Base) local InfoValue = InfoHelp[Ent_Info:GetInt()] and Ent_Info:GetInt() or 1 Base:AddLabel("Display ACF entity information:") @@ -57,19 +47,22 @@ do -- Clientside settings Base:AddHelp("Requires hitboxes to be enabled.") end) - ACF.AddClientSettings("Legal Checks", function(Base) - local Hints = Base:AddCheckBox("Enable hints on entity disabling.") - Hints:SetConVar("acf_legalhints") - end) + ACF.AddClientSettings(101, "Effects and Visual Elements", function(Base) + local Ropes = Base:AddCheckBox("Create mobility rope links.") + Ropes:SetConVar("acf_mobilityropelinks") - ACF.AddClientSettings("Tool Category", function(Base) - local Category = Base:AddCheckBox("Use custom category for ACF tools.") - Category:SetConVar("acf_tool_category") + local Particles = Base:AddSlider("Particle Mult.", 0.1, 1, 2) + Particles:SetConVar("acf_cl_particlemul") - Base:AddHelp("You will need to rejoin the server for this option to apply.") + Base:AddHelp("Defines the clientside particle multiplier, reduce it if you're experiencing lag when ACF effects are created.") + end) + + ACF.AddClientSettings(201, "Legal Checks", function(Base) + local Hints = Base:AddCheckBox("Enable hints on entity disabling.") + Hints:SetConVar("acf_legalhints") end) - ACF.AddClientSettings("Debris", function(Base) + ACF.AddClientSettings(301, "Debris", function(Base) local Debris = Base:AddCheckBox("Allow creation of clientside debris.") Debris:SetConVar("acf_debris") @@ -93,12 +86,82 @@ do -- Clientside settings Base:AddHelp("Defines how long each debris gib will live before fading out.") end) + + ACF.AddClientSettings(401, "Tool Category", function(Base) + local Category = Base:AddCheckBox("Use custom category for ACF tools.") + Category:SetConVar("acf_tool_category") + + Base:AddHelp("You will need to rejoin the server for this option to apply.") + end) end do -- Serverside settings ACF.AddMenuItem(101, "Settings", "Serverside Settings", "server", ACF.GenerateServerSettings) - ACF.AddServerSettings("Fun Entities and Menu", function(Base) + ACF.AddServerSettings(1, "General Settings", function(Base) + Base:AddLabel("ACF Gamemode for this server:") + + local Gamemode = Base:AddComboBox() + Gamemode:AddChoice("Sandbox") + Gamemode:AddChoice("Classic") + Gamemode:AddChoice("Competitive") + Gamemode:SetServerData("Gamemode", "OnSelect") + Gamemode:DefineSetter(function(Panel, _, _, Value) + if Panel.selected == Value then return end -- God bless derma + + Panel:ChooseOptionID(Value) + + return Value + end) + + Base:AddHelp("Each gamemode has its own restrictions, Sandbox being the most relaxed and Competitive the most strict.") + + local Admins = Base:AddCheckBox("Allow admins to control server data.") + Admins:SetServerData("ServerDataAllowAdmin", "OnChange") + Admins:DefineSetter(function(Panel, _, _, Value) + Panel:SetValue(Value) + + return Value + end) + + Base:AddHelp("If enabled, admins will be able to mess with the settings on this panel.") + + local Gunfire = Base:AddCheckBox("Allow weapons to be fired.") + Gunfire:SetServerData("GunfireEnabled", "OnChange") + Gunfire:DefineSetter(function(Panel, _, _, Value) + Panel:SetValue(Value) + + return Value + end) + + local Health = Base:AddSlider("Health Factor", 0.01, 2, 2) + Health:SetServerData("HealthFactor", "OnValueChanged") + Health:DefineSetter(function(Panel, _, _, Value) + Panel:SetValue(Value) + + return Value + end) + + local Fuel = Base:AddSlider("Fuel Factor", 0.01, 2, 2) + Fuel:SetServerData("FuelFactor", "OnValueChanged") + Fuel:DefineSetter(function(Panel, _, _, Value) + Panel:SetValue(Value) + + return Value + end) + + local CompFuel = Base:AddSlider("Competitive Fuel Factor", 0.01, 2, 2) + CompFuel:SetServerData("CompFuelFactor", "OnValueChanged") + CompFuel:DefineSetter(function(Panel, _, _, Value) + Panel:SetValue(Value) + + return Value + end) + + Base:AddHelp("Only applies to servers with their ACF Gamemode set to Competitive.") + end) + + ACF.AddServerSettings(101, "Fun Entities and Menu", function(Base) local Entities = Base:AddCheckBox("Allow use of Fun Entities.") Entities:SetServerData("AllowFunEnts", "OnChange") Entities:DefineSetter(function(Panel, _, _, Value) @@ -120,7 +183,7 @@ do -- Serverside settings Base:AddHelp("Changes on this option will only take effect once the players reload their menu.") end) - ACF.AddServerSettings("Custom Killicons", function(Base) + ACF.AddServerSettings(201, "Custom Killicons", function(Base) local Icons = Base:AddCheckBox("Use custom killicons for ACF entities.") Icons:SetServerData("UseKillicons", "OnChange") Icons:DefineSetter(function(Panel, _, _, Value) @@ -132,7 +195,7 @@ do -- Serverside settings Base:AddHelp("Changing this option will require a server restart.") end) - ACF.AddServerSettings("Debris", function(Base) + ACF.AddServerSettings(301, "Debris", function(Base) local Debris = Base:AddCheckBox("Allow networking of debris to clients.") Debris:SetServerData("CreateDebris", "OnChange") Debris:DefineSetter(function(Panel, _, _, Value) @@ -162,11 +225,3 @@ do -- Serverside settings Base:AddHelp("Multiplier for the amount of serverside fireballs to be created.") end) end - --- TODO --- Replace acf_healthmod and ACF.Threshold --- Replace acf_armormod and ACF.ArmorMod --- Replace or deprecate acf_ammomod and ACF.AmmoMod --- Replace acf_fuelrate and ACF.FuelRate --- Replace acf_spalling --- Replace acf_gunfire and ACF.GunfireEnabled diff --git a/lua/acf/client/spawn_menu.lua b/lua/acf/client/spawn_menu.lua index 2c4596714..b19b622f6 100644 --- a/lua/acf/client/spawn_menu.lua +++ b/lua/acf/client/spawn_menu.lua @@ -229,23 +229,26 @@ do -- Client and server settings local Settings = ACF.SettingsPanels --- Generates the following functions: - -- ACF.AddClientSettings(Name, Function) + -- ACF.AddClientSettings(Index, Name, Function) -- ACF.RemoveClientSettings(Name) -- ACF.GenerateClientSettings(MenuPanel) - -- ACF.AddServerSettings(Name, Function) + -- ACF.AddServerSettings(Index, Name, Function) -- ACF.RemoveServerSettings(Name) -- ACF.GenerateServerSettings(MenuPanel) - for Realm in pairs(Settings) do - local Destiny = Settings[Realm] + for Realm, Destiny in pairs(Settings) do local Hook = "ACF_On" .. Realm .. "SettingsLoaded" local Message = "No %sside settings have been registered." - ACF["Add" .. Realm .. "Settings"] = function(Name, Function) + ACF["Add" .. Realm .. "Settings"] = function(Index, Name, Function) + if not isnumber(Index) then return end if not isstring(Name) then return end if not isfunction(Function) then return end - Destiny[Name] = Function + Destiny[Name] = { + Create = Function, + Index = Index, + } end ACF["Remove" .. Realm .. "Settings"] = function(Name) @@ -263,10 +266,10 @@ do -- Client and server settings return end - for Name, Function in SortedPairs(Destiny) do + for Name, Data in SortedPairsByMemberValue(Destiny, "Index") do local Base = Menu:AddCollapsible(Name) - Function(Base) + Data.Create(Base) hook.Run(Hook, Name, Base) end diff --git a/lua/acf/server/persisted_vars.lua b/lua/acf/server/persisted_vars.lua index 679996b79..dcc0cc289 100644 --- a/lua/acf/server/persisted_vars.lua +++ b/lua/acf/server/persisted_vars.lua @@ -1,7 +1,13 @@ -- Variables that should be persisted between server restarts +-- Settings +ACF.PersistServerData("Gamemode", 2) ACF.PersistServerData("ServerDataAllowAdmin", false) ACF.PersistServerData("GunfireEnabled", true) +ACF.PersistServerData("HealthFactor", 1) +ACF.PersistServerData("ArmorFactor", 1) +ACF.PersistServerData("FuelFactor", 1) +ACF.PersistServerData("CompFuelFactor", 1) ACF.PersistServerData("AllowFunEnts", true) ACF.PersistServerData("UseKillicons", true) ACF.PersistServerData("ShowFunMenu", true) diff --git a/lua/acf/shared/data_callbacks.lua b/lua/acf/shared/data_callbacks.lua new file mode 100644 index 000000000..7441266c1 --- /dev/null +++ b/lua/acf/shared/data_callbacks.lua @@ -0,0 +1,90 @@ +local ACF = ACF + +local Names = { + [1] = "Sandbox", + [2] = "Classic", + [3] = "Competitive" +} + +local Settings = { + Gamemode = function(_, _, Value) + local Mode = math.Clamp(math.floor(tonumber(Value) or 2), 1, 3) + + if Mode == ACF.Gamemode then return end + + ACF.Gamemode = Mode + + print("ACF Gamemode has been changed to " .. Names[Mode]) + end, + ServerDataAllowAdmin = function(_, _, Value) + local Bool = tobool(Value) + + ACF.AllowAdminData = Bool + end, + GunfireEnabled = function(_, _, Value) + local Bool = tobool(Value) + + if ACF.GunfireEnabled == Bool then return end + + ACF.GunfireEnabled = Bool + + print("ACF Gunfire has been " .. (Bool and "enabled." or "disabled.")) + end, + HealthFactor = function(_, _, Value) + local Factor = math.Clamp(math.Round(tonumber(Value) or 1, 2), 0.01, 2) + + if ACF.HealthFactor == Factor then return end + + local Old = ACF.HealthFactor + + ACF.HealthFactor = Factor + ACF.Threshold = ACF.Threshold / Old * Factor + + print("ACF Health Mod changed to a factor of " .. Factor) + end, + ArmorFactor = function(_, _, Value) + local Factor = math.Clamp(math.Round(tonumber(Value) or 1, 2), 0.01, 2) + + if ACF.ArmorFactor == Factor then return end + + local Old = ACF.ArmorFactor + + ACF.ArmorFactor = Factor + ACF.ArmorMod = ACF.ArmorMod / Old * Factor + + print("ACF Armor Mod changed to a factor of " .. Factor) + end, + FuelFactor = function(_, _, Value) + local Factor = math.Clamp(math.Round(tonumber(Value) or 1, 2), 0.01, 2) + + if ACF.FuelFactor == Factor then return end + + local Old = ACF.FuelFactor + + ACF.FuelFactor = Factor + ACF.FuelRate = ACF.FuelRate / Old * Factor + + print("ACF Fuel Rate changed to a factor of " .. Factor) + end, + CompFuelFactor = function(_, _, Value) + local Factor = math.Clamp(math.Round(tonumber(Value) or 1, 2), 0.01, 2) + + if ACF.CompFuelFactor == Factor then return end + + local Old = ACF.CompFuelFactor + + ACF.CompFuelFactor = Factor + ACF.CompFuelRate = ACF.CompFuelRate / Old * Factor + + print("ACF Competitive Fuel Rate changed to a factor of " .. Factor) + end, + AllowFunEnts = function(_, _, Value) + local Bool = tobool(Value) + + ACF.AllowFunEnts = Bool + end, +} + +for Key, Function in pairs(Settings) do + ACF.AddServerDataCallback(Key, "Global Variable Callback", Function) +end diff --git a/lua/entities/acf_engine/init.lua b/lua/entities/acf_engine/init.lua index 04daf62a5..b120af372 100644 --- a/lua/entities/acf_engine/init.lua +++ b/lua/entities/acf_engine/init.lua @@ -111,11 +111,10 @@ local TimerCreate = timer.Create local TimerSimple = timer.Simple local TimerRemove = timer.Remove local HookRun = hook.Run -local Gamemode = GetConVar("acf_gamemode") -- Fuel consumption is increased on competitive servers local function GetEfficiencyMult() - return Gamemode:GetInt() == 2 and ACF.CompFuelRate or 1 + return ACF.Gamemode == 3 and ACF.CompFuelRate or 1 end local function GetPitchVolume(Engine) @@ -639,7 +638,7 @@ function ENT:CalcRPM() self.FuelUsage = 60 * Consumption / DeltaTime FuelTank:Consume(Consumption) - elseif Gamemode:GetInt() ~= 0 then -- Sandbox gamemode servers will require no fuel + elseif ACF.Gamemode ~= 1 then -- Sandbox gamemode servers will require no fuel SetActive(self, false) self.FuelUsage = 0 diff --git a/lua/entities/acf_piledriver/init.lua b/lua/entities/acf_piledriver/init.lua index 1023aeb1a..b78182cbb 100644 --- a/lua/entities/acf_piledriver/init.lua +++ b/lua/entities/acf_piledriver/init.lua @@ -341,8 +341,8 @@ do -- Firing ------------------------------------ -- The entity should produce a "click" sound if this function returns false function ENT:CanShoot() - if not ACF.GetServerBool("GunfireEnabled") then return false end - if not ACF.GetServerBool("AllowFunEnts") then return false end + if not ACF.GunfireEnabled then return false end + if not ACF.AllowFunEnts then return false end if hook.Run("ACF_FireShell", self) == false then return false end return self.CurrentShot > 0 From fab28037cd9df6402fead45ac06b7d4da97abaf8 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Sun, 17 Jan 2021 22:35:01 -0300 Subject: [PATCH 270/279] Updated fuel consumption on engines menu - Engine menu will now show the correct fuel consumption values if the server is set to competitive mode. - Fuel type's ConsumptionText function will now receive the real Efficiency value as the third argument, the other two were just moved as fourth and fifth arguments. --- lua/acf/client/menu_items/engines_menu.lua | 70 +++++++++++++--------- lua/acf/shared/fuel_types/electric.lua | 6 +- 2 files changed, 44 insertions(+), 32 deletions(-) diff --git a/lua/acf/client/menu_items/engines_menu.lua b/lua/acf/client/menu_items/engines_menu.lua index 0e48445ab..7a8b3fe5e 100644 --- a/lua/acf/client/menu_items/engines_menu.lua +++ b/lua/acf/client/menu_items/engines_menu.lua @@ -1,18 +1,41 @@ -local ACF = ACF +local ACF = ACF local EngineTypes = ACF.Classes.EngineTypes -local FuelTypes = ACF.Classes.FuelTypes -local FuelTanks = ACF.Classes.FuelTanks -local Engines = ACF.Classes.Engines +local FuelTypes = ACF.Classes.FuelTypes +local FuelTanks = ACF.Classes.FuelTanks +local Engines = ACF.Classes.Engines +local RPMText = [[ + Idle RPM : %s RPM + Powerband : %s-%s RPM + Redline : %s RPM + Mass : %s + + This entity can be fully parented. + %s + %s]] +local PowerText = [[ + Peak Torque : %s n/m - %s ft-lb + Peak Power : %s kW - %s HP @ %s RPM]] +local ConsumptionText = [[ + %s Consumption : + %s L/min - %s gal/min @ %s RPM]] + +-- Fuel consumption is increased on competitive servers +local function GetEfficiencyMult() + return ACF.Gamemode == 3 and ACF.CompFuelRate or 1 +end local function UpdateEngineStats(Label, Data) - local RPM = Data.RPM - local PeakkW = Data.Torque * RPM.PeakMax / 9548.8 - local PeakkWRPM = RPM.PeakMax - local MinPower = RPM.PeakMin - local MaxPower = RPM.PeakMax - - local RPMText = "Idle RPM : %s RPM\nPowerband : %s-%s RPM\nRedline : %s RPM\nMass : %s\n\nThis entity can be fully parented." - local LabelText = "" + local RPM = Data.RPM + local PeakkW = Data.Torque * RPM.PeakMax / 9548.8 + local PeakkWRPM = RPM.PeakMax + local MinPower = RPM.PeakMin + local MaxPower = RPM.PeakMax + local Mass = ACF.GetProperMass(Data.Mass) + local Torque = math.floor(Data.Torque) + local TorqueFeet = math.floor(Data.Torque * 0.73) + local Type = EngineTypes[Data.Type] + local Efficiency = Type.Efficiency * GetEfficiencyMult() + local FuelList = "" -- Electric motors and turbines get peak power in middle of rpm range if Data.IsElectric then @@ -22,39 +45,28 @@ local function UpdateEngineStats(Label, Data) MaxPower = PeakkWRPM end - LabelText = LabelText .. RPMText:format(RPM.Idle, MinPower, MaxPower, RPM.Limit, ACF.GetProperMass(Data.Mass)) - - local TorqueText = "\nPeak Torque : %s n/m - %s ft-lb" - local PowerText = "\nPeak Power : %s kW - %s HP @ %s RPM" - local Consumption, Power = "", "" - for K in pairs(Data.Fuel) do if not FuelTypes[K] then continue end - local Type = EngineTypes[Data.Type] local Fuel = FuelTypes[K] local AddText = "" if Fuel.ConsumptionText then - AddText = Fuel.ConsumptionText(PeakkW, PeakkWRPM, Type, Fuel) + AddText = Fuel.ConsumptionText(PeakkW, PeakkWRPM, Efficiency, Type, Fuel) else - local Text = "\n\n%s Consumption :\n%s L/min - %s gal/min @ %s RPM" - local Rate = ACF.FuelRate * Type.Efficiency * PeakkW / (60 * Fuel.Density) + local Rate = ACF.FuelRate * Efficiency * PeakkW / (60 * Fuel.Density) - AddText = Text:format(Fuel.Name, math.Round(Rate, 2), math.Round(Rate * 0.264, 2), PeakkWRPM) + AddText = ConsumptionText:format(Fuel.Name, math.Round(Rate, 2), math.Round(Rate * 0.264, 2), PeakkWRPM) end - Consumption = Consumption .. AddText + FuelList = FuelList .. "\n" .. AddText .. "\n" Data.Fuel[K] = Fuel -- TODO: Replace once engines use the proper class functions end - Power = Power .. "\n" .. PowerText:format(math.floor(PeakkW), math.floor(PeakkW * 1.34), PeakkWRPM) - Power = Power .. TorqueText:format(math.floor(Data.Torque), math.floor(Data.Torque * 0.73)) - - LabelText = LabelText .. Consumption .. Power + local Power = PowerText:format(Torque, TorqueFeet, math.floor(PeakkW), math.floor(PeakkW * 1.34), PeakkWRPM) - Label:SetText(LabelText) + Label:SetText(RPMText:format(RPM.Idle, MinPower, MaxPower, RPM.Limit, Mass, FuelList, Power)) end local function CreateMenu(Menu) diff --git a/lua/acf/shared/fuel_types/electric.lua b/lua/acf/shared/fuel_types/electric.lua index 7f7185603..527a0dbbe 100644 --- a/lua/acf/shared/fuel_types/electric.lua +++ b/lua/acf/shared/fuel_types/electric.lua @@ -1,9 +1,9 @@ ACF.RegisterFuelType("Electric", { Name = "Lit-Ion Battery", Density = 3.89, - ConsumptionText = function(PeakkW, _, TypeData) - local Text = "\n\nPeak Energy Consumption :\n%s kW - %s MJ/min" - local Rate = ACF.FuelRate * PeakkW / TypeData.Efficiency + ConsumptionText = function(PeakkW, _, Efficiency) + local Text = "Peak Energy Consumption :\n%s kW - %s MJ/min" + local Rate = ACF.FuelRate * PeakkW / Efficiency return Text:format(math.Round(Rate, 2), math.Round(Rate * 0.06, 2)) end, From 3238061a99e125a39a71f17ab257b978644922cc Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Mon, 18 Jan 2021 00:27:22 -0300 Subject: [PATCH 271/279] Globalized ammo crate capacity calculation function - Globalized the function used to get the capacity of ammo crates. It's now available as the shared ACF.GetAmmoCrateCapacity function. --- lua/acf/base/sh_round_functions.lua | 176 +++++++++++++++++++++++++ lua/entities/acf_ammo/init.lua | 193 ++-------------------------- 2 files changed, 184 insertions(+), 185 deletions(-) diff --git a/lua/acf/base/sh_round_functions.lua b/lua/acf/base/sh_round_functions.lua index 94e91c342..1e9629ef5 100644 --- a/lua/acf/base/sh_round_functions.lua +++ b/lua/acf/base/sh_round_functions.lua @@ -148,3 +148,179 @@ function ACF.PenRanging(MuzzleVel, DragCoef, ProjMass, PenArea, LimitVel, Range) return math.Round(Vel * 0.0254, 2), math.Round(Pen, 2) end + +do -- Ammo crate capacity calculation + local Axises = { + x = { Y = "y", Z = "z", Ang = Angle() }, + y = { Y = "x", Z = "z", Ang = Angle(0, 90) }, + z = { Y = "x", Z = "y", Ang = Angle(90, 90) } + } + + local function GetBoxDimensions(Axis, Size) + local AxisInfo = Axises[Axis] + local Y = Size[AxisInfo.Y] + local Z = Size[AxisInfo.Z] + + return Size[Axis], Y, Z, AxisInfo.Ang + end + + local function GetRoundsPerAxis(SizeX, SizeY, SizeZ, Length, Width, Height, Spacing) + -- Omitting spacing for the axises with just one round + if math.floor(SizeX / Length) > 1 then Length = Length + Spacing end + if math.floor(SizeY / Width) > 1 then Width = Width + Spacing end + if math.floor(SizeZ / Height) > 1 then Height = Height + Spacing end + + local RoundsX = math.floor(SizeX / Length) + local RoundsY = math.floor(SizeY / Width) + local RoundsZ = math.floor(SizeZ / Height) + + return RoundsX, RoundsY, RoundsZ + end + + -- Split this off from the original function, + -- All this does is compare a distance against a table of distances with string indexes for the shortest fitting size + -- It returns the string index of the dimension, or nil if it fails to fit + local function ShortestSize(Length, Width, Height, Spacing, Dimensions, ExtraData, IsIrregular) + local BestCount = 0 + local BestAxis + + for Axis in pairs(Axises) do + local X, Y, Z = GetBoxDimensions(Axis, Dimensions) + local Multiplier = 1 + + if not IsIrregular then + local MagSize = ExtraData.MagSize + + if MagSize and MagSize > 0 then + Multiplier = MagSize + end + end + + local RoundsX, RoundsY, RoundsZ = GetRoundsPerAxis(X, Y, Z, Length, Width, Height, Spacing) + local Count = RoundsX * RoundsY * RoundsZ * Multiplier + + if Count > BestCount then + BestAxis = Axis + BestCount = Count + end + end + + return BestAxis, BestCount + end + + -- BoxSize is just OBBMaxs-OBBMins + -- Removed caliber and round length inputs, uses GunData and BulletData now + -- AddSpacing is just extra spacing (directly reduces storage, but can later make it harder to detonate) + -- AddArmor is literally just extra armor on the ammo crate, but inside (also directly reduces storage) + -- For missiles/bombs, they MUST have ActualLength and ActualWidth (of the model in cm, and in the round table) to use this, otherwise it will fall back to the original calculations + -- Made by LiddulBOFH :) + function ACF.CalculateCrateCapacity(BoxSize, GunData, BulletData, AddSpacing, AddArmor) + -- gives a nice number of rounds per refill box + if BulletData.Type == "Refill" then return math.ceil(BoxSize.x * BoxSize.y * BoxSize.z * 0.01) end + + local GunCaliber = GunData.Caliber * 0.1 -- mm to cm + local RoundCaliber = GunCaliber * ACF.AmmoCaseScale + local RoundLength = BulletData.PropLength + BulletData.ProjLength + (BulletData.Tracer or 0) + local ExtraData = {} + + -- Filters for missiles, and sets up data + if GunData.Round.ActualWidth then + RoundCaliber = GunData.Round.ActualWidth + RoundLength = GunData.Round.ActualLength + ExtraData.IsRacked = true + elseif GunData.Class.Entity == "acf_rack" then + local Efficiency = 0.1576 * ACF.AmmoMod + local Volume = math.floor(BoxSize.x * BoxSize.y * BoxSize.z) * Efficiency + local CapMul = (Volume > 40250) and ((math.log(Volume * 0.00066) / math.log(2) - 4) * 0.15 + 1) or 1 + + return math.floor(CapMul * Volume * 16.38 / BulletData.RoundVolume) -- Fallback to old capacity + end + + local Rounds = 0 + local Spacing = math.max(AddSpacing, 0) + 0.125 + local MagSize = GunData.MagSize or 1 + local IsBoxed = GunData.Class.IsBoxed + local Rotate + + -- Converting everything to source units + local Length = RoundLength * 0.3937 -- cm to inches + local Width = RoundCaliber * 0.3937 -- cm to inches + local Height = Width + + ExtraData.Spacing = Spacing + + -- This block alters the stored round size, making it more like a container of the rounds + -- This cuts a little bit of ammo storage out + if MagSize > 1 then + if IsBoxed and not ExtraData.IsRacked then + -- Makes certain automatic ammo stored by boxes + Width = Width * math.sqrt(MagSize) + Height = Width + + ExtraData.MagSize = MagSize + ExtraData.IsBoxed = true + else + MagSize = 1 + end + end + + if AddArmor then + -- Converting millimeters to inches then multiplying by two since the armor is on both sides + local BoxArmor = AddArmor * 0.039 * 2 + local X = math.max(BoxSize.x - BoxArmor, 0) + local Y = math.max(BoxSize.y - BoxArmor, 0) + local Z = math.max(BoxSize.z - BoxArmor, 0) + + BoxSize = Vector(X, Y, Z) + end + + local ShortestFit = ShortestSize(Length, Width, Height, Spacing, BoxSize, ExtraData) + + -- If ShortestFit is nil, that means the round isn't able to fit at all in the box + -- If its a racked munition that doesn't fit, it will go ahead and try to fit 2-pice + -- Otherwise, checks if the caliber is over 100mm before trying 2-piece ammunition + -- It will flatout not do anything if its boxed and not fitting + if not ShortestFit and not ExtraData.IsBoxed and (GunCaliber >= 10 or ExtraData.IsRacked) then + Length = Length * 0.5 -- Not exactly accurate, but cuts the round in two + Width = Width * 2 -- two pieces wide + + ExtraData.IsTwoPiece = true + + local ShortestFit1, Count1 = ShortestSize(Length, Width, Height, Spacing, BoxSize, ExtraData, true) + local ShortestFit2, Count2 = ShortestSize(Length, Height, Width, Spacing, BoxSize, ExtraData, true) + + if Count1 > Count2 then + ShortestFit = ShortestFit1 + else + ShortestFit = ShortestFit2 + Rotate = true + end + end + + -- If it still doesn't fit the box, then it's just too small + if ShortestFit then + local SizeX, SizeY, SizeZ, LocalAng = GetBoxDimensions(ShortestFit, BoxSize) + + ExtraData.LocalAng = LocalAng + ExtraData.RoundSize = Vector(Length, Width, Height) + + -- In case the round was cut and needs to be rotated, then we do some minor changes + if Rotate then + local OldY = SizeY + + SizeY = SizeZ + SizeZ = OldY + + ExtraData.LocalAng = ExtraData.LocalAng + Angle(0, 0, 90) + end + + local RoundsX, RoundsY, RoundsZ = GetRoundsPerAxis(SizeX, SizeY, SizeZ, Length, Width, Height, Spacing) + + ExtraData.FitPerAxis = Vector(RoundsX, RoundsY, RoundsZ) + + Rounds = RoundsX * RoundsY * RoundsZ * MagSize + end + + return Rounds, ExtraData + end +end \ No newline at end of file diff --git a/lua/entities/acf_ammo/init.lua b/lua/entities/acf_ammo/init.lua index 3d15b3dcd..89999ab65 100644 --- a/lua/entities/acf_ammo/init.lua +++ b/lua/entities/acf_ammo/init.lua @@ -12,179 +12,11 @@ local HookRun = hook.Run do -- Spawning and Updating -------------------- local CheckLegal = ACF_CheckLegal - local Axises = { - x = { Y = "y", Z = "z", Ang = Angle() }, - y = { Y = "x", Z = "z", Ang = Angle(0, 90) }, - z = { Y = "x", Z = "y", Ang = Angle(90, 90) } - } - - local function GetBoxDimensions(Axis, Size) - local AxisInfo = Axises[Axis] - local Y = Size[AxisInfo.Y] - local Z = Size[AxisInfo.Z] - - return Size[Axis], Y, Z, AxisInfo.Ang - end - - local function GetRoundsPerAxis(SizeX, SizeY, SizeZ, Length, Width, Height, Spacing) - -- Omitting spacing for the axises with just one round - if math.floor(SizeX / Length) > 1 then Length = Length + Spacing end - if math.floor(SizeY / Width) > 1 then Width = Width + Spacing end - if math.floor(SizeZ / Height) > 1 then Height = Height + Spacing end - - local RoundsX = math.floor(SizeX / Length) - local RoundsY = math.floor(SizeY / Width) - local RoundsZ = math.floor(SizeZ / Height) - - return RoundsX, RoundsY, RoundsZ - end - - -- Split this off from the original function, - -- All this does is compare a distance against a table of distances with string indexes for the shortest fitting size - -- It returns the string index of the dimension, or nil if it fails to fit - local function ShortestSize(Length, Width, Height, Spacing, Dimensions, ExtraData, IsIrregular) - local BestCount = 0 - local BestAxis - - for Axis in pairs(Axises) do - local X, Y, Z = GetBoxDimensions(Axis, Dimensions) - local Multiplier = 1 - - if not IsIrregular then - local MagSize = ExtraData.MagSize - - if MagSize and MagSize > 0 then - Multiplier = MagSize - end - end - - local RoundsX, RoundsY, RoundsZ = GetRoundsPerAxis(X, Y, Z, Length, Width, Height, Spacing) - local Count = RoundsX * RoundsY * RoundsZ * Multiplier - - if Count > BestCount then - BestAxis = Axis - BestCount = Count - end - end - - return BestAxis, BestCount - end - - -- BoxSize is just OBBMaxs-OBBMins - -- Removed caliber and round length inputs, uses GunData and BulletData now - -- AddSpacing is just extra spacing (directly reduces storage, but can later make it harder to detonate) - -- AddArmor is literally just extra armor on the ammo crate, but inside (also directly reduces storage) - -- For missiles/bombs, they MUST have ActualLength and ActualWidth (of the model in cm, and in the round table) to use this, otherwise it will fall back to the original calculations - -- Made by LiddulBOFH :) - local function CalcAmmo(BoxSize, GunData, BulletData, AddSpacing, AddArmor) - -- gives a nice number of rounds per refill box - if BulletData.Type == "Refill" then return math.ceil(BoxSize.x * BoxSize.y * BoxSize.z * 0.01) end - - local GunCaliber = GunData.Caliber * 0.1 -- mm to cm - local RoundCaliber = GunCaliber * ACF.AmmoCaseScale - local RoundLength = BulletData.PropLength + BulletData.ProjLength + (BulletData.Tracer or 0) - - local ExtraData = {} - - -- Filters for missiles, and sets up data - if GunData.Round.ActualWidth then - RoundCaliber = GunData.Round.ActualWidth - RoundLength = GunData.Round.ActualLength - ExtraData.isRacked = true - elseif GunData.Class.Entity == "acf_rack" then return -1 end -- Fallback to old capacity - - local Rounds = 0 - local Spacing = math.max(AddSpacing, 0) + 0.125 - local MagSize = GunData.MagSize or 1 - local IsBoxed = GunData.Class.IsBoxed - local Rotate - - -- Converting everything to source units - local Length = RoundLength * 0.3937 -- cm to inches - local Width = RoundCaliber * 0.3937 -- cm to inches - local Height = Width - - ExtraData.Spacing = Spacing - - -- This block alters the stored round size, making it more like a container of the rounds - -- This cuts a little bit of ammo storage out - if MagSize > 1 then - if IsBoxed and not ExtraData.isRacked then - -- Makes certain automatic ammo stored by boxes - Width = Width * math.sqrt(MagSize) - Height = Width - - ExtraData.MagSize = MagSize - ExtraData.isBoxed = true - else - MagSize = 1 - end - end - - if AddArmor then - -- Converting millimeters to inches then multiplying by two since the armor is on both sides - local BoxArmor = AddArmor * 0.039 * 2 - local X = math.max(BoxSize.x - BoxArmor, 0) - local Y = math.max(BoxSize.y - BoxArmor, 0) - local Z = math.max(BoxSize.z - BoxArmor, 0) - - BoxSize = Vector(X, Y, Z) - end - - local ShortestFit = ShortestSize(Length, Width, Height, Spacing, BoxSize, ExtraData) - - -- If ShortestFit is nil, that means the round isn't able to fit at all in the box - -- If its a racked munition that doesn't fit, it will go ahead and try to fit 2-pice - -- Otherwise, checks if the caliber is over 100mm before trying 2-piece ammunition - -- It will flatout not do anything if its boxed and not fitting - if not ShortestFit and not ExtraData.isBoxed and (GunCaliber >= 10 or ExtraData.isRacked) then - Length = Length * 0.5 -- Not exactly accurate, but cuts the round in two - Width = Width * 2 -- two pieces wide - - ExtraData.isTwoPiece = true - - local ShortestFit1, Count1 = ShortestSize(Length, Width, Height, Spacing, BoxSize, ExtraData, true) - local ShortestFit2, Count2 = ShortestSize(Length, Height, Width, Spacing, BoxSize, ExtraData, true) - - if Count1 > Count2 then - ShortestFit = ShortestFit1 - else - ShortestFit = ShortestFit2 - Rotate = true - end - end - - -- If it still doesn't fit the box, then it's just too small - if ShortestFit then - local SizeX, SizeY, SizeZ, LocalAng = GetBoxDimensions(ShortestFit, BoxSize) - - ExtraData.LocalAng = LocalAng - ExtraData.RoundSize = Vector(Length, Width, Height) - - -- In case the round was cut and needs to be rotated, then we do some minor changes - if Rotate then - local OldY = SizeY - - SizeY = SizeZ - SizeZ = OldY - - ExtraData.LocalAng = ExtraData.LocalAng + Angle(0, 0, 90) - end - - local RoundsX, RoundsY, RoundsZ = GetRoundsPerAxis(SizeX, SizeY, SizeZ, Length, Width, Height, Spacing) - - ExtraData.FitPerAxis = Vector(RoundsX, RoundsY, RoundsZ) - - Rounds = RoundsX * RoundsY * RoundsZ * MagSize - end - - return Rounds, ExtraData - end - local Classes = ACF.Classes local Crates = Classes.Crates local AmmoTypes = Classes.AmmoTypes local GetClassGroup = ACF.GetClassGroup + local Updated = { ["20mmHRAC"] = "20mmRAC", ["30mmHRAC"] = "30mmRAC", @@ -304,21 +136,12 @@ do -- Spawning and Updating -------------------- do -- Ammo count calculation local Size = Entity:GetSize() local Spacing = Weapon.Caliber * 0.0039 - local Rounds, ExtraData = CalcAmmo(Size, Weapon, Entity.BulletData, Spacing, ACF.AmmoArmor) + local Rounds, ExtraData = ACF.CalculateCrateCapacity(Size, Weapon, Entity.BulletData, Spacing, ACF.AmmoArmor) local Percentage = Entity.Capacity and Entity.Ammo / math.max(Entity.Capacity, 1) or 1 - if Rounds ~= -1 then - Entity.Capacity = Rounds - else - local Efficiency = 0.1576 * ACF.AmmoMod - local Volume = math.floor(Entity:GetPhysicsObject():GetVolume()) * Efficiency - local CapMul = (Volume > 40250) and ((math.log(Volume * 0.00066) / math.log(2) - 4) * 0.15 + 1) or 1 - - Entity.Capacity = math.floor(CapMul * Volume * 16.38 / Entity.BulletData.RoundVolume) - end - + Entity.Capacity = Rounds Entity.AmmoMassMax = math.floor(Entity.BulletData.CartMass * Entity.Capacity) - Entity.Ammo = math.floor(Entity.Capacity * Percentage) + Entity.Ammo = math.floor(Entity.Capacity * Percentage) WireLib.TriggerOutput(Entity, "Ammo", Entity.Ammo) @@ -328,11 +151,11 @@ do -- Spawning and Updating -------------------- local MagSize = Weapon.MagSize -- for future use in reloading - --Entity.isBoxed = ExtraData.isBoxed -- Ammunition is boxed - --Entity.isTwoPiece = ExtraData.isTwoPiece -- Ammunition is broken down to two pieces + --Entity.IsBoxed = ExtraData.IsBoxed -- Ammunition is boxed + --Entity.IsTwoPiece = ExtraData.IsTwoPiece -- Ammunition is broken down to two pieces - ExtraData.MagSize = ExtraData.isBoxed and MagSize or 0 - ExtraData.IsRound = not (ExtraData.isBoxed or ExtraData.isTwoPiece or ExtraData.isRacked) + ExtraData.MagSize = ExtraData.IsBoxed and MagSize or 0 + ExtraData.IsRound = not (ExtraData.IsBoxed or ExtraData.IsTwoPiece or ExtraData.IsRacked) ExtraData.Capacity = Entity.Capacity ExtraData.Enabled = true else From 566738a27a93b41d28b550ace388a937fb9cb672 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Mon, 18 Jan 2021 01:39:37 -0300 Subject: [PATCH 272/279] Improved ammo crate updating with the menu tool - Updating an ammo crate with the menu tool will no longer change the size of the crate. - Renamed ACF.CalculateCrateCapacity to ACF.GetAmmoCrateCapacity. --- lua/acf/base/sh_round_functions.lua | 2 +- lua/entities/acf_ammo/init.lua | 12 +++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/lua/acf/base/sh_round_functions.lua b/lua/acf/base/sh_round_functions.lua index 1e9629ef5..42d16c842 100644 --- a/lua/acf/base/sh_round_functions.lua +++ b/lua/acf/base/sh_round_functions.lua @@ -214,7 +214,7 @@ do -- Ammo crate capacity calculation -- AddArmor is literally just extra armor on the ammo crate, but inside (also directly reduces storage) -- For missiles/bombs, they MUST have ActualLength and ActualWidth (of the model in cm, and in the round table) to use this, otherwise it will fall back to the original calculations -- Made by LiddulBOFH :) - function ACF.CalculateCrateCapacity(BoxSize, GunData, BulletData, AddSpacing, AddArmor) + function ACF.GetAmmoCrateCapacity(BoxSize, GunData, BulletData, AddSpacing, AddArmor) -- gives a nice number of rounds per refill box if BulletData.Type == "Refill" then return math.ceil(BoxSize.x * BoxSize.y * BoxSize.z * 0.01) end diff --git a/lua/entities/acf_ammo/init.lua b/lua/entities/acf_ammo/init.lua index 89999ab65..3fb4a6798 100644 --- a/lua/entities/acf_ammo/init.lua +++ b/lua/entities/acf_ammo/init.lua @@ -136,7 +136,7 @@ do -- Spawning and Updating -------------------- do -- Ammo count calculation local Size = Entity:GetSize() local Spacing = Weapon.Caliber * 0.0039 - local Rounds, ExtraData = ACF.CalculateCrateCapacity(Size, Weapon, Entity.BulletData, Spacing, ACF.AmmoArmor) + local Rounds, ExtraData = ACF.GetAmmoCrateCapacity(Size, Weapon, Entity.BulletData, Spacing, ACF.AmmoArmor) local Percentage = Entity.Capacity and Entity.Ammo / math.max(Entity.Capacity, 1) or 1 Entity.Capacity = Rounds @@ -208,6 +208,16 @@ do -- Spawning and Updating -------------------- end end) + hook.Add("ACF_CanUpdateEntity", "ACF Crate Size Update", function(Entity, Data) + if not Entity.IsAmmoCrate then return end + if Data.Size then return end -- The menu won't send it like this + + Data.Size = Entity:GetSize() + Data.CrateSizeX = nil + Data.CrateSizeY = nil + Data.CrateSizeZ = nil + end) + ------------------------------------------------------------------------------- function MakeACF_Ammo(Player, Pos, Ang, Data) From ab4e9faff6ef31402337a3b6128752506d288f3a Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Mon, 18 Jan 2021 03:26:20 -0300 Subject: [PATCH 273/279] Added crate information to ammo menu - The ammo menu will now display a paragraph with the armor, mass and capacity of the ammo crate that'd be created with the current settings. - Added Ammo:AddCrateDataTrackers function to each ammo type that contains a modifier that'd mess with the round's size or mass. --- lua/acf/client/ammo_menu.lua | 80 ++++++++++++++++++++++++++--- lua/acf/shared/ammo_types/ap.lua | 5 ++ lua/acf/shared/ammo_types/aphe.lua | 6 +++ lua/acf/shared/ammo_types/fl.lua | 6 +++ lua/acf/shared/ammo_types/heat.lua | 7 +++ lua/acf/shared/ammo_types/hp.lua | 6 +++ lua/acf/shared/ammo_types/smoke.lua | 7 +++ 7 files changed, 109 insertions(+), 8 deletions(-) diff --git a/lua/acf/client/ammo_menu.lua b/lua/acf/client/ammo_menu.lua index 11cdf15d8..901f90dca 100644 --- a/lua/acf/client/ammo_menu.lua +++ b/lua/acf/client/ammo_menu.lua @@ -1,8 +1,15 @@ -local ACF = ACF -local AmmoTypes = ACF.Classes.AmmoTypes +local ACF = ACF +local Classes = ACF.Classes +local AmmoTypes = Classes.AmmoTypes +local BoxSize = Vector() local Ammo, BulletData +local CrateText = [[ + Crate Armor: %s mm + Crate Mass : %s + Crate Capacity : %s round(s)]] + local function CopySettings(Settings) local Copy = {} @@ -28,6 +35,21 @@ local function GetAmmoList(Class) return Result end +local function GetWeaponData(ToolData) + local Destiny = Classes[ToolData.Destiny or "Weapons"] + local Class = ACF.GetClassGroup(Destiny, ToolData.Weapon) + + return Class.Lookup[ToolData.Weapon] +end + +local function GetEmptyMass() + local Armor = ACF.AmmoArmor * 0.039 -- Millimeters to inches + local ExteriorVolume = BoxSize.x * BoxSize.y * BoxSize.z + local InteriorVolume = (BoxSize.x - Armor) * (BoxSize.y - Armor) * (BoxSize.z - Armor) + + return math.Round((ExteriorVolume - InteriorVolume) * 0.13, 2) +end + local function AddPreview(Base, Settings, ToolData) if Settings.SuppressPreview then return end @@ -125,6 +147,36 @@ end local function AddInformation(Base, Settings, ToolData) if Settings.SuppressInformation then return end + if not Settings.SuppressCrateInformation then + local Trackers = {} + + local Crate = Base:AddLabel() + Crate:TrackClientData("Weapon", "SetText") + Crate:TrackClientData("CrateSizeX") + Crate:TrackClientData("CrateSizeY") + Crate:TrackClientData("CrateSizeZ") + Crate:DefineSetter(function() + local Weapon = GetWeaponData(ToolData) + local Spacing = Weapon.Caliber * 0.0039 + local Rounds = ACF.GetAmmoCrateCapacity(BoxSize, Weapon, BulletData, Spacing, ACF.AmmoArmor) + local Empty = GetEmptyMass() + local Load = math.floor(BulletData.CartMass * Rounds) + local Mass = ACF.GetProperMass(math.floor(Empty + Load)) + + return CrateText:format(ACF.AmmoArmor, Mass, Rounds) + end) + + if Ammo.AddCrateDataTrackers then + Ammo:AddCrateDataTrackers(Trackers, ToolData, BulletData) + end + + hook.Run("ACF_AddCrateDataTrackers", Trackers, ToolData, Ammo, BulletData) + + for Tracker in pairs(Trackers) do + Crate:TrackClientData(Tracker) + end + end + if Ammo.AddAmmoInformation then Ammo:AddAmmoInformation(Base, ToolData, BulletData) end @@ -173,25 +225,37 @@ function ACF.CreateAmmoMenu(Menu, Settings) local SizeX = Menu:AddSlider("Crate Width", 6, 96, 2) SizeX:SetClientData("CrateSizeX", "OnValueChanged") SizeX:DefineSetter(function(Panel, _, _, Value) - Panel:SetValue(Value) + local X = math.Round(Value, 2) + + Panel:SetValue(X) - return Value + BoxSize.x = X + + return X end) local SizeY = Menu:AddSlider("Crate Height", 6, 96, 2) SizeY:SetClientData("CrateSizeY", "OnValueChanged") SizeY:DefineSetter(function(Panel, _, _, Value) - Panel:SetValue(Value) + local Y = math.Round(Value, 2) + + Panel:SetValue(Y) + + BoxSize.y = Y - return Value + return Y end) local SizeZ = Menu:AddSlider("Crate Depth", 6, 96, 2) SizeZ:SetClientData("CrateSizeZ", "OnValueChanged") SizeZ:DefineSetter(function(Panel, _, _, Value) - Panel:SetValue(Value) + local Z = math.Round(Value, 2) + + Panel:SetValue(Z) + + BoxSize.z = Z - return Value + return Z end) local Base = Menu:AddCollapsible("Ammo Information") diff --git a/lua/acf/shared/ammo_types/ap.lua b/lua/acf/shared/ammo_types/ap.lua index febda14d2..651adb9b5 100644 --- a/lua/acf/shared/ammo_types/ap.lua +++ b/lua/acf/shared/ammo_types/ap.lua @@ -216,6 +216,11 @@ else util.Effect("ACF_Ricochet", Effect) end + function Ammo:AddCrateDataTrackers(Trackers) + Trackers.Projectile = true + Trackers.Propellant = true + end + function Ammo:AddAmmoInformation(Base, ToolData, BulletData) local RoundStats = Base:AddLabel() RoundStats:TrackClientData("Projectile", "SetText") diff --git a/lua/acf/shared/ammo_types/aphe.lua b/lua/acf/shared/ammo_types/aphe.lua index f514401b0..3960b655f 100644 --- a/lua/acf/shared/ammo_types/aphe.lua +++ b/lua/acf/shared/ammo_types/aphe.lua @@ -146,6 +146,12 @@ else end) end + function Ammo:AddCrateDataTrackers(Trackers, ...) + Ammo.BaseClass.AddCrateDataTrackers(self, Trackers, ...) + + Trackers.FillerMass = true + end + function Ammo:AddAmmoInformation(Base, ToolData, BulletData) local RoundStats = Base:AddLabel() RoundStats:TrackClientData("Projectile", "SetText") diff --git a/lua/acf/shared/ammo_types/fl.lua b/lua/acf/shared/ammo_types/fl.lua index 32f065945..0d23c5741 100644 --- a/lua/acf/shared/ammo_types/fl.lua +++ b/lua/acf/shared/ammo_types/fl.lua @@ -206,6 +206,12 @@ else end) end + function Ammo:AddCrateDataTrackers(Trackers, ...) + Ammo.BaseClass.AddCrateDataTrackers(self, Trackers, ...) + + Trackers.Flechettes = true + end + function Ammo:AddAmmoInformation(Menu, ToolData, BulletData) local RoundStats = Menu:AddLabel() RoundStats:TrackClientData("Projectile", "SetText") diff --git a/lua/acf/shared/ammo_types/heat.lua b/lua/acf/shared/ammo_types/heat.lua index cf7733527..d3079a253 100644 --- a/lua/acf/shared/ammo_types/heat.lua +++ b/lua/acf/shared/ammo_types/heat.lua @@ -345,6 +345,13 @@ else end) end + function Ammo:AddCrateDataTrackers(Trackers, ...) + Ammo.BaseClass.AddCrateDataTrackers(self, Trackers, ...) + + Trackers.FillerMass = true + Trackers.LinerAngle = true + end + function Ammo:AddAmmoInformation(Base, ToolData, BulletData) local RoundStats = Base:AddLabel() RoundStats:TrackClientData("Projectile", "SetText") diff --git a/lua/acf/shared/ammo_types/hp.lua b/lua/acf/shared/ammo_types/hp.lua index 8523ebaf1..40ad4c3f4 100644 --- a/lua/acf/shared/ammo_types/hp.lua +++ b/lua/acf/shared/ammo_types/hp.lua @@ -122,6 +122,12 @@ else end) end + function Ammo:AddCrateDataTrackers(Trackers, ...) + Ammo.BaseClass.AddCrateDataTrackers(self, Trackers, ...) + + Trackers.HollowCavity = true + end + function Ammo:AddAmmoInformation(Base, ToolData, BulletData) local RoundStats = Base:AddLabel() RoundStats:TrackClientData("Projectile", "SetText") diff --git a/lua/acf/shared/ammo_types/smoke.lua b/lua/acf/shared/ammo_types/smoke.lua index 65523383e..62fbd0b9d 100644 --- a/lua/acf/shared/ammo_types/smoke.lua +++ b/lua/acf/shared/ammo_types/smoke.lua @@ -232,6 +232,13 @@ else end) end + function Ammo:AddCrateDataTrackers(Trackers, ...) + Ammo.BaseClass.AddCrateDataTrackers(self, Trackers, ...) + + Trackers.SmokeFiller = true + Trackers.WPFiller = true + end + function Ammo:AddAmmoInformation(Menu, ToolData, Data) local RoundStats = Menu:AddLabel() RoundStats:TrackClientData("Projectile", "SetText") From d01cffb7b9a786828d63733fda15be22d8ea6251 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Mon, 18 Jan 2021 04:57:34 -0300 Subject: [PATCH 274/279] Converted the last server convars to data vars - Converted the last few convars on the ACF globals file to data variables. - Added all these new data variables to the server settings menu. - Callbacks will now ACF.PrintLog on the serverside and ACF.PrintToChat on the clientside to announce a value change. --- lua/acf/base/acf_globals.lua | 42 +++++------- lua/acf/client/menu_items/settings_menu.lua | 65 +++++++++++++++++-- lua/acf/server/ballistics.lua | 3 +- lua/acf/server/damage.lua | 3 +- lua/acf/server/persisted_vars.lua | 6 ++ lua/acf/shared/data_callbacks.lua | 47 +++++++++++--- lua/entities/acf_gun/init.lua | 3 +- lua/entities/acf_piledriver/init.lua | 3 +- .../core/custom/acffunctions.lua | 5 +- lua/starfall/libs_sv/acffunctions.lua | 5 +- 10 files changed, 130 insertions(+), 52 deletions(-) diff --git a/lua/acf/base/acf_globals.lua b/lua/acf/base/acf_globals.lua index b1348851e..8cc9382d9 100644 --- a/lua/acf/base/acf_globals.lua +++ b/lua/acf/base/acf_globals.lua @@ -6,13 +6,19 @@ do -- ACF global vars ACF.ClientData = ACF.ClientData or {} ACF.ServerData = ACF.ServerData or {} - -- Misc + -- General Settings ACF.Gamemode = 2 -- Gamemode of the server. 1 = Sandbox, 2 = Classic, 3 = Competitive ACF.Year = 1945 ACF.IllegalDisableTime = 30 -- Time in seconds for an entity to be disabled when it fails ACF_IsLegal + ACF.RestrictInfo = true -- If enabled, players will be only allowed to get info from entities they're allowed to mess with. ACF.GunfireEnabled = true ACF.AllowAdminData = false -- Allows admins to mess with a few server settings and data variables + ACF.HEPush = true -- Whether or not HE pushes on entities + ACF.KEPush = true -- Whether or not kinetic force pushes on entities + ACF.RecoilPush = true -- Whether or not ACF guns apply recoil ACF.AllowFunEnts = true -- Allows entities listed under the Fun Stuff option to be used + ACF.WorkshopContent = true -- Enable workshop content download for clients + ACF.WorkshopExtras = false -- Enable extra workshop content download for clients ACF.SmokeWind = 5 + math.random() * 35 --affects the ability of smoke to be used for screening effect -- Fuzes @@ -103,7 +109,7 @@ do -- ACF global vars ACF.RefuelSpeed = 20 -- Liters per second * ACF.FuelRate end -do -- ACF Convars/Callbacks ------------------------ +do -- ACF Convars & Particles CreateConVar("sbox_max_acf_ammo", 32, FCVAR_ARCHIVE + FCVAR_NOTIFY, "Maximum amount of ACF ammo crates a player can create.") game.AddParticles("particles/acf_muzzleflashes.pcf") @@ -114,30 +120,18 @@ end if SERVER then util.AddNetworkString("ACF_UpdateEntity") - CreateConVar("acf_enable_workshop_content", 1, FCVAR_ARCHIVE, "Enable workshop content download for clients. Requires server restart on change.", 0, 1) - CreateConVar("acf_enable_workshop_extras", 0, FCVAR_ARCHIVE, "Enable extra workshop content download for clients. Requires server restart on change.", 0, 1) - CreateConVar("acf_gamemode", 1, FCVAR_ARCHIVE + FCVAR_NOTIFY, "Sets the ACF gamemode of the server. 0 = Sandbox, 1 = Classic, 2 = Competitive", 0, 2) - CreateConVar("acf_restrict_info", 1, FCVAR_ARCHIVE, "If enabled, players will be only allowed to get info from entities they're allowed to mess with.", 0, 1) - CreateConVar("acf_hepush", 1, FCVAR_ARCHIVE, "Whether or not HE pushes on entities", 0, 1) - CreateConVar("acf_kepush", 1, FCVAR_ARCHIVE, "Whether or not kinetic force pushes on entities", 0, 1) - CreateConVar("acf_recoilpush", 1, FCVAR_ARCHIVE, "Whether or not ACF guns apply recoil", 0, 1) - - -- Addon content ---------------------------- - local Content = GetConVar("acf_enable_workshop_content") - - if Content:GetBool() then - resource.AddWorkshop("2183798463") -- Playermodel seats - end - --------------------------------------------- + hook.Add("PlayerConnect", "ACF Workshop Content", function() + if ACF.WorkshopContent then + resource.AddWorkshop("2183798463") -- Playermodel seats + end - -- Extra content ---------------------------- - local Extras = GetConVar("acf_enable_workshop_extras") + if ACF.WorkshopExtras then + resource.AddWorkshop("439526795") -- Hide Errors addon + resource.AddWorkshop("2099387099") -- ACF-3 Removed Extra Sounds + end - if Extras:GetBool() then - resource.AddWorkshop("439526795") -- Hide Errors addon - resource.AddWorkshop("2099387099") -- ACF-3 Removed Extra Sounds - end - --------------------------------------------- + hook.Add("PlayerConnect", "ACF Workshop Content") + end) elseif CLIENT then CreateClientConVar("acf_show_entity_info", 1, true, false, "Defines under what conditions the info bubble on ACF entities will be shown. 0 = Never, 1 = When not seated, 2 = Always", 0, 2) CreateClientConVar("acf_cl_particlemul", 1, true, true, "Multiplier for the density of ACF effects.", 0.1, 1) diff --git a/lua/acf/client/menu_items/settings_menu.lua b/lua/acf/client/menu_items/settings_menu.lua index ad56d5852..825d0a421 100644 --- a/lua/acf/client/menu_items/settings_menu.lua +++ b/lua/acf/client/menu_items/settings_menu.lua @@ -126,7 +126,17 @@ do -- Serverside settings Base:AddHelp("If enabled, admins will be able to mess with the settings on this panel.") - local Gunfire = Base:AddCheckBox("Allow weapons to be fired.") + local Info = Base:AddCheckBox("Restrict entity information.") + Info:SetServerData("RestrictInfo", "OnChange") + Info:DefineSetter(function(Panel, _, _, Value) + Panel:SetValue(Value) + + return Value + end) + + Base:AddHelp("You'll need the player's permissions in order to check relevant information on entities owned by them.") + + local Gunfire = Base:AddCheckBox("Allow weapon fire.") Gunfire:SetServerData("GunfireEnabled", "OnChange") Gunfire:DefineSetter(function(Panel, _, _, Value) Panel:SetValue(Value) @@ -161,7 +171,34 @@ do -- Serverside settings Base:AddHelp("Only applies to servers with their ACF Gamemode set to Competitive.") end) - ACF.AddServerSettings(101, "Fun Entities and Menu", function(Base) + ACF.AddServerSettings(100, "Sound Volume", function(Base) + ACF.AddServerSettings(101, "Entity Pushing", function(Base) + local HEPush = Base:AddCheckBox("Push entities due to HE forces.") + HEPush:SetServerData("HEPush", "OnChange") + HEPush:DefineSetter(function(Panel, _, _, Value) + Panel:SetValue(Value) + + return Value + end) + + local KEPush = Base:AddCheckBox("Push entities due to kinetic forces.") + KEPush:SetServerData("KEPush", "OnChange") + KEPush:DefineSetter(function(Panel, _, _, Value) + Panel:SetValue(Value) + + return Value + end) + + local Recoil = Base:AddCheckBox("Push entities due to weapon recoil.") + Recoil:SetServerData("RecoilPush", "OnChange") + Recoil:DefineSetter(function(Panel, _, _, Value) + Panel:SetValue(Value) + + return Value + end) + end) + + ACF.AddServerSettings(201, "Fun Entities and Menu", function(Base) local Entities = Base:AddCheckBox("Allow use of Fun Entities.") Entities:SetServerData("AllowFunEnts", "OnChange") Entities:DefineSetter(function(Panel, _, _, Value) @@ -183,7 +220,27 @@ do -- Serverside settings Base:AddHelp("Changes on this option will only take effect once the players reload their menu.") end) - ACF.AddServerSettings(201, "Custom Killicons", function(Base) + ACF.AddServerSettings(301, "Workshop Content", function(Base) + local Content = Base:AddCheckBox("Enable workshop content download for clients.") + Content:SetServerData("WorkshopContent", "OnChange") + Content:DefineSetter(function(Panel, _, _, Value) + Panel:SetValue(Value) + + return Value + end) + + local Extra = Base:AddCheckBox("Enable extra workshop content download for clients.") + Extra:SetServerData("WorkshopExtras", "OnChange") + Extra:DefineSetter(function(Panel, _, _, Value) + Panel:SetValue(Value) + + return Value + end) + + Base:AddHelp("Both of these options require a server restart to apply changes.") + end) + + ACF.AddServerSettings(401, "Custom Killicons", function(Base) local Icons = Base:AddCheckBox("Use custom killicons for ACF entities.") Icons:SetServerData("UseKillicons", "OnChange") Icons:DefineSetter(function(Panel, _, _, Value) @@ -195,7 +252,7 @@ do -- Serverside settings Base:AddHelp("Changing this option will require a server restart.") end) - ACF.AddServerSettings(301, "Debris", function(Base) + ACF.AddServerSettings(501, "Debris", function(Base) local Debris = Base:AddCheckBox("Allow networking of debris to clients.") Debris:SetServerData("CreateDebris", "OnChange") Debris:DefineSetter(function(Panel, _, _, Value) diff --git a/lua/acf/server/ballistics.lua b/lua/acf/server/ballistics.lua index 811c67064..6501e72cf 100644 --- a/lua/acf/server/ballistics.lua +++ b/lua/acf/server/ballistics.lua @@ -15,7 +15,6 @@ local GlobalFilter = ACF.GlobalFilter local AmmoTypes = ACF.Classes.AmmoTypes local Gravity = Vector(0, 0, -GetConVar("sv_gravity"):GetInt()) local HookRun = hook.Run -local ACF_KEPUSH = GetConVar("acf_kepush") cvars.AddChangeCallback("sv_gravity", function(_, _, Value) Gravity.z = -Value @@ -360,7 +359,7 @@ do -- Terminal ballistics -------------------------- end end - if ACF_KEPUSH:GetBool() then + if ACF.KEPush then ACF.KEShove( Target, HitPos, diff --git a/lua/acf/server/damage.lua b/lua/acf/server/damage.lua index 8118baa0d..44ec79623 100644 --- a/lua/acf/server/damage.lua +++ b/lua/acf/server/damage.lua @@ -1,6 +1,5 @@ -- Local Vars ----------------------------------- local ACF = ACF -local ACF_HEPUSH = GetConVar("acf_hepush") local TimerCreate = timer.Create local TraceRes = {} local TraceData = { output = TraceRes, mask = MASK_SOLID, filter = false } @@ -249,7 +248,7 @@ do -- Explosions ---------------------------- end Loop = true -- Check for new targets since something died, maybe we'll find something new - elseif ACF_HEPUSH:GetBool() then -- Just damaged, not killed, so push on it some + elseif ACF.HEPush then -- Just damaged, not killed, so push on it some Shove(Ent, Origin, Table.Vec, PowerFraction * 33.3) -- Assuming about 1/30th of the explosive energy goes to propelling the target prop (Power in KJ * 1000 to get J then divided by 33) end diff --git a/lua/acf/server/persisted_vars.lua b/lua/acf/server/persisted_vars.lua index dcc0cc289..7b6fbb267 100644 --- a/lua/acf/server/persisted_vars.lua +++ b/lua/acf/server/persisted_vars.lua @@ -3,14 +3,20 @@ -- Settings ACF.PersistServerData("Gamemode", 2) ACF.PersistServerData("ServerDataAllowAdmin", false) +ACF.PersistServerData("RestrictInfo", true) ACF.PersistServerData("GunfireEnabled", true) ACF.PersistServerData("HealthFactor", 1) ACF.PersistServerData("ArmorFactor", 1) ACF.PersistServerData("FuelFactor", 1) ACF.PersistServerData("CompFuelFactor", 1) +ACF.PersistServerData("HEPush", true) +ACF.PersistServerData("KEPush", true) +ACF.PersistServerData("RecoilPush", true) ACF.PersistServerData("AllowFunEnts", true) ACF.PersistServerData("UseKillicons", true) ACF.PersistServerData("ShowFunMenu", true) +ACF.PersistServerData("WorkshopContent", true) +ACF.PersistServerData("WorkshopExtras", true) -- Debris ACF.PersistServerData("CreateDebris", true) diff --git a/lua/acf/shared/data_callbacks.lua b/lua/acf/shared/data_callbacks.lua index 7441266c1..6da4554e0 100644 --- a/lua/acf/shared/data_callbacks.lua +++ b/lua/acf/shared/data_callbacks.lua @@ -1,4 +1,5 @@ local ACF = ACF +local Message = SERVER and ACF.PrintLog or ACF.PrintToChat local Names = { [1] = "Sandbox", @@ -14,12 +15,13 @@ local Settings = { ACF.Gamemode = Mode - print("ACF Gamemode has been changed to " .. Names[Mode]) + Message("Info", "ACF Gamemode has been changed to " .. Names[Mode]) end, ServerDataAllowAdmin = function(_, _, Value) - local Bool = tobool(Value) - - ACF.AllowAdminData = Bool + ACF.AllowAdminData = tobool(Value) + end, + RestrictInfo = function(_, _, Value) + ACF.RestrictInfo = tobool(Value) end, GunfireEnabled = function(_, _, Value) local Bool = tobool(Value) @@ -28,7 +30,7 @@ local Settings = { ACF.GunfireEnabled = Bool - print("ACF Gunfire has been " .. (Bool and "enabled." or "disabled.")) + Message("Info", "ACF Gunfire has been " .. (Bool and "enabled." or "disabled.")) end, HealthFactor = function(_, _, Value) local Factor = math.Clamp(math.Round(tonumber(Value) or 1, 2), 0.01, 2) @@ -40,7 +42,7 @@ local Settings = { ACF.HealthFactor = Factor ACF.Threshold = ACF.Threshold / Old * Factor - print("ACF Health Mod changed to a factor of " .. Factor) + Message("Info", "ACF Health Mod changed to a factor of " .. Factor) end, ArmorFactor = function(_, _, Value) local Factor = math.Clamp(math.Round(tonumber(Value) or 1, 2), 0.01, 2) @@ -52,7 +54,7 @@ local Settings = { ACF.ArmorFactor = Factor ACF.ArmorMod = ACF.ArmorMod / Old * Factor - print("ACF Armor Mod changed to a factor of " .. Factor) + Message("Info", "ACF Armor Mod changed to a factor of " .. Factor) end, FuelFactor = function(_, _, Value) local Factor = math.Clamp(math.Round(tonumber(Value) or 1, 2), 0.01, 2) @@ -64,7 +66,7 @@ local Settings = { ACF.FuelFactor = Factor ACF.FuelRate = ACF.FuelRate / Old * Factor - print("ACF Fuel Rate changed to a factor of " .. Factor) + Message("Info", "ACF Fuel Rate changed to a factor of " .. Factor) end, CompFuelFactor = function(_, _, Value) local Factor = math.Clamp(math.Round(tonumber(Value) or 1, 2), 0.01, 2) @@ -76,12 +78,37 @@ local Settings = { ACF.CompFuelFactor = Factor ACF.CompFuelRate = ACF.CompFuelRate / Old * Factor - print("ACF Competitive Fuel Rate changed to a factor of " .. Factor) + Message("Info", "ACF Competitive Fuel Rate changed to a factor of " .. Factor) + end, + HEPush = function(_, _, Value) + ACF.HEPush = tobool(Value) + end, + KEPush = function(_, _, Value) + ACF.KEPush = tobool(Value) + end, + RecoilPush = function(_, _, Value) + ACF.RecoilPush = tobool(Value) end, AllowFunEnts = function(_, _, Value) + ACF.AllowFunEnts = tobool(Value) + end, + WorkshopContent = function(_, _, Value) local Bool = tobool(Value) - ACF.AllowFunEnts = Bool + if ACF.WorkshopContent == Bool then return end + + ACF.WorkshopContent = Bool + + Message("Info", "ACF Workshop Content download has been " .. (Bool and "enabled." or "disabled.")) + end, + WorkshopExtras = function(_, _, Value) + local Bool = tobool(Value) + + if ACF.WorkshopExtras == Bool then return end + + ACF.WorkshopExtras = Bool + + Message("Info", "ACF Extra Workshop Content download has been " .. (Bool and "enabled." or "disabled.")) end, } diff --git a/lua/entities/acf_gun/init.lua b/lua/entities/acf_gun/init.lua index 2b5f6d4f5..6c10d674c 100644 --- a/lua/entities/acf_gun/init.lua +++ b/lua/entities/acf_gun/init.lua @@ -6,7 +6,6 @@ include("shared.lua") -- Local Vars ----------------------------------- local ACF = ACF -local ACF_RECOIL = GetConVar("acf_recoilpush") local UnlinkSound = "physics/metal/metal_box_impact_bullet%s.wav" local CheckLegal = ACF_CheckLegal local Shove = ACF.KEShove @@ -487,7 +486,7 @@ do -- Metamethods -------------------------------- end function ENT:Recoil() - if not ACF_RECOIL:GetBool() then return end + if not ACF.RecoilPush then return end local MassCenter = self:LocalToWorld(self:GetPhysicsObject():GetMassCenter()) local Energy = self.BulletData.ProjMass * self.BulletData.MuzzleVel * 39.37 + self.BulletData.PropMass * 3000 * 39.37 diff --git a/lua/entities/acf_piledriver/init.lua b/lua/entities/acf_piledriver/init.lua index b78182cbb..b255b5849 100644 --- a/lua/entities/acf_piledriver/init.lua +++ b/lua/entities/acf_piledriver/init.lua @@ -10,7 +10,6 @@ do -- Spawning and Updating -------------------- local Piledrivers = ACF.Classes.Piledrivers local AmmoTypes = ACF.Classes.AmmoTypes local CheckLegal = ACF_CheckLegal - local ACF_RECOIL = GetConVar("acf_recoilpush") local function VerifyData(Data) if isstring(Data.Id) then @@ -129,7 +128,7 @@ do -- Spawning and Updating -------------------- end function BulletData:OnEndFlight(Trace) - if not ACF_RECOIL:GetBool() then return end + if not ACF.RecoilPush then return end if not IsValid(Entity) then return end if not Trace.HitWorld then return end if Trace.Fraction == 0 then return end diff --git a/lua/entities/gmod_wire_expression2/core/custom/acffunctions.lua b/lua/entities/gmod_wire_expression2/core/custom/acffunctions.lua index 748946d1e..7019870b4 100644 --- a/lua/entities/gmod_wire_expression2/core/custom/acffunctions.lua +++ b/lua/entities/gmod_wire_expression2/core/custom/acffunctions.lua @@ -11,7 +11,6 @@ E2Lib.RegisterExtension("acf", true) -- Local Variables and Helper Functions --===============================================================================================-- -local Restrict = GetConVar("acf_restrict_info") local ACF = ACF local AllLinkSources = ACF.GetAllLinkSources local LinkSource = ACF.GetLinkSource @@ -29,7 +28,7 @@ local function IsACFEntity(Entity) end local function RestrictInfo(Player, Entity) - if not Restrict:GetBool() then return false end + if not ACF.RestrictInfo then return false end return not isOwner(Player, Entity) end @@ -103,7 +102,7 @@ end -- Returns 1 if functions returning sensitive info are restricted to owned props e2function number acfInfoRestricted() - return Restrict:GetBool() and 1 or 0 + return ACF.RestrictInfo and 1 or 0 end __e2setcost(5) diff --git a/lua/starfall/libs_sv/acffunctions.lua b/lua/starfall/libs_sv/acffunctions.lua index 7a5c7d4f5..80c2e44a1 100644 --- a/lua/starfall/libs_sv/acffunctions.lua +++ b/lua/starfall/libs_sv/acffunctions.lua @@ -21,7 +21,6 @@ local ACF = ACF local math = math local match = string.match -local Restrict = GetConVar("acf_restrict_info") local AmmoTypes = ACF.Classes.AmmoTypes local Engines = ACF.Classes.Engines local FuelTanks = ACF.Classes.FuelTanks @@ -136,7 +135,7 @@ local ang_meta, aunwrap = instance.Types.Angle, instance.Types.Angle.Unwrap local vec_meta, vunwrap = instance.Types.Vector, instance.Types.Vector.Unwrap local function RestrictInfo(Entity) - if not Restrict:GetBool() then return false end + if not ACF.RestrictInfo then return false end return not isOwner(instance, Entity) end @@ -204,7 +203,7 @@ end -- @server -- @return True if restriced, False if not function acf_library.infoRestricted() - return Restrict:GetBool() + return ACF.RestrictInfo end --- Returns current ACF drag divisor From 5631ad4043cae66f78e575fed8528663ebe9040f Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Mon, 18 Jan 2021 05:37:44 -0300 Subject: [PATCH 275/279] Reimplemented ACF.Volume with data vars - Reimplemented the current changes on master related to the addition of the ACF.Volume global to work with data variables. --- lua/acf/base/acf_globals.lua | 1 + lua/acf/client/menu_items/settings_menu.lua | 23 +++++++++++++++++++++ lua/acf/client/persisted_vars.lua | 4 ++++ lua/acf/server/persisted_vars.lua | 1 + lua/acf/shared/ammo_types/refill.lua | 4 ++-- lua/acf/shared/data_callbacks.lua | 9 ++++++++ lua/effects/acf_explosion.lua | 6 ++++-- lua/effects/acf_muzzle_flash.lua | 7 ++++--- lua/effects/acf_penetration.lua | 14 ++++++++----- lua/effects/acf_ricochet.lua | 14 ++++++++----- lua/entities/acf_ammo/init.lua | 3 ++- lua/entities/acf_engine/init.lua | 4 ++-- lua/entities/acf_fueltank/init.lua | 8 +++---- lua/entities/acf_gearbox/init.lua | 2 +- lua/entities/acf_gun/init.lua | 10 ++++----- lua/entities/acf_piledriver/init.lua | 4 ++-- lua/weapons/acf_base/init.lua | 4 ++-- lua/weapons/torch/shared.lua | 9 +++++--- 18 files changed, 90 insertions(+), 37 deletions(-) diff --git a/lua/acf/base/acf_globals.lua b/lua/acf/base/acf_globals.lua index 8cc9382d9..71dbe5eaf 100644 --- a/lua/acf/base/acf_globals.lua +++ b/lua/acf/base/acf_globals.lua @@ -16,6 +16,7 @@ do -- ACF global vars ACF.HEPush = true -- Whether or not HE pushes on entities ACF.KEPush = true -- Whether or not kinetic force pushes on entities ACF.RecoilPush = true -- Whether or not ACF guns apply recoil + ACF.Volume = 1 -- Global volume for ACF sounds ACF.AllowFunEnts = true -- Allows entities listed under the Fun Stuff option to be used ACF.WorkshopContent = true -- Enable workshop content download for clients ACF.WorkshopExtras = false -- Enable extra workshop content download for clients diff --git a/lua/acf/client/menu_items/settings_menu.lua b/lua/acf/client/menu_items/settings_menu.lua index 825d0a421..90f4fd2db 100644 --- a/lua/acf/client/menu_items/settings_menu.lua +++ b/lua/acf/client/menu_items/settings_menu.lua @@ -47,6 +47,18 @@ do -- Clientside settings Base:AddHelp("Requires hitboxes to be enabled.") end) + ACF.AddClientSettings(100, "Sound Volume", function(Base) + local Volume = Base:AddSlider("Client Sound Volume", 0, 1, 2) + Volume:SetClientData("Volume", "OnValueChanged") + Volume:DefineSetter(function(Panel, _, _, Value) + Panel:SetValue(Value) + + return Value + end) + + Base:AddHelp("For the moment, this will only affect sounds that are played from the clientside.") + end) + ACF.AddClientSettings(101, "Effects and Visual Elements", function(Base) local Ropes = Base:AddCheckBox("Create mobility rope links.") Ropes:SetConVar("acf_mobilityropelinks") @@ -172,6 +184,17 @@ do -- Serverside settings end) ACF.AddServerSettings(100, "Sound Volume", function(Base) + local Volume = Base:AddSlider("Server Sound Volume", 0, 1, 2) + Volume:SetServerData("Volume", "OnValueChanged") + Volume:DefineSetter(function(Panel, _, _, Value) + Panel:SetValue(Value) + + return Value + end) + + Base:AddHelp("Will affect a handful of sounds that are played from the serverside. This will be deprecated in the future.") + end) + ACF.AddServerSettings(101, "Entity Pushing", function(Base) local HEPush = Base:AddCheckBox("Push entities due to HE forces.") HEPush:SetServerData("HEPush", "OnChange") diff --git a/lua/acf/client/persisted_vars.lua b/lua/acf/client/persisted_vars.lua index 0df5e1b36..e7adf27d4 100644 --- a/lua/acf/client/persisted_vars.lua +++ b/lua/acf/client/persisted_vars.lua @@ -1,5 +1,9 @@ -- Variables that should be persisted between servers +-- Settings +ACF.PersistClientData("Volume", 1) + +-- Crate size ACF.PersistClientData("CrateSizeX", 24) ACF.PersistClientData("CrateSizeY", 24) ACF.PersistClientData("CrateSizeZ", 24) diff --git a/lua/acf/server/persisted_vars.lua b/lua/acf/server/persisted_vars.lua index 7b6fbb267..074b1fbc7 100644 --- a/lua/acf/server/persisted_vars.lua +++ b/lua/acf/server/persisted_vars.lua @@ -12,6 +12,7 @@ ACF.PersistServerData("CompFuelFactor", 1) ACF.PersistServerData("HEPush", true) ACF.PersistServerData("KEPush", true) ACF.PersistServerData("RecoilPush", true) +ACF.PersistServerData("Volume", 1) ACF.PersistServerData("AllowFunEnts", true) ACF.PersistServerData("UseKillicons", true) ACF.PersistServerData("ShowFunMenu", true) diff --git a/lua/acf/shared/ammo_types/refill.lua b/lua/acf/shared/ammo_types/refill.lua index a18d217a3..3c637bb56 100644 --- a/lua/acf/shared/ammo_types/refill.lua +++ b/lua/acf/shared/ammo_types/refill.lua @@ -90,8 +90,8 @@ if SERVER then Crate:Consume(-Transfer) Refill:Consume(Transfer) - Crate:EmitSound("items/ammo_pickup.wav", 350, 100, 0.5) - Refill:EmitSound("items/ammo_pickup.wav", 350, 100, 0.5) + Crate:EmitSound("items/ammo_pickup.wav", 70, 100, 0.5 * ACF.Volume) + Refill:EmitSound("items/ammo_pickup.wav", 70, 100, 0.5 * ACF.Volume) elseif Refill.SupplyingTo[Crate] then Refill.SupplyingTo[Crate] = nil diff --git a/lua/acf/shared/data_callbacks.lua b/lua/acf/shared/data_callbacks.lua index 6da4554e0..f2e756553 100644 --- a/lua/acf/shared/data_callbacks.lua +++ b/lua/acf/shared/data_callbacks.lua @@ -115,3 +115,12 @@ local Settings = { for Key, Function in pairs(Settings) do ACF.AddServerDataCallback(Key, "Global Variable Callback", Function) end + +do -- Volume setting callback + local Realm = SERVER and "Server" or "Client" + local Callback = ACF["Add" .. Realm .. "DataCallback"] + + Callback("Volume", "Volume Variable Callback", function(_, _, Value) + ACF.Volume = math.Clamp(tonumber(Value) or 1, 0, 1) + end) +end diff --git a/lua/effects/acf_explosion.lua b/lua/effects/acf_explosion.lua index 71f380a5f..22b4ce965 100644 --- a/lua/effects/acf_explosion.lua +++ b/lua/effects/acf_explosion.lua @@ -119,8 +119,10 @@ function EFFECT:Core(Direction) end end - sound.Play("ambient/explosions/explode_5.wav", self.Origin, math.Clamp(Radius * 10, 75, 165), math.Clamp(300 - Radius * 12, 15, 255)) - sound.Play("ambient/explosions/explode_4.wav", self.Origin, math.Clamp(Radius * 10, 75, 165), math.Clamp(300 - Radius * 25, 15, 255)) + local Level = math.Clamp(Radius * 10, 75, 165) + + sound.Play("ambient/explosions/explode_5.wav", self.Origin, Level, math.Clamp(300 - Radius * 12, 15, 255), ACF.Volume) + sound.Play("ambient/explosions/explode_4.wav", self.Origin, Level, math.Clamp(300 - Radius * 25, 15, 255), ACF.Volume) end function EFFECT:GroundImpact() diff --git a/lua/effects/acf_muzzle_flash.lua b/lua/effects/acf_muzzle_flash.lua index cee141fa1..ec5318ee9 100644 --- a/lua/effects/acf_muzzle_flash.lua +++ b/lua/effects/acf_muzzle_flash.lua @@ -27,13 +27,14 @@ function EFFECT:Init(Data) if Sound ~= "" then local SoundPressure = (Propellant * 1000) ^ 0.5 - sound.Play(Sound, GunPos, math.Clamp(SoundPressure, 75, 127), 100) --wiki documents level tops out at 180, but seems to fall off past 127 + -- NOTE: Wiki documents level tops out at 180, but seems to fall off past 127 + sound.Play(Sound, GunPos, math.Clamp(SoundPressure, 75, 127), 100, ACF.Volume) if not (Class == "MG" or Class == "RAC") then - sound.Play(Sound, GunPos, math.Clamp(SoundPressure, 75, 127), 100) + sound.Play(Sound, GunPos, math.Clamp(SoundPressure, 75, 127), 100, ACF.Volume) if SoundPressure > 127 then - sound.Play(Sound, GunPos, math.Clamp(SoundPressure - 127, 1, 127), 100) + sound.Play(Sound, GunPos, math.Clamp(SoundPressure - 127, 1, 127), 100, ACF.Volume) end end end diff --git a/lua/effects/acf_penetration.lua b/lua/effects/acf_penetration.lua index fb1b50ecf..640524ed2 100644 --- a/lua/effects/acf_penetration.lua +++ b/lua/effects/acf_penetration.lua @@ -1,8 +1,9 @@ -local TraceData = { start = true, endpos = true } -local TraceLine = util.TraceLine +local TraceData = { start = true, endpos = true } +local TraceLine = util.TraceLine local ValidDecal = ACF.IsValidAmmoDecal -local GetDecal = ACF.GetPenetrationDecal -local GetScale = ACF.GetDecalScale +local GetDecal = ACF.GetPenetrationDecal +local GetScale = ACF.GetDecalScale +local Sound = "acf_base/fx/penetration%s.mp3" function EFFECT:Init(Data) self.Caliber = Data:GetRadius() @@ -37,7 +38,10 @@ function EFFECT:Init(Data) util.DecalEx(GetDecal(Type), Trace.Entity, Trace.HitPos, self.Normal, Color(255, 255, 255), Scale, Scale) end - sound.Play("acf_base/fx/penetration" .. math.random(1, 6) .. ".mp3", Trace.HitPos, math.Clamp(self.Mass * 200, 65, 500), math.Clamp(self.Velocity * 0.01, 25, 255), 1) + local Level = math.Clamp(self.Mass * 200, 65, 500) + local Pitch = math.Clamp(self.Velocity * 0.01, 25, 255) + + sound.Play(Sound:format(math.random(1, 6)), Trace.HitPos, Level, Pitch, ACF.Volume) end function EFFECT:Metal() diff --git a/lua/effects/acf_ricochet.lua b/lua/effects/acf_ricochet.lua index 58adc3f2f..86a9e730f 100644 --- a/lua/effects/acf_ricochet.lua +++ b/lua/effects/acf_ricochet.lua @@ -1,8 +1,9 @@ -local TraceData = { start = true, endpos = true } -local TraceLine = util.TraceLine +local TraceData = { start = true, endpos = true } +local TraceLine = util.TraceLine local ValidDecal = ACF.IsValidAmmoDecal -local GetDecal = ACF.GetRicochetDecal -local GetScale = ACF.GetDecalScale +local GetDecal = ACF.GetRicochetDecal +local GetScale = ACF.GetDecalScale +local Sound = "acf_base/fx/ricochet%s.mp3" function EFFECT:Init(Data) local Caliber = Data:GetRadius() @@ -24,7 +25,10 @@ function EFFECT:Init(Data) util.DecalEx(GetDecal(DecalType), Trace.Entity, Trace.HitPos, Trace.HitNormal, Color(255, 255, 255), Scale, Scale) end - sound.Play("acf_base/fx/penetration" .. math.random(1, 4) .. ".mp3", Origin, math.Clamp(Mass * 200, 65, 500), math.Clamp(Velocity * 0.01, 25, 255), 1) + local Level = math.Clamp(Mass * 200, 65, 500) + local Pitch = math.Clamp(Velocity * 0.01, 25, 255) + + sound.Play(Sound:format(math.random(1, 4)), Origin, Level, Pitch, ACF.Volume) end function EFFECT:Think() diff --git a/lua/entities/acf_ammo/init.lua b/lua/entities/acf_ammo/init.lua index 3fb4a6798..10ebc3b8f 100644 --- a/lua/entities/acf_ammo/init.lua +++ b/lua/entities/acf_ammo/init.lua @@ -374,8 +374,9 @@ do -- ACF Activation and Damage ----------------- if VolumeRoll and AmmoRoll then local Speed = ACF_MuzzleVelocity(Entity.BulletData.PropMass, Entity.BulletData.ProjMass / 2) + local Pitch = math.max(255 - Entity.BulletData.PropMass * 100,60) - Entity:EmitSound("ambient/explosions/explode_4.wav", 350, math.max(255 - Entity.BulletData.PropMass * 100,60)) + Entity:EmitSound("ambient/explosions/explode_4.wav", 140, Pitch, ACF.Volume) Entity.BulletData.Pos = Entity:LocalToWorld(Entity:OBBCenter() + VectorRand() * Entity:GetSize() * 0.5) Entity.BulletData.Flight = VectorRand():GetNormalized() * Speed * 39.37 + ACF_GetAncestor(Entity):GetVelocity() diff --git a/lua/entities/acf_engine/init.lua b/lua/entities/acf_engine/init.lua index b120af372..75630374a 100644 --- a/lua/entities/acf_engine/init.lua +++ b/lua/entities/acf_engine/init.lua @@ -122,7 +122,7 @@ local function GetPitchVolume(Engine) local Pitch = math.Clamp(20 + (RPM * Engine.SoundPitch) * 0.02, 1, 255) local Volume = 0.25 + (0.1 + 0.9 * ((RPM / Engine.LimitRPM) ^ 1.5)) * Engine.Throttle * 0.666 - return Pitch, Volume + return Pitch, Volume * ACF.Volume end local function GetNextFuelTank(Engine) @@ -145,7 +145,7 @@ local function CheckDistantFuelTanks(Engine) for Tank in pairs(Engine.FuelTanks) do if EnginePos:DistToSqr(Tank:GetPos()) > 262144 then - Engine:EmitSound(UnlinkSound:format(math.random(1, 3)), 500, 100) + Engine:EmitSound(UnlinkSound:format(math.random(1, 3)), 70, 100, ACF.Volume) Engine:Unlink(Tank) end diff --git a/lua/entities/acf_fueltank/init.lua b/lua/entities/acf_fueltank/init.lua index 7ddbf587f..c6fce5771 100644 --- a/lua/entities/acf_fueltank/init.lua +++ b/lua/entities/acf_fueltank/init.lua @@ -452,11 +452,11 @@ function ENT:Think() Tank:Consume(-Exchange) if self.FuelType == "Electric" then - self:EmitSound("ambient/energy/newspark04.wav", 75, 100, 0.5) - Tank:EmitSound("ambient/energy/newspark04.wav", 75, 100, 0.5) + self:EmitSound("ambient/energy/newspark04.wav", 70, 100, 0.5 * ACF.Volume) + Tank:EmitSound("ambient/energy/newspark04.wav", 70, 100, 0.5 * ACF.Volume) else - self:EmitSound("vehicles/jetski/jetski_no_gas_start.wav", 75, 120, 0.5) - Tank:EmitSound("vehicles/jetski/jetski_no_gas_start.wav", 75, 120, 0.5) + self:EmitSound("vehicles/jetski/jetski_no_gas_start.wav", 70, 120, 0.5 * ACF.Volume) + Tank:EmitSound("vehicles/jetski/jetski_no_gas_start.wav", 70, 120, 0.5 * ACF.Volume) end end end diff --git a/lua/entities/acf_gearbox/init.lua b/lua/entities/acf_gearbox/init.lua index d116a61ca..14e353172 100644 --- a/lua/entities/acf_gearbox/init.lua +++ b/lua/entities/acf_gearbox/init.lua @@ -763,7 +763,7 @@ function ENT:ChangeGear(Value) self.GearRatio = self.Gears[Value] * self.FinalDrive self.ChangeFinished = ACF.CurTime + self.SwitchTime - self:EmitSound("buttons/lever7.wav", 250, 100) + self:EmitSound("buttons/lever7.wav", 70, 100, 0.5 * ACF.Volume) WireLib.TriggerOutput(self, "Current Gear", Value) WireLib.TriggerOutput(self, "Ratio", self.GearRatio) diff --git a/lua/entities/acf_gun/init.lua b/lua/entities/acf_gun/init.lua index 6c10d674c..e5770036b 100644 --- a/lua/entities/acf_gun/init.lua +++ b/lua/entities/acf_gun/init.lua @@ -388,7 +388,7 @@ do -- Metamethods -------------------------------- if self.State ~= "Loaded" then -- Weapon is not loaded if self.State == "Empty" and not self.Retry then if not self:Load() then - self:EmitSound("weapons/pistol/pistol_empty.wav", 500, 100) -- Click! + self:EmitSound("weapons/pistol/pistol_empty.wav", 70, 100, ACF.Volume) -- Click! end self.Retry = true @@ -521,7 +521,7 @@ do -- Metamethods -------------------------------- self:ReloadEffect(Reload and Time * 2 or Time) self:SetState("Unloading") - self:EmitSound("weapons/357/357_reload4.wav", 500, 100) + self:EmitSound("weapons/357/357_reload4.wav", 70, 100, ACF.Volume) self.CurrentShot = 0 self.BulletData = EMPTY @@ -604,7 +604,7 @@ do -- Metamethods -------------------------------- self:SetState("Loading") if self.MagReload then -- Mag-fed/Automatically loaded - self:EmitSound("weapons/357/357_reload4.wav", 500, 100) + self:EmitSound("weapons/357/357_reload4.wav", 70, 100, ACF.Volume) self.NextFire = ACF.CurTime + self.MagReload @@ -734,8 +734,8 @@ do -- Metamethods -------------------------------- if Crate:GetPos():DistToSqr(Pos) > 62500 then -- 250 unit radius self:Unlink(Crate) - self:EmitSound(UnlinkSound:format(math.random(1, 3)), 500, 100) - Crate:EmitSound(UnlinkSound:format(math.random(1, 3)), 500, 100) + self:EmitSound(UnlinkSound:format(math.random(1, 3)), 70, 100, ACF.Volume) + Crate:EmitSound(UnlinkSound:format(math.random(1, 3)), 70, 100, ACF.Volume) end end end diff --git a/lua/entities/acf_piledriver/init.lua b/lua/entities/acf_piledriver/init.lua index b255b5849..1cdbd10bc 100644 --- a/lua/entities/acf_piledriver/init.lua +++ b/lua/entities/acf_piledriver/init.lua @@ -356,7 +356,7 @@ do -- Firing ------------------------------------ local Sound = self.SoundPath or Impact:format(math.random(5, 6)) local Bullet = self.BulletData - self:EmitSound(Sound, 500, math.Rand(98, 102)) + self:EmitSound(Sound, 70, math.Rand(98, 102), ACF.Volume) self:SetSequence("load") Bullet.Owner = self:GetUser(self.Inputs.Fire.Src) -- Must be updated on every shot @@ -376,7 +376,7 @@ do -- Firing ------------------------------------ self:SetSequence("idle") end) else - self:EmitSound("weapons/pistol/pistol_empty.wav", 500, math.Rand(98, 102)) + self:EmitSound("weapons/pistol/pistol_empty.wav", 70, math.Rand(98, 102), ACF.Volume) Delay = 1 end diff --git a/lua/weapons/acf_base/init.lua b/lua/weapons/acf_base/init.lua index 10e149673..c4744bf12 100644 --- a/lua/weapons/acf_base/init.lua +++ b/lua/weapons/acf_base/init.lua @@ -30,7 +30,7 @@ end function SWEP:Reload() if (self:Clip1() < self.Primary.ClipSize and self.Owner:GetAmmoCount(self.Primary.Ammo) > 0) then - self:EmitSound("weapons/AMR/sniper_reload.wav", 350, 110) + self:EmitSound("weapons/AMR/sniper_reload.wav", 70, 110, ACF.Volume) self:DefaultReload(ACT_VM_RELOAD) end end @@ -47,7 +47,7 @@ end --Server side effect, for external stuff function SWEP:MuzzleEffect() - self:EmitSound("weapons/AMR/sniper_fire.wav") + self:EmitSound("weapons/AMR/sniper_fire.wav", nil, nil, ACF.Volume) self.Owner:MuzzleFlash() self.Owner:SetAnimation(PLAYER_ATTACK1) end diff --git a/lua/weapons/torch/shared.lua b/lua/weapons/torch/shared.lua index 44d1c1b57..85dbb0644 100644 --- a/lua/weapons/torch/shared.lua +++ b/lua/weapons/torch/shared.lua @@ -30,6 +30,9 @@ SWEP.DrawAmmo = false SWEP.DrawCrosshair = true SWEP.MaxDistance = 64 * 64 -- Squared distance +local Spark = "ambient/energy/NewSpark0%s.wav" +local Zap = "weapons/physcannon/superphys_small_zap%s.wav" + local function TeslaSpark(pos, magnitude) zap = ents.Create("point_tesla") zap:SetKeyValue("targetname", "teslab") @@ -139,7 +142,7 @@ function SWEP:PrimaryAttack() Effect:SetEntity(self) util.Effect("thruster_ring", Effect, true, true) - Entity:EmitSound("items/medshot4.wav") + Entity:EmitSound("items/medshot4.wav", nil, nil, ACF.Volume) else if CPPI and not Entity:CPPICanTool(Owner, "torch") then return end @@ -161,7 +164,7 @@ function SWEP:PrimaryAttack() Entity:ACF_OnRepaired(OldArmor, OldHealth, Armor, Health) end - Entity:EmitSound("ambient/energy/NewSpark0" .. math.random(3, 5) .. ".wav") + Entity:EmitSound(Spark:format(math.random(3, 5)), nil, nil, ACF.Volume) TeslaSpark(Trace.HitPos, 1) end end @@ -204,7 +207,7 @@ function SWEP:SecondaryAttack() Effect:SetOrigin(Trace.HitPos) util.Effect("Sparks", Effect, true, true) - Entity:EmitSound("weapons/physcannon/superphys_small_zap" .. math.random(1, 4) .. ".wav") + Entity:EmitSound(Zap:format(math.random(1, 4)), nil, nil, ACF.Volume) end end end From 464394f6aebeb0a78015c354e7aae7846986e187 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Mon, 18 Jan 2021 05:38:26 -0300 Subject: [PATCH 276/279] Added sound replacer support to gearboxes - Players can now change the gear change sound on gearboxes with the Sound Replacer tool. --- lua/acf/base/sh_classes.lua | 4 +++ lua/entities/acf_engine/init.lua | 2 +- lua/entities/acf_gearbox/init.lua | 32 ++++++++++++----------- lua/entities/acf_gun/init.lua | 2 +- lua/weapons/gmod_tool/stools/acfsound.lua | 12 +++++++++ 5 files changed, 35 insertions(+), 17 deletions(-) diff --git a/lua/acf/base/sh_classes.lua b/lua/acf/base/sh_classes.lua index a093e3f38..7d2403c75 100644 --- a/lua/acf/base/sh_classes.lua +++ b/lua/acf/base/sh_classes.lua @@ -367,6 +367,10 @@ do -- Gearbox registration functions function ACF.RegisterGearboxClass(ID, Data) local Group = AddClassGroup(ID, Gearboxes, Data) + if not Group.Sound then + Group.Sound = "buttons/lever7.wav" + end + if not Group.LimitConVar then Group.LimitConVar = { Name = "_acf_gearbox", diff --git a/lua/entities/acf_engine/init.lua b/lua/entities/acf_engine/init.lua index 75630374a..75ed68089 100644 --- a/lua/entities/acf_engine/init.lua +++ b/lua/entities/acf_engine/init.lua @@ -265,6 +265,7 @@ do -- Spawn and Update functions Entity.ShortName = EngineData.ID Entity.EntType = Class.Name Entity.ClassData = Class + Entity.DefaultSound = EngineData.Sound Entity.SoundPitch = EngineData.Pitch or 1 Entity.PeakTorque = EngineData.Torque Entity.PeakTorqueHeld = EngineData.Torque @@ -346,7 +347,6 @@ do -- Spawn and Update functions Engine.Throttle = 0 Engine.FlyRPM = 0 Engine.SoundPath = EngineData.Sound - Engine.DefaultSound = EngineData.Sound Engine.Inputs = WireLib.CreateInputs(Engine, { "Active", "Throttle" }) Engine.Outputs = WireLib.CreateOutputs(Engine, { "RPM", "Torque", "Power", "Fuel Use", "Entity [ENTITY]", "Mass", "Physical Mass" }) Engine.DataStore = ACF.GetEntityArguments("acf_engine") diff --git a/lua/entities/acf_gearbox/init.lua b/lua/entities/acf_gearbox/init.lua index 14e353172..97ce866ea 100644 --- a/lua/entities/acf_gearbox/init.lua +++ b/lua/entities/acf_gearbox/init.lua @@ -328,20 +328,21 @@ do -- Spawn and Update functions Entity[V] = Data[V] end - Entity.Name = Gearbox.Name - Entity.ShortName = Gearbox.ID - Entity.EntType = Class.Name - Entity.ClassData = Class - Entity.SwitchTime = Gearbox.Switch - Entity.MaxTorque = Gearbox.MaxTorque - Entity.MinGear = Class.Gears.Min - Entity.MaxGear = Class.Gears.Max - Entity.GearCount = Entity.MaxGear - Entity.DualClutch = Gearbox.DualClutch - Entity.In = Entity:WorldToLocal(Entity:GetAttachment(Entity:LookupAttachment("input")).Pos) - Entity.OutL = Entity:WorldToLocal(Entity:GetAttachment(Entity:LookupAttachment("driveshaftL")).Pos) - Entity.OutR = Entity:WorldToLocal(Entity:GetAttachment(Entity:LookupAttachment("driveshaftR")).Pos) - Entity.HitBoxes = ACF.HitBoxes[Gearbox.Model] + Entity.Name = Gearbox.Name + Entity.ShortName = Gearbox.ID + Entity.EntType = Class.Name + Entity.ClassData = Class + Entity.DefaultSound = Class.Sound + Entity.SwitchTime = Gearbox.Switch + Entity.MaxTorque = Gearbox.MaxTorque + Entity.MinGear = Class.Gears.Min + Entity.MaxGear = Class.Gears.Max + Entity.GearCount = Entity.MaxGear + Entity.DualClutch = Gearbox.DualClutch + Entity.In = Entity:WorldToLocal(Entity:GetAttachment(Entity:LookupAttachment("input")).Pos) + Entity.OutL = Entity:WorldToLocal(Entity:GetAttachment(Entity:LookupAttachment("driveshaftL")).Pos) + Entity.OutR = Entity:WorldToLocal(Entity:GetAttachment(Entity:LookupAttachment("driveshaftR")).Pos) + Entity.HitBoxes = ACF.HitBoxes[Gearbox.Model] CreateInputs(Entity, Data, Class, Gearbox) CreateOutputs(Entity, Data, Class, Gearbox) @@ -425,6 +426,7 @@ do -- Spawn and Update functions Player:AddCount(Limit, Gearbox) Gearbox.Owner = Player -- MUST be stored on ent for PP + Gearbox.SoundPath = Class.Sound Gearbox.Engines = {} Gearbox.Wheels = {} -- a "Link" has these components: Ent, Side, Axis, Rope, RopeLen, Output, ReqTq, Vel Gearbox.GearboxIn = {} @@ -763,7 +765,7 @@ function ENT:ChangeGear(Value) self.GearRatio = self.Gears[Value] * self.FinalDrive self.ChangeFinished = ACF.CurTime + self.SwitchTime - self:EmitSound("buttons/lever7.wav", 70, 100, 0.5 * ACF.Volume) + self:EmitSound(self.SoundPath, 70, 100, 0.5 * ACF.Volume) WireLib.TriggerOutput(self, "Current Gear", Value) WireLib.TriggerOutput(self, "Ratio", self.GearRatio) diff --git a/lua/entities/acf_gun/init.lua b/lua/entities/acf_gun/init.lua index e5770036b..c5ed25f57 100644 --- a/lua/entities/acf_gun/init.lua +++ b/lua/entities/acf_gun/init.lua @@ -116,6 +116,7 @@ do -- Spawn and Update functions -------------------------------- Entity.Cyclic = Weapon.Cyclic and 60 / Weapon.Cyclic Entity.ReloadTime = Entity.Cyclic or 1 Entity.Spread = Class.Spread + Entity.DefaultSound = Class.Sound Entity.HitBoxes = ACF.HitBoxes[Weapon.Model] Entity.Long = Class.LongBarrel Entity.NormalMuzzle = Entity:WorldToLocal(Entity:GetAttachment(Entity:LookupAttachment("muzzle")).Pos) @@ -182,7 +183,6 @@ do -- Spawn and Update functions -------------------------------- Gun.Owner = Player -- MUST be stored on ent for PP Gun.SoundPath = Class.Sound - Gun.DefaultSound = Class.Sound Gun.BarrelFilter = { Gun } Gun.State = "Empty" Gun.Crates = {} diff --git a/lua/weapons/gmod_tool/stools/acfsound.lua b/lua/weapons/gmod_tool/stools/acfsound.lua index 3dff2b141..99b427dc5 100644 --- a/lua/weapons/gmod_tool/stools/acfsound.lua +++ b/lua/weapons/gmod_tool/stools/acfsound.lua @@ -50,6 +50,18 @@ Sounds.acf_engine = { end } +Sounds.acf_gearbox = { + GetSound = function(ent) + return { Sound = ent.SoundPath } + end, + SetSound = function(ent, soundData) + ent.SoundPath = soundData.Sound + end, + ResetSound = function(ent) + ent.SoundPath = ent.DefaultSound + end +} + Sounds.acf_piledriver = { GetSound = function(ent) return { Sound = ent.SoundPath or "" } From d2a781a1b7f5c2772281416577bd93d94aad2181 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Mon, 18 Jan 2021 17:50:15 -0300 Subject: [PATCH 277/279] Improved persisted variable loading process - Fixed persisted data loading process to first attempt to load the value stored on the json file if possible, or just load the default value of each persisted variable. - Changed default value of serverside WorkshopExtras to false. --- lua/acf/base/data_vars/sh_data_vars.lua | 30 +++++++++++++------------ lua/acf/server/persisted_vars.lua | 2 +- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/lua/acf/base/data_vars/sh_data_vars.lua b/lua/acf/base/data_vars/sh_data_vars.lua index dcd5d3ac2..08bb92ba8 100644 --- a/lua/acf/base/data_vars/sh_data_vars.lua +++ b/lua/acf/base/data_vars/sh_data_vars.lua @@ -64,6 +64,7 @@ do -- Data persisting local Values = ACF[Realm .. "Data"] local Folder = "acf/data_vars" local File = "stored.json" + local Storing local function StoreData() local Result = {} @@ -77,21 +78,25 @@ do -- Data persisting } end + Storing = nil + ACF.SaveToJSON(Folder, File, Result, true) end local function UpdateData(Key) if Keys[Key] == nil then return end + if Values[Key] == nil then return end - local Default = Keys[Key] - local Value = Either(Values[Key] ~= nil, Values[Key], Default) + local Value = Values[Key] if Persist[Key] ~= Value then Persist[Key] = Value - if timer.Exists("ACF Store Persisted") then return end + if not Storing then + timer.Create("ACF Store Persisted", 1, 1, StoreData) - timer.Create("ACF Store Persisted", 1, 1, StoreData) + Storing = true + end end end @@ -104,8 +109,6 @@ do -- Data persisting if Default == nil then Default = "nil" end Keys[Key] = Default - - UpdateData(Key) end hook.Add("ACF_On" .. Realm .. "DataUpdate", "ACF Persisted Data", function(_, Key) @@ -118,20 +121,19 @@ do -- Data persisting if Saved then for Key, Stored in pairs(Saved) do - if Keys[Key] == nil then - Keys[Key] = Stored.Default - end + if Keys[Key] == nil then continue end if Stored.Value ~= "nil" then SetFunction(Key, Stored.Value) end end - else - for Key, Default in pairs(Keys) do - local Value = Either(Persist[Key] ~= nil, Persist[Key], Default) + end - SetFunction(Key, Value) - end + -- In case the file doesn't exist or it's missing one of the persisted variables + for Key, Default in pairs(Keys) do + if Persist[Key] ~= nil then continue end + + SetFunction(Key, Default) end hook.Remove("Initialize", "ACF Load Persisted Data") diff --git a/lua/acf/server/persisted_vars.lua b/lua/acf/server/persisted_vars.lua index 074b1fbc7..d3bb0c38a 100644 --- a/lua/acf/server/persisted_vars.lua +++ b/lua/acf/server/persisted_vars.lua @@ -17,7 +17,7 @@ ACF.PersistServerData("AllowFunEnts", true) ACF.PersistServerData("UseKillicons", true) ACF.PersistServerData("ShowFunMenu", true) ACF.PersistServerData("WorkshopContent", true) -ACF.PersistServerData("WorkshopExtras", true) +ACF.PersistServerData("WorkshopExtras", false) -- Debris ACF.PersistServerData("CreateDebris", true) From 9eb171d521be3cc81d369fabe4a556f4f1f74460 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Tue, 19 Jan 2021 01:38:18 -0300 Subject: [PATCH 278/279] Updated GLuaFixer - Updated GLuaFixer to the version 1.17.0. --- .github/workflows/GLuaFixer.yml | 4 ++-- .glualint.json | 9 ++++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/.github/workflows/GLuaFixer.yml b/.github/workflows/GLuaFixer.yml index 3e7767e7d..e74d0564c 100644 --- a/.github/workflows/GLuaFixer.yml +++ b/.github/workflows/GLuaFixer.yml @@ -15,8 +15,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v1 - - name: Download GLuaFixer 1.12.0 - run: curl -o glualint.zip -L https://github.com/FPtje/GLuaFixer/releases/download/1.12.0/glualint-1.12.0-linux.zip + - name: Download GLuaFixer 1.17.0 + run: curl -o glualint.zip -L https://github.com/FPtje/GLuaFixer/releases/download/1.17.0/glualint-1.17.0-linux.zip - name: Extract glualint.zip run: unzip glualint.zip - name: Remove blacklisted folders diff --git a/.glualint.json b/.glualint.json index 3229b3f22..08dd758ef 100644 --- a/.glualint.json +++ b/.glualint.json @@ -3,24 +3,31 @@ "lint_syntaxErrors": true, "lint_syntaxInconsistencies": true, "lint_deprecated": true, + "lint_trailingWhitespace": true, "lint_whitespaceStyle": true, "lint_beginnerMistakes": true, "lint_emptyBlocks": true, "lint_shadowing": true, "lint_gotos": true, "lint_doubleNegations": true, + "lint_redundantIfStatements": true, + "lint_redundantParentheses": true, "lint_duplicateTableKeys": true, "lint_profanity": true, "lint_unusedVars": true, "lint_unusedParameters": true, "lint_unusedLoopVars": true, + "lint_ignoreFiles": [], "prettyprint_spaceAfterParens": false, "prettyprint_spaceAfterBrackets": false, "prettyprint_spaceAfterBraces": false, + "prettyprint_spaceAfterLabel": false, "prettyprint_spaceBeforeComma": false, "prettyprint_spaceAfterComma": true, "prettyprint_semicolons": false, "prettyprint_cStyle": false, - "prettyprint_indentation": "\t" + "prettyprint_rejectInvalidCode": false, + "prettyprint_indentation": "\t", + "log_format": "auto" } \ No newline at end of file From 2e04bf09b0c1b6fded33bb17fef0a5edccf43594 Mon Sep 17 00:00:00 2001 From: TwistedTail <8784231+TwistedTail@users.noreply.github.com> Date: Tue, 19 Jan 2021 01:55:35 -0300 Subject: [PATCH 279/279] Updated code to comply with the new linter - Updated every case on ACF entities where the owner was retrieved with ENT.Owned, using ENT:GetPlayer() now. - Updated every SWEP and tool where SWEP.Owner was used, replaced it with SWEP:GetOwner(). --- lua/entities/acf_base_scalable/init.lua | 4 ++-- lua/entities/acf_base_simple/init.lua | 4 ++-- lua/entities/acf_gun/init.lua | 2 +- lua/weapons/acf_base/cl_init.lua | 20 +++++++++------- lua/weapons/acf_base/init.lua | 32 +++++++++++++++---------- lua/weapons/acf_base/shared.lua | 18 +++++++------- lua/weapons/torch/shared.lua | 6 ++--- 7 files changed, 49 insertions(+), 37 deletions(-) diff --git a/lua/entities/acf_base_scalable/init.lua b/lua/entities/acf_base_scalable/init.lua index b6f53e1ef..2c580785e 100644 --- a/lua/entities/acf_base_scalable/init.lua +++ b/lua/entities/acf_base_scalable/init.lua @@ -174,10 +174,10 @@ do -- Entity user ------------------------------- end function ENT:GetUser(Input) - if not IsValid(Input) then return self.Owner end + if not IsValid(Input) then return self:GetPlayer() end local User = FindUser(self, Input) - return IsValid(User) and User or self.Owner + return IsValid(User) and User or self:GetPlayer() end end --------------------------------------------- diff --git a/lua/entities/acf_base_simple/init.lua b/lua/entities/acf_base_simple/init.lua index b6f53e1ef..2c580785e 100644 --- a/lua/entities/acf_base_simple/init.lua +++ b/lua/entities/acf_base_simple/init.lua @@ -174,10 +174,10 @@ do -- Entity user ------------------------------- end function ENT:GetUser(Input) - if not IsValid(Input) then return self.Owner end + if not IsValid(Input) then return self:GetPlayer() end local User = FindUser(self, Input) - return IsValid(User) and User or self.Owner + return IsValid(User) and User or self:GetPlayer() end end --------------------------------------------- diff --git a/lua/entities/acf_gun/init.lua b/lua/entities/acf_gun/init.lua index c5ed25f57..7abbf96f2 100644 --- a/lua/entities/acf_gun/init.lua +++ b/lua/entities/acf_gun/init.lua @@ -372,7 +372,7 @@ do -- Metamethods -------------------------------- if TraceRes.Hit then local Entity = TraceRes.Entity - if Entity == self.CurrentUser or Entity:CPPIGetOwner() == self.Owner then + if Entity == self.CurrentUser or Entity:CPPIGetOwner() == self:GetPlayer() then self.BarrelFilter[#self.BarrelFilter + 1] = Entity return self:BarrelCheck(Offset) diff --git a/lua/weapons/acf_base/cl_init.lua b/lua/weapons/acf_base/cl_init.lua index 6ff0c9414..e2031cd31 100644 --- a/lua/weapons/acf_base/cl_init.lua +++ b/lua/weapons/acf_base/cl_init.lua @@ -4,11 +4,15 @@ SWEP.Slot = 1 SWEP.SlotPos = 1 SWEP.DrawAmmo = false SWEP.DrawCrosshair = false -SWEP.ScreenFactor = {} -SWEP.ScreenFactor.w = surface.ScreenWidth() -SWEP.ScreenFactor.h = surface.ScreenHeight() -SWEP.FloatingAim = {} -SWEP.FloatingAim.bounds = 0.3 + +SWEP.ScreenFactor = { + w = ScrW(), + h = ScrH(), +} + +SWEP.FloatingAim = { + bounds = 0.3, +} function SWEP:Initialize() self:StartUp() @@ -65,18 +69,18 @@ end function SWEP:ApplyRecoil(Recoil) local RecoilAng = Angle(Recoil * math.Rand(-1, -0.25), Recoil * math.Rand(-0.25, 0.25), 0) - self.Owner:ViewPunch(RecoilAng) + self:GetOwner():ViewPunch(RecoilAng) end --Clientside effect, for Viewmodel stuff function SWEP:MuzzleEffect() self:SendWeaponAnim(ACT_VM_PRIMARYATTACK) - self.Owner:MuzzleFlash() + self:GetOwner():MuzzleFlash() end function SWEP:StartUp() print("Starting Client") - self.FOV = self.Owner:GetFOV() + self.FOV = self:GetOwner():GetFOV() self.ViewModelFOV = self.FOV self.LastIrons = 0 --hook.Add("InputMouseApply","ACF_SWEPFloatingCrosshair",ACF_SWEPFloatingCrosshair) diff --git a/lua/weapons/acf_base/init.lua b/lua/weapons/acf_base/init.lua index c4744bf12..ffd7ae12a 100644 --- a/lua/weapons/acf_base/init.lua +++ b/lua/weapons/acf_base/init.lua @@ -29,7 +29,7 @@ function SWEP:Initialize() end function SWEP:Reload() - if (self:Clip1() < self.Primary.ClipSize and self.Owner:GetAmmoCount(self.Primary.Ammo) > 0) then + if (self:Clip1() < self.Primary.ClipSize and self:GetOwner():GetAmmoCount(self.Primary.Ammo) > 0) then self:EmitSound("weapons/AMR/sniper_reload.wav", 70, 110, ACF.Volume) self:DefaultReload(ACT_VM_RELOAD) end @@ -38,7 +38,7 @@ end function SWEP:Think() if self.OwnerIsNPC then return end - if self.Owner:KeyDown(IN_USE) then + if self:GetOwner():KeyDown(IN_USE) then self:CrateReload() end @@ -47,16 +47,21 @@ end --Server side effect, for external stuff function SWEP:MuzzleEffect() + local Owner = self:GetOwner() + self:EmitSound("weapons/AMR/sniper_fire.wav", nil, nil, ACF.Volume) - self.Owner:MuzzleFlash() - self.Owner:SetAnimation(PLAYER_ATTACK1) + + Owner:MuzzleFlash() + Owner:SetAnimation(PLAYER_ATTACK1) end function SWEP:CrateReload() - local ViewTr = {} - ViewTr.start = self.Owner:GetShootPos() - ViewTr.endpos = self.Owner:GetShootPos() + self.Owner:GetAimVector() * 128 - ViewTr.filter = {self.Owner, self} + local Owner = self:GetOwner() + local ViewTr = { + start = Owner:GetShootPos(), + endpos = Owner:GetShootPos() + Owner:GetAimVector() * 128, + filter = { Owner, self }, + } local ViewRes = util.TraceLine(ViewTr) --Trace to see if it will hit anything @@ -64,13 +69,14 @@ function SWEP:CrateReload() local AmmoEnt = ViewRes.Entity if IsValid(AmmoEnt) and AmmoEnt.Ammo > 0 and AmmoEnt.RoundId == self.Primary.UserData["Id"] then - local CurAmmo = self.Owner:GetAmmoCount(self.Primary.Ammo) + local CurAmmo = Owner:GetAmmoCount(self.Primary.Ammo) local Transfert = math.min(AmmoEnt.Ammo, self.Primary.DefaultClip - CurAmmo) local AmmoType = AmmoTypes[AmmoEnt.AmmoType] AmmoEnt.Ammo = AmmoEnt.Ammo - Transfert - self.Owner:GiveAmmo(Transfert, self.Primary.Ammo) + Owner:GiveAmmo(Transfert, self.Primary.Ammo) + self.Primary.BulletData = AmmoEnt.BulletData self.Primary.RoundData = AmmoType @@ -82,11 +88,13 @@ function SWEP:CrateReload() end function SWEP:StartUp() + local Owner = self:GetOwner() + self:SetDTBool(0, false) self.LastIrons = 0 - if self.Owner then - self.OwnerIsNPC = self.Owner:IsNPC() -- This ought to be better than getting it every time we fire + if Owner then + self.OwnerIsNPC = Owner:IsNPC() -- This ought to be better than getting it every time we fire end end diff --git a/lua/weapons/acf_base/shared.lua b/lua/weapons/acf_base/shared.lua index 308628291..ba92c42da 100644 --- a/lua/weapons/acf_base/shared.lua +++ b/lua/weapons/acf_base/shared.lua @@ -61,8 +61,9 @@ function SWEP:PrimaryAttack() self:ApplyRecoil(math.min(Recoil,50)) self:MuzzleEffect() else - local MuzzlePos = self.Owner:GetShootPos() - local MuzzleVec = self.Owner:GetAimVector() + local Owner = self:GetOwner() + local MuzzlePos = Owner:GetShootPos() + local MuzzleVec = Owner:GetAimVector() local Speed = self.Primary.BulletData["MuzzleVel"] local Modifiers = self:CalculateModifiers() --local Recoil = (self.Primary.BulletData["ProjMass"] * self.Primary.BulletData["MuzzleVel"] + self.Primary.BulletData["PropMass"] * 3000)/self.Weight @@ -74,8 +75,8 @@ function SWEP:PrimaryAttack() self.Primary.BulletData["Pos"] = MuzzlePos self.Primary.BulletData["Flight"] = (MuzzleVec + Inaccuracy):GetNormalized() * Speed * 39.37 + self:GetVelocity() - self.Primary.BulletData["Owner"] = self.Owner - self.Primary.BulletData["Gun"] = self.Owner + self.Primary.BulletData["Owner"] = Owner + self.Primary.BulletData["Gun"] = Owner self.Primary.BulletData["Crate"] = self:EntIndex() self.Primary.RoundData:Create(self, self.Primary.BulletData) @@ -103,21 +104,20 @@ end -- Acuracy/recoil modifiers function SWEP:CalculateModifiers() - + local Owner = self:GetOwner() local modifier = 1 - if self.Owner:KeyDown(IN_FORWARD or IN_BACK or IN_MOVELEFT or IN_MOVERIGHT) then + if Owner:KeyDown(IN_FORWARD or IN_BACK or IN_MOVELEFT or IN_MOVERIGHT) then modifier = modifier * 2 end - if not self.Owner:IsOnGround() then + if not Owner:IsOnGround() then modifier = modifier * 2 --You can't be jumping and crouching at the same time, so return here return modifier end - if self.Owner:Crouching() then + if Owner:Crouching() then modifier = modifier * 0.5 end return modifier - end diff --git a/lua/weapons/torch/shared.lua b/lua/weapons/torch/shared.lua index 85dbb0644..9c9a6a9c2 100644 --- a/lua/weapons/torch/shared.lua +++ b/lua/weapons/torch/shared.lua @@ -75,7 +75,7 @@ function SWEP:Think() if CLIENT then return end local Health, MaxHealth, Armor, MaxArmor = 0, 0, 0, 0 - local Trace = self.Owner:GetEyeTrace() + local Trace = self:GetOwner():GetEyeTrace() local Entity = Trace.Entity self.LastDistance = Trace.StartPos:DistToSqr(Trace.HitPos) @@ -121,7 +121,7 @@ function SWEP:PrimaryAttack() local Entity = self.LastEntity local Trace = self.LastTrace - local Owner = self.Owner + local Owner = self:GetOwner() if ACF.Check(Entity) then if Entity:IsPlayer() or Entity:IsNPC() then @@ -181,7 +181,7 @@ function SWEP:SecondaryAttack() local Entity = self.LastEntity local Trace = self.LastTrace - local Owner = self.Owner + local Owner = self:GetOwner() if ACF.Check(Entity) then local HitRes = {}