diff --git a/lua/acf/server/sv_pointshandling.lua b/lua/acf/server/sv_pointshandling.lua index 0f78a0f2..05df05c3 100644 --- a/lua/acf/server/sv_pointshandling.lua +++ b/lua/acf/server/sv_pointshandling.lua @@ -189,6 +189,8 @@ local function ACE_CalcNonAmmoSubsystem(ents, subsystem, minDetailPts) pts = tonumber(ACE.CrewSeatPointCost) or tonumber((ACE.PointCostConfig or {}).CrewSeatFlat) or 250 + elseif subsystem == "Firepower" and cls == "acf_gun" then + pts = ACE_GetGunFirepowerPoints(ent) else pts = ACE_GetEntPoints(ent) end diff --git a/lua/acf/shared/sh_ace_functions.lua b/lua/acf/shared/sh_ace_functions.lua index 28a25c55..9836dc44 100644 --- a/lua/acf/shared/sh_ace_functions.lua +++ b/lua/acf/shared/sh_ace_functions.lua @@ -1259,20 +1259,91 @@ function ACE_GetAmmoThreatWeight(bdata) return threatFactor end --- Compute sustained rounds per second for a gun/rack. -function ACE_GetEntRps(ent) - local reload = ent.ReloadTime - if reload and reload > 0 then return 1 / reload end - - local rof = ent.RateOfFire - if rof and rof > 0 then return rof / 60 end - - return 0 -end - --- Collect per-gun RPS totals and rack entities for a contraption. -function ACE_BuildGunRpsAndRacks(ents) - local gunRpsById, racks = {}, {} +-- Compute a gun's configured sustained RPS from its current setup. +function ACE_GetGunConfiguredRps(ent, rofLimit) + if not ACE_IsEnt(ent) or ent:GetClass() ~= "acf_gun" then return 0 end + + local bdata = ent.BulletData or {} + local roundVolume = tonumber(bdata.RoundVolume) + if not roundVolume or roundVolume <= 0 then + local reload = tonumber(ent.ReloadTime) + if reload and reload > 0 then return 1 / reload end + + local rof = tonumber(ent.RateOfFire) + if rof and rof > 0 then return rof / 60 end + + return 0 + end + + local adj = tonumber(bdata.LengthAdj) or 1 + local fireRateModifier = (tonumber(ent.RoFmod) or 1) * (tonumber(ent.PGRoFmod) or 1) + + local crate = bdata.Crate and Entity(bdata.Crate) or nil + if ACE_IsEnt(crate) and crate.RoFMul then + fireRateModifier = fireRateModifier * (crate.RoFMul + 1) + end + + local defaultReloadTime = ((math.max(roundVolume, (tonumber(ent.MinLengthBonus) or 0) / adj) / 500) ^ 0.60) * fireRateModifier + local lowestReloadTime = defaultReloadTime + local maxRof = tonumber(ent.maxrof) or 0 + rofLimit = tonumber(rofLimit) or 0 + + if rofLimit > 0 and maxRof > 0 then + maxRof = math.min(maxRof, rofLimit) + elseif rofLimit > 0 then + maxRof = rofLimit + end + + if maxRof > 0 then + lowestReloadTime = 60 / maxRof + end + + local reloadTime = math.max(defaultReloadTime, lowestReloadTime) + + if reloadTime <= 0 then return 0 end + + return 1 / reloadTime +end + +-- Compute sustained rounds per second for a gun/rack. +function ACE_GetEntRps(ent) + if ACE_IsEnt(ent) and ent:GetClass() == "acf_gun" then + return ACE_GetGunConfiguredRps(ent, ent.ROFLimit) + end + + local reload = ent.ReloadTime + if reload and reload > 0 then return 1 / reload end + + local rof = ent.RateOfFire + if rof and rof > 0 then return rof / 60 end + + return 0 +end + +-- Scale a gun's firepower points by its current ROF threat relative to its base ROF. +function ACE_GetGunFirepowerPoints(ent) + if not ACE_IsEnt(ent) or ent:GetClass() ~= "acf_gun" then + return tonumber(ent and ent.ACEPoints) or 0 + end + + local basePoints = tonumber(ent.ACEPoints) or 0 + if basePoints <= 0 then return 0 end + + local currentRps = ACE_GetEntRps(ent) + local baseRps = ACE_GetGunConfiguredRps(ent, 0) + if currentRps <= 0 or baseRps <= 0 then return basePoints end + + local cfg = ACE.AmmoCostConfig or {} + local currentThreat = ACE_GetRofThreatFactor(currentRps, cfg) + local baseThreat = ACE_GetRofThreatFactor(baseRps, cfg) + if currentThreat <= 0 or baseThreat <= 0 then return basePoints end + + return basePoints * math.min(currentThreat / baseThreat, 1) +end + +-- Collect per-gun RPS totals and rack entities for a contraption. +function ACE_BuildGunRpsAndRacks(ents) + local gunRpsById, racks = {}, {} for _, ent in ipairs(ents) do if ACE_IsEnt(ent) then diff --git a/lua/entities/acf_gun/init.lua b/lua/entities/acf_gun/init.lua index cb44c218..ed26dbc8 100644 --- a/lua/entities/acf_gun/init.lua +++ b/lua/entities/acf_gun/init.lua @@ -5,13 +5,23 @@ include("shared.lua") local GunClasses = ACF.Classes.GunClass -local GunTable = ACF.Weapons.Guns - ---The distances these ents would have if its caliber was 10mm. Incremented by caliber size. -local CrewLinkDistBase = 200 -local AmmoLinkDistBase = 512 - -function ENT:Initialize() +local GunTable = ACF.Weapons.Guns + +--The distances these ents would have if its caliber was 10mm. Incremented by caliber size. +local CrewLinkDistBase = 200 +local AmmoLinkDistBase = 512 + +local function MarkGunPointStateDirty(Gun) + if not ACE_MarkSubsystemDirty then return end + + local Contraption = Gun.GetContraption and Gun:GetContraption() or nil + if not Contraption then return end + + ACE_MarkSubsystemDirty(Contraption, "Firepower") + ACE_MarkSubsystemDirty(Contraption, "Ammo") +end + +function ENT:Initialize() self.ReloadTime = 1 @@ -555,16 +565,21 @@ function ENT:TriggerInput(iname, value) self.BulletData.FuseLength = 0 self.OverrideFuse = false end - elseif iname == "ROFLimit" then - -- Set the rate of fire limit if value is greater than 0 - local lowestROF = 0.1 - if value > 0 then - self.ROFLimit = math.max(value, lowestROF) -- Limit the rate of fire - else - self.ROFLimit = 0 - end - end -end + elseif iname == "ROFLimit" then + -- Set the rate of fire limit if value is greater than 0 + local lowestROF = 0.1 + local oldLimit = self.ROFLimit + if value > 0 then + self.ROFLimit = math.max(value, lowestROF) -- Limit the rate of fire + else + self.ROFLimit = 0 + end + + if oldLimit ~= self.ROFLimit then + MarkGunPointStateDirty(self) + end + end +end