1453 lines
49 KiB
Lua
1453 lines
49 KiB
Lua
function SWEP:GetReloadTime(base)
|
||
local vm = self:GetVM()
|
||
local valfunc = base and self.GetBaseValue or self.GetValue
|
||
|
||
if !valfunc(self, "ShotgunReload") then
|
||
local seq = vm:LookupSequence(self:TranslateSequence("reload"))
|
||
local basetime = vm:SequenceDuration(seq)
|
||
local mult = valfunc(self, "ReloadTimeMult") / TacRP.ConVars["mult_reloadspeed"]:GetFloat()
|
||
|
||
return basetime * mult
|
||
else
|
||
local seq1 = vm:LookupSequence(self:TranslateSequence("reload_start"))
|
||
-- local seq2 = vm:LookupSequence(self:TranslateSequence("reload"))
|
||
local seq3 = vm:LookupSequence(self:TranslateSequence("reload_finish"))
|
||
|
||
local time_1 = vm:SequenceDuration(seq1)
|
||
local time_2 = valfunc(self, "ShotgunUpInTime") --vm:SequenceDuration(seq2)
|
||
local time_3 = vm:SequenceDuration(seq3)
|
||
|
||
local mult = valfunc(self, "ReloadTimeMult") / TacRP.ConVars["mult_reloadspeed"]:GetFloat()
|
||
|
||
local basetime = time_1 + (time_2 * valfunc(self, "ClipSize")) + time_3
|
||
|
||
if valfunc(self, "ShotgunThreeload") then
|
||
basetime = time_1 + (time_2 * valfunc(self, "ClipSize") / 3) + time_3
|
||
end
|
||
|
||
return basetime * mult
|
||
end
|
||
end
|
||
|
||
function SWEP:GetDeployTime(base)
|
||
local vm = self:GetVM()
|
||
local valfunc = base and self.GetBaseValue or self.GetValue
|
||
|
||
local anim = "deploy"
|
||
local mult = valfunc(self, "DeployTimeMult")
|
||
|
||
if valfunc(self, "TryUnholster") then
|
||
anim = "unholster"
|
||
mult = mult * valfunc(self, "UnholsterTimeMult")
|
||
end
|
||
|
||
local seq = vm:LookupSequence(self:TranslateSequence(anim))
|
||
local basetime = vm:SequenceDuration(seq)
|
||
|
||
return basetime * mult
|
||
end
|
||
|
||
function SWEP:CalcHolsterTime(base)
|
||
local vm = self:GetVM()
|
||
local valfunc = base and self.GetBaseValue or self.GetValue
|
||
|
||
local anim = "holster"
|
||
if valfunc(self, "NoHolsterAnimation") then
|
||
anim = "deploy"
|
||
end
|
||
|
||
local mult = valfunc(self, "HolsterTimeMult")
|
||
|
||
local seq = vm:LookupSequence(self:TranslateSequence(anim))
|
||
local basetime = vm:SequenceDuration(seq)
|
||
|
||
return basetime * mult
|
||
end
|
||
|
||
function SWEP:GetMuzzleVelocity(base)
|
||
local valfunc = base and self.GetBaseValue or self.GetValue
|
||
|
||
local basetime = valfunc(self, "MuzzleVelocity")
|
||
|
||
if valfunc(self, "ShootEnt") then
|
||
basetime = valfunc(self, "ShootEntForce")
|
||
end
|
||
|
||
return math.ceil(0.3048 * basetime / 12)
|
||
end
|
||
|
||
-- function SWEP:GetMeanShotsToFail(base)
|
||
-- local valfunc = base and self.GetBaseValue or self.GetValue
|
||
-- local shootchance = valfunc(self, "ShootChance")
|
||
|
||
-- return 1 / (1 - shootchance)
|
||
-- end
|
||
|
||
function SWEP:GetBestFiremode(base)
|
||
local valfunc = base and self.GetBaseValue or self.GetValue
|
||
|
||
if valfunc(self, "Firemodes") then
|
||
local bfm, bfm_i
|
||
for k, v in pairs(valfunc(self, "Firemodes")) do
|
||
if !bfm or v == 2 or (bfm <= 1 and v < bfm) then
|
||
bfm = v
|
||
bfm_i = k
|
||
end
|
||
end
|
||
return bfm, bfm_i
|
||
else
|
||
return valfunc(self, "Firemode") or 0, 1
|
||
end
|
||
end
|
||
|
||
local hitgroups = {
|
||
[HITGROUP_HEAD] = 0.1,
|
||
[HITGROUP_CHEST] = 0.2,
|
||
[HITGROUP_STOMACH] = 0.3,
|
||
[HITGROUP_LEFTARM] = 0.2,
|
||
[HITGROUP_LEFTLEG] = 0.2,
|
||
}
|
||
|
||
local mssd_scoring = {
|
||
[HITGROUP_HEAD] = {0.15, 0.5, {1, 0.6, 0.3, 0.15, 0.05}},
|
||
[HITGROUP_CHEST] = {0.25, 0.75, {1, 0.75, 0.4, 0.2, 0.1}},
|
||
[HITGROUP_STOMACH] = {0.25, 0.8, {1, 0.8, 0.5, 0.25, 0.15, 0.05}},
|
||
[HITGROUP_LEFTARM] = {0.2, 0.5, {1, 0.85, 0.6, 0.3, 0.2, 0.1, 0.05}},
|
||
[HITGROUP_LEFTLEG] = {0.15, 0.5, {1, 0.9, 0.7, 0.4, 0.25, 0.15, 0.1}},
|
||
}
|
||
|
||
local mssd_scoring_ttt = {
|
||
[HITGROUP_HEAD] = {0.25, 0.5, {1, 0.75, 0.50, 0.25, 0.15, 0.10, 0.05, 0.025}},
|
||
[HITGROUP_CHEST] = {0.25, 0.75, {1, 0.90, 0.75, 0.55, 0.45, 0.35, 0.25, 0.15, 0.10, 0.05}},
|
||
[HITGROUP_STOMACH] = {0.25, 1, {1, 1.00, 0.90, 0.80, 0.60, 0.40, 0.30, 0.20, 0.15, 0.10, 0.05}},
|
||
[HITGROUP_LEFTARM] = {0.15, 1, {1, 1.00, 0.80, 0.70, 0.50, 0.30, 0.25, 0.15, 0.10, 0.05, 0.025}},
|
||
[HITGROUP_LEFTLEG] = {0.10, 1, {1, 1.00, 0.90, 0.75, 0.60, 0.50, 0.40, 0.30, 0.25, 0.20, 0.15, 0.10, 0.05}},
|
||
}
|
||
|
||
SWEP.StatGroupGrades = {
|
||
{88, "S", Color(230, 60, 60)},
|
||
{75, "A", Color(230, 180, 60)},
|
||
{60, "B", Color(230, 230, 60)},
|
||
{40, "C", Color(60, 230, 60)},
|
||
{20, "D", Color(60, 60, 230)},
|
||
{00, "E", Color(145, 94, 146)},
|
||
{ -math.huge, "F", Color(150, 150, 150)},
|
||
}
|
||
SWEP.StatGroups = {
|
||
{
|
||
Name = "rating.lethality",
|
||
Description = "rating.lethality.desc",
|
||
RatingFunction = function(self, base)
|
||
-- local score = 0
|
||
local valfunc = base and self.GetBaseValue or self.GetValue
|
||
|
||
local bfm = self:GetBestFiremode(base)
|
||
local rrpm = self:GetRPM(base, bfm)
|
||
local pbd = valfunc(self, "PostBurstDelay")
|
||
local ttt = TacRP.GetBalanceMode() == TacRP.BALANCE_TTT
|
||
local pve = TacRP.GetBalanceMode() == TacRP.BALANCE_PVE
|
||
local health = pve and 50 or 100
|
||
|
||
local num = valfunc(self, "Num")
|
||
local bdm = self:GetBodyDamageMultipliers(base)
|
||
local bdm_add = 0
|
||
for k, v in pairs(hitgroups) do
|
||
bdm_add = bdm_add + bdm[k] * v
|
||
end
|
||
|
||
local d_max, d_min = valfunc(self, "Damage_Max"), valfunc(self, "Damage_Min")
|
||
local explosive_damage = valfunc(self, "ExplosiveDamage")
|
||
|
||
d_max = d_max + explosive_damage
|
||
d_min = d_min + explosive_damage
|
||
|
||
local dmg_max = math.max(d_max, d_min)
|
||
local dmg_avg = dmg_max * bdm_add --Lerp(0.2, math.max(d_max, d_min), math.min(d_max, d_min)) * bdm_add
|
||
|
||
-- max single shot damage
|
||
local mssd = 0
|
||
for k, v in pairs(ttt and mssd_scoring_ttt or mssd_scoring) do
|
||
local stk = math.ceil(health / (dmg_max * (bdm[k] or 1) * (1 + (num - 1) * v[2])))
|
||
mssd = mssd + (v[3][stk] or 0) * v[1]
|
||
-- print(bdm[k], stk, (mssd_scoring[k][stk] or 0))
|
||
end
|
||
if pve then
|
||
mssd = mssd ^ 1
|
||
elseif ttt then
|
||
mssd = mssd ^ 0.75
|
||
end
|
||
|
||
-- avg time to kill
|
||
local stk = math.ceil(health / (dmg_avg * num))
|
||
local ttk_s
|
||
if stk == 1 then
|
||
ttk_s = math.Clamp(rrpm / 120, 0, 1) ^ 0.75
|
||
else
|
||
local ttk = (stk - 1) * (60 / rrpm)
|
||
if bfm < 0 then
|
||
ttk = ttk + math.floor(ttk / -bfm) * pbd
|
||
end
|
||
if pve then
|
||
ttk_s = math.Clamp(1 - ttk / 2, 0, 1) ^ 2
|
||
elseif ttt then
|
||
ttk_s = math.Clamp(1 - ttk / 3, 0, 1) ^ 3
|
||
else
|
||
ttk_s = math.Clamp(1 - ttk / 1.5, 0, 1) ^ 1.5
|
||
end
|
||
end
|
||
|
||
local scores = {mssd, ttk_s}
|
||
table.sort(scores)
|
||
|
||
return scores[2] * 75 + scores[1] * 25
|
||
|
||
end,
|
||
},
|
||
{
|
||
Name = "rating.suppression",
|
||
Description = "rating.suppression.desc",
|
||
RatingFunction = function(self, base)
|
||
local valfunc = base and self.GetBaseValue or self.GetValue
|
||
|
||
local bfm = self:GetBestFiremode(base)
|
||
local rrpm = self:GetRPM(base, bfm)
|
||
local erpm = rrpm
|
||
local pbd = valfunc(self, "PostBurstDelay")
|
||
local ttt = TacRP.GetBalanceMode() == TacRP.BALANCE_TTT
|
||
local pve = TacRP.GetBalanceMode() == TacRP.BALANCE_PVE
|
||
|
||
if bfm == 1 then
|
||
erpm = math.min(rrpm, 600) + math.max(rrpm - 600, 0) ^ 0.75 -- you can't click *that* fast
|
||
elseif bfm < 0 then
|
||
erpm = 60 / ((1 / (rrpm / 60)) + (pbd / -bfm))
|
||
end
|
||
|
||
local num = valfunc(self, "Num")
|
||
local bdm = self:GetBodyDamageMultipliers(base)
|
||
local bdm_add = 0
|
||
for k, v in pairs(hitgroups) do
|
||
bdm_add = bdm_add + bdm[k] * v
|
||
end
|
||
|
||
local d_max, d_min = valfunc(self, "Damage_Max"), valfunc(self, "Damage_Min")
|
||
local explosive_damage = valfunc(self, "ExplosiveDamage")
|
||
local explosive_radius = valfunc(self, "ExplosiveRadius")
|
||
|
||
explosive_damage = explosive_damage * explosive_radius / 64 * 2
|
||
|
||
d_max = d_max + explosive_damage
|
||
d_min = d_min + explosive_damage
|
||
|
||
-- local dmg_max = math.max(d_max, d_min)
|
||
local dmg_avg = Lerp(0.2, math.max(d_max, d_min), math.min(d_max, d_min)) * bdm_add
|
||
|
||
-- raw dps
|
||
local dps = dmg_avg * num * erpm / 60
|
||
-- average dps over time
|
||
local dot = dmg_avg * num / (60 / erpm + self:GetReloadTime(base) / (valfunc(self, "ClipSize") / valfunc(self, "AmmoPerShot")))
|
||
local dps_s, dot_s
|
||
if pve then
|
||
dps_s = math.Clamp((dps - 12.5) / 150, 0, 1)
|
||
dot_s = math.Clamp((dot - 5) / 100, 0, 1) ^ 0.9
|
||
elseif ttt then
|
||
dps_s = math.Clamp((dps - 25) / 200, 0, 1)
|
||
dot_s = math.Clamp((dot - 10) / 100, 0, 1)
|
||
else
|
||
dps_s = math.Clamp((dps - 50) / 400, 0, 1) ^ 0.9
|
||
dot_s = math.Clamp((dot - 20) / 200, 0, 1) ^ 0.9
|
||
end
|
||
|
||
local scores = {dps_s, dot_s}
|
||
table.sort(scores)
|
||
|
||
return scores[2] * 70 + scores[1] * 30
|
||
end,
|
||
},
|
||
{
|
||
Name = "rating.range",
|
||
Description = "rating.range.desc",
|
||
RatingFunction = function(self, base)
|
||
local score = 0
|
||
local valfunc = base and self.GetBaseValue or self.GetValue
|
||
|
||
local d_max, d_min = valfunc(self, "Damage_Max"), valfunc(self, "Damage_Min")
|
||
local r_min, r_max = self:GetMinMaxRange(base)
|
||
local ttt = TacRP.GetBalanceMode() == TacRP.BALANCE_TTT
|
||
|
||
local r_mid = r_min + (r_max - r_min) / 2
|
||
local d_diff = math.abs(d_max - d_min) / math.max(d_max, d_min)
|
||
if d_max > d_min then
|
||
-- [100] 50% damage falloff range
|
||
score = score + math.Clamp((r_mid - 500) / (ttt and 2500 or 3000), 0, 1) ^ 0.75 * 100
|
||
|
||
-- [0] damage reduction from range
|
||
-- score = score + math.Clamp(1 - d_diff, 0, 1) ^ 1.5 * 0
|
||
else
|
||
-- [40] free points
|
||
-- [40] 50% damage rampup range
|
||
score = score + 40 + math.Clamp(r_mid / (ttt and 1500 or 3000), 0, 1) * 40
|
||
-- print(r_mid, math.Clamp(1 - r_mid / 5000, 0, 1))
|
||
|
||
-- [20] damage reduction from range
|
||
score = score + math.Clamp(1 - d_diff, 0, 1) * 20
|
||
end
|
||
|
||
return score
|
||
end,
|
||
},
|
||
{
|
||
Name = "rating.precision",
|
||
Description = "rating.precision.desc",
|
||
RatingFunction = function(self, base)
|
||
local score = 0
|
||
local valfunc = base and self.GetBaseValue or self.GetValue
|
||
|
||
local bfm = self:GetBestFiremode(base)
|
||
local rpm = valfunc(self, "RPM")
|
||
|
||
local num = valfunc(self, "Num")
|
||
local spread = valfunc(self, "Spread")
|
||
local rps = valfunc(self, "RecoilPerShot")
|
||
local rsp = valfunc(self, "RecoilSpreadPenalty")
|
||
local rrt = self:GetRecoilResetTime(base)
|
||
local rdr = valfunc(self, "RecoilDissipationRate")
|
||
local dt = math.max(0, -rrt)
|
||
local rbs = dt * rdr -- amount of recoil we can recover between shots even if fired ASAP
|
||
|
||
if self:UseAltRecoil() then
|
||
local min = 0.0001
|
||
local tgt = 0.015
|
||
if num > 2 then tgt = 0.04 end
|
||
score = math.Clamp(1 - (spread - min) / tgt, 0, 1) * 100
|
||
else
|
||
-- [50] base spread
|
||
local min = 0.001
|
||
local tgt = 0.015
|
||
if num > 2 then tgt = 0.04 end
|
||
score = score + math.Clamp(1 - (spread - min) / tgt, 0, 1) * 50
|
||
|
||
local fss = valfunc(self, "RecoilFirstShotMult") * rps
|
||
-- score = score + math.Clamp(1 - (spread + fss * rsp - rbs) / tgt, 0, 1) * 25
|
||
|
||
-- [50] spread over 0.3s (or one burst)
|
||
local shots = math.min(math.ceil(rpm / 60 * 0.3), math.floor(self:GetBaseValue("ClipSize") * 0.5))
|
||
if bfm < 0 then
|
||
shots = -bfm
|
||
end
|
||
if rbs <= fss then
|
||
local so1 = (fss - rbs + shots * (rps - rbs)) * rsp
|
||
score = score + math.Clamp(1 - so1 / 0.03, 0, 1) ^ 1.25 * 50
|
||
else
|
||
-- delay is so long we always get first shot
|
||
score = score + 50
|
||
end
|
||
end
|
||
|
||
-- recoil reset time
|
||
-- score = score + math.Clamp(1 - math.max(0, rrt - delay) / 0.25, 0, 1) * 10
|
||
|
||
return score
|
||
end,
|
||
},
|
||
{
|
||
Name = "rating.control",
|
||
Description = "rating.control.desc",
|
||
RatingFunction = function(self, base)
|
||
local score = 0
|
||
local valfunc = base and self.GetBaseValue or self.GetValue
|
||
|
||
local bfm = self:GetBestFiremode(base)
|
||
local erpm = valfunc(self, "RPM")
|
||
local pbd = valfunc(self, "AutoBurst") and valfunc(self, "PostBurstDelay") or math.max(0.15, valfunc(self, "PostBurstDelay"))
|
||
if bfm == 1 then
|
||
erpm = math.min(erpm, 600) -- you can't click *that* fast
|
||
elseif bfm < 0 then
|
||
erpm = 60 / ((1 / (erpm / 60)) + (pbd / -bfm))
|
||
end
|
||
local rps = valfunc(self, "RecoilPerShot")
|
||
local rsp = valfunc(self, "RecoilSpreadPenalty")
|
||
local rrt = self:GetRecoilResetTime(base)
|
||
local rdr = valfunc(self, "RecoilDissipationRate")
|
||
local dt = math.max(0, -rrt)
|
||
local rbs = dt * rdr -- amount of recoil we can recover between shots even if fired ASAP
|
||
local fss = valfunc(self, "RecoilFirstShotMult")
|
||
local rmax = valfunc(self, "RecoilMaximum")
|
||
local rk = math.abs(valfunc(self, "RecoilKick"))
|
||
|
||
-- local rrec_s = math.Clamp(rdr / rps / rmax / 5, 0, 1) ^ 0.9
|
||
-- local mspr_s = math.Clamp(1 - rmax * rsp / 0.04, 0, 1)
|
||
-- score = score + mspr_s * 20
|
||
|
||
-- [50] recoil kick over 1s
|
||
local score_rk1 = 50
|
||
local shots = math.ceil(erpm / 60 * 1)
|
||
score = score + math.Clamp(1 - (rk * shots * rrt - 3) / 12, 0, 1) * score_rk1
|
||
-- print("rk1", rk * shots * rrt, math.Clamp(1 - rk * shots * rrt / 15, 0, 1) * score_rk1)
|
||
|
||
-- [50] bloom over 1s
|
||
local score_sg = 50
|
||
if bfm < 0 then
|
||
local rbb = math.max(0, pbd - rrt) * rdr -- recovery between bursts
|
||
local rpb = -bfm * rps - (-bfm - 1) * rbs - rbb -- recoil per full burst
|
||
score = score + math.Clamp(1 - (rpb * rsp * 2) / 0.03, 0, 1) ^ 1.5 * score_sg
|
||
-- print("spb", rpb * rsp, math.Clamp(1 - (rpb * rsp * 3) / 0.04, 0, 1) ^ 2 * score_sg)
|
||
else
|
||
-- local sg = math.min(shots, math.ceil(rmax / rsp))
|
||
local sot = math.min(rmax, fss - rbs + (shots - 1) * (rps - rbs)) * rsp
|
||
-- print("sot", sot, math.Clamp(1 - (sot - 0.01) / 0.03, 0, 1) ^ 0.75 * score_sg)
|
||
score = score + math.Clamp(1 - (sot - 0.01) / 0.02, 0, 1) ^ 1.5 * score_sg
|
||
end
|
||
|
||
return score
|
||
end,
|
||
},
|
||
{
|
||
Name = "rating.handling",
|
||
Description = "rating.handling.desc",
|
||
RatingFunction = function(self, base)
|
||
local score = 0
|
||
|
||
-- [40] sprint
|
||
score = score + math.Clamp(1 - (self:GetSprintToFireTime(base) - 0.15) / 0.5, 0, 1) * 40
|
||
|
||
-- [45] ads
|
||
score = score + math.Clamp(1 - (self:GetAimDownSightsTime(base) - 0.15) / 0.5, 0, 1) * 45
|
||
|
||
-- [15] deploy
|
||
score = score + math.Clamp(1 - (self:GetDeployTime(base) - 0.5) / 1.5, 0, 1) * 15
|
||
|
||
return score
|
||
end,
|
||
},
|
||
{
|
||
Name = "rating.maneuvering",
|
||
Description = "rating.maneuvering.desc",
|
||
RatingFunction = function(self, base)
|
||
local score = 0
|
||
local valfunc = base and self.GetBaseValue or self.GetValue
|
||
|
||
-- [40] free aim + sway (if both are disabled, score goes to other 2)
|
||
local bonus = 40
|
||
local freeaim_s = 1
|
||
if TacRP.ConVars["freeaim"]:GetBool() then
|
||
if valfunc(self, "FreeAim") then
|
||
freeaim_s = math.Clamp(1 - (valfunc(self, "FreeAimMaxAngle") - 2) / 8, 0, 1) ^ 0.8
|
||
end
|
||
bonus = 0
|
||
end
|
||
local sway_s = 1
|
||
if TacRP.ConVars["sway"]:GetBool() then
|
||
sway_s = math.Clamp(1 - (valfunc(self, "Sway") - 0.75) / 2.25, 0, 1)
|
||
bonus = 0
|
||
end
|
||
if bonus == 0 then
|
||
score = score + math.min(freeaim_s, sway_s) * 20 + math.max(freeaim_s, sway_s) * 20
|
||
end
|
||
|
||
-- local diff = valfunc(self, "HipFireSpreadPenalty") / math.Clamp(self:GetBaseValue("Spread"), 0.015, 0.03)
|
||
local hipspread = valfunc(self, "Spread") + valfunc(self, "HipFireSpreadPenalty") + valfunc(self, "MoveSpreadPenalty")
|
||
|
||
-- [0] peeking
|
||
-- score = score + math.Clamp(1 - (hipspread * valfunc(self, "PeekPenaltyFraction") - 0.01) / 0.015, 0, 1) * (10 + bonus * 0.25)
|
||
|
||
-- [50] hip spread + spread
|
||
score = score + math.Clamp(1 - (hipspread - 0.02) / 0.05, 0, 1) * (50 + bonus * 0.75)
|
||
|
||
-- [10] mid-air spread
|
||
score = score + math.Clamp(1 - (valfunc(self, "MidAirSpreadPenalty") ) / 0.1, 0, 1) * (10 + bonus * 0.25)
|
||
|
||
return score
|
||
end,
|
||
},
|
||
{
|
||
Name = "rating.mobility",
|
||
Description = "rating.mobility.desc",
|
||
RatingFunction = function(self, base)
|
||
local score = 0
|
||
local valfunc = base and self.GetBaseValue or self.GetValue
|
||
local ttt = TacRP.GetBalanceMode() == TacRP.BALANCE_TTT
|
||
|
||
if ttt then
|
||
-- [30] move
|
||
score = score + math.Clamp((valfunc(self, "MoveSpeedMult") - 0.6) / 0.4, 0, 1) * 30
|
||
|
||
-- [25] sighted
|
||
score = score + math.Clamp((valfunc(self, "SightedSpeedMult") - 0.2) / 0.8, 0, 1) * 25
|
||
|
||
-- [25] shooting
|
||
score = score + math.Clamp((valfunc(self, "ShootingSpeedMult") - 0.2) / 0.8, 0, 1) * 25
|
||
|
||
-- [20] reload
|
||
score = score + math.Clamp((valfunc(self, "ReloadSpeedMult") - 0.4) / 0.6, 0, 1) * 20
|
||
else
|
||
-- [50] move
|
||
score = score + math.Clamp((math.min(1, valfunc(self, "MoveSpeedMult")) - 0.6) / 0.4, 0, 1) ^ 2 * 50
|
||
|
||
-- [25] sighted
|
||
score = score + math.Clamp((math.min(1, valfunc(self, "SightedSpeedMult")) - 0.3) / 0.7, 0, 1) * 25
|
||
|
||
-- [25] shooting
|
||
score = score + math.Clamp((math.min(1, valfunc(self, "ShootingSpeedMult")) - 0.4) / 0.6, 0, 1) * 25
|
||
|
||
-- [-20] reload
|
||
score = score - math.Clamp(1 - (math.min(1, valfunc(self, "ReloadSpeedMult")) - 0.4) / 0.6, 0, 1) * 20
|
||
end
|
||
|
||
|
||
return score
|
||
end,
|
||
},
|
||
{
|
||
Name = "rating.stability",
|
||
Description = "rating.stability.desc",
|
||
RatingFunction = function(self, base)
|
||
local score = 0
|
||
local valfunc = base and self.GetBaseValue or self.GetValue
|
||
|
||
-- [40] sway
|
||
score = score + math.Clamp(1 - valfunc(self, "Sway") / 2.5, 0, 1) ^ 0.8 * 40
|
||
|
||
-- [60] sighted sway
|
||
score = score + math.Clamp(1 - valfunc(self, "ScopedSway") / 1, 0, 1) ^ 1.5 * 60
|
||
|
||
-- blindfire sway
|
||
-- score = score + math.Clamp(1 - valfunc(self, "BlindFireSway") / 2, 0, 1) * 10
|
||
|
||
return score
|
||
end,
|
||
},
|
||
}
|
||
|
||
SWEP.StatDisplay = {
|
||
-- {
|
||
-- Name = "",
|
||
-- Value = "",
|
||
-- LowerIsBetter = false,
|
||
-- AggregateFunction = nil,
|
||
-- Unit = ""
|
||
-- }
|
||
{
|
||
Name = "spacer.damage",
|
||
Description = "spacer.damage.desc",
|
||
Spacer = true,
|
||
},
|
||
{
|
||
Name = "stat.damage",
|
||
Description = "stat.damage.desc",
|
||
Value = "Damage_Max",
|
||
AggregateFunction = function(self, base, val)
|
||
if !(self:IsDamageConstant(false) and self:IsDamageConstant(true)) then return end
|
||
-- local valfunc = base and self.GetBaseValue or self.GetValue
|
||
-- return math.Round(val * valfunc(self, "Num"), 0)
|
||
return math.floor(val)
|
||
end,
|
||
},
|
||
{
|
||
Name = "stat.damage_max",
|
||
Description = "stat.damage_max.desc",
|
||
Value = "Damage_Max",
|
||
AggregateFunction = function(self, base, val)
|
||
if self:IsDamageConstant(false) and self:IsDamageConstant(true) then return end
|
||
-- local valfunc = base and self.GetBaseValue or self.GetValue
|
||
-- return math.Round(val * valfunc(self, "Num"), 0)
|
||
return math.floor(val)
|
||
end,
|
||
},
|
||
{
|
||
Name = "stat.damage_min",
|
||
Description = "stat.damage_min.desc",
|
||
Value = "Damage_Min",
|
||
AggregateFunction = function(self, base, val)
|
||
if self:IsDamageConstant(false) and self:IsDamageConstant(true) then return end
|
||
-- local valfunc = base and self.GetBaseValue or self.GetValue
|
||
-- return math.Round(val * valfunc(self, "Num"), 0)
|
||
return math.floor(val)
|
||
end,
|
||
},
|
||
{
|
||
Name = "stat.explosivedamage",
|
||
Description = "stat.explosivedamage.desc",
|
||
Value = "ExplosiveDamage",
|
||
DefaultValue = 0,
|
||
},
|
||
{
|
||
Name = "stat.explosiveradius",
|
||
Description = "stat.explosiveradius.desc",
|
||
Value = "ExplosiveRadius",
|
||
DefaultValue = 0,
|
||
DisplayFunction = function(self, base, val)
|
||
return self:RangeUnitize(val)
|
||
end,
|
||
},
|
||
{
|
||
Name = "stat.damagemultnpc",
|
||
Description = "stat.damagemultnpc.desc",
|
||
Value = "DamageMultNPC",
|
||
DefaultValue = 1,
|
||
AggregateFunction = function(self, base, val)
|
||
return math.Round(val * 100, 1)
|
||
end,
|
||
Unit = "%",
|
||
},
|
||
{
|
||
Name = "stat.num",
|
||
Description = "stat.num.desc",
|
||
Value = "Num",
|
||
DefaultValue = 1,
|
||
},
|
||
{
|
||
Name = "stat.range_min",
|
||
Description = "stat.range_min.desc",
|
||
Value = "Range_Min",
|
||
AggregateFunction = function(self, base, val)
|
||
if self:IsDamageConstant(base) then return end
|
||
return val
|
||
end,
|
||
DisplayFunction = function(self, base, val)
|
||
if val == 0 then return "∞" end
|
||
return self:RangeUnitize(val)
|
||
end,
|
||
},
|
||
{
|
||
Name = "stat.range_max",
|
||
Description = "stat.range_max.desc",
|
||
Value = "Range_Max",
|
||
AggregateFunction = function(self, base, val)
|
||
if self:IsDamageConstant(base) then return end
|
||
return val
|
||
end,
|
||
DisplayFunction = function(self, base, val)
|
||
if val == 0 then return "∞" end
|
||
return self:RangeUnitize(val)
|
||
end,
|
||
},
|
||
{
|
||
Name = "stat.raw_dps",
|
||
Description = "stat.raw_dps.desc",
|
||
Value = "",
|
||
AggregateFunction = function(self, base, val)
|
||
local valfunc = base and self.GetBaseValue or self.GetValue
|
||
|
||
local bfm = self:GetBestFiremode(base)
|
||
local rrpm = self:GetRPM(base, bfm)
|
||
local erpm = rrpm
|
||
local pbd = valfunc(self, "PostBurstDelay")
|
||
|
||
if bfm < 0 then
|
||
erpm = 60 / ((1 / (rrpm / 60)) + (pbd / -bfm))
|
||
end
|
||
|
||
local num = valfunc(self, "Num")
|
||
local dmg = math.max(valfunc(self, "Damage_Max"), valfunc(self, "Damage_Min"))
|
||
dmg = dmg + valfunc(self, "ExplosiveDamage")
|
||
|
||
return math.Round(dmg * num * erpm / 60, 1)
|
||
end,
|
||
},
|
||
{
|
||
Name = "stat.min_ttk",
|
||
Description = "stat.min_ttk.desc",
|
||
Value = "",
|
||
Unit = "unit.second",
|
||
LowerIsBetter = true,
|
||
AggregateFunction = function(self, base, val)
|
||
local valfunc = base and self.GetBaseValue or self.GetValue
|
||
|
||
local bfm = self:GetBestFiremode(base)
|
||
local rpm = self:GetRPM(base, bfm)
|
||
|
||
local num = valfunc(self, "Num")
|
||
local dmg = math.max(valfunc(self, "Damage_Max"), valfunc(self, "Damage_Min"))
|
||
local stk = math.ceil(100 / (dmg * num))
|
||
local ttk = stk * (60 / rpm)
|
||
|
||
if bfm < 0 and stk > -bfm then
|
||
local pbd = valfunc(self, "PostBurstDelay")
|
||
ttk = ttk + pbd * math.floor(stk / -bfm)
|
||
end
|
||
return math.Round(ttk, 2)
|
||
end,
|
||
},
|
||
{
|
||
Name = "spacer.action",
|
||
Description = "spacer.action.desc",
|
||
Spacer = true,
|
||
},
|
||
{
|
||
Name = "stat.clipsize",
|
||
Description = "stat.clipsize.desc",
|
||
Value = "ClipSize",
|
||
},
|
||
{
|
||
Name = "stat.ammopershot",
|
||
Description = "stat.ammopershot.desc",
|
||
Value = "AmmoPerShot",
|
||
DefaultValue = 1,
|
||
},
|
||
{
|
||
Name = "stat.rpm",
|
||
Description = "stat.rpm.desc",
|
||
Value = "RPM",
|
||
Unit = "rpm",
|
||
AggregateFunction = function(self, base, val)
|
||
return math.Round(val, 0)
|
||
end,
|
||
},
|
||
{
|
||
Name = "stat.rpm_burst",
|
||
Description = "stat.rpm_burst.desc",
|
||
Value = "RPMMultBurst",
|
||
Unit = "rpm",
|
||
AggregateFunction = function(self, base, val)
|
||
if !self:HasFiremode(-1) then return end
|
||
local valfunc = base and self.GetBaseValue or self.GetValue
|
||
return math.Round(val * valfunc(self, "RPM"), 0)
|
||
end,
|
||
DefaultValue = 1,
|
||
},
|
||
{
|
||
Name = "stat.rpm_burst_peak",
|
||
Description = "stat.rpm_burst_peak.desc",
|
||
Value = "PostBurstDelay",
|
||
Unit = "rpm",
|
||
AggregateFunction = function(self, base, val)
|
||
if !self:HasFiremode(-1) then return end
|
||
local valfunc = base and self.GetBaseValue or self.GetValue
|
||
local cfm = self:GetFiremodeBurstLength()
|
||
local delay = 60 / ( valfunc(self, "RPM") * valfunc(self, "RPMMultBurst") ) -- delay
|
||
local nerd = 0
|
||
nerd = nerd + (delay * (cfm-1))
|
||
nerd = nerd + math.max( delay, valfunc(self, "PostBurstDelay") )
|
||
nerd = nerd / cfm
|
||
nerd = 60 / nerd
|
||
return math.Round( nerd )
|
||
end,
|
||
--DefaultValue = 0,
|
||
},
|
||
{
|
||
Name = "stat.rpm_semi",
|
||
Description = "stat.rpm_semi.desc",
|
||
Value = "RPMMultSemi",
|
||
Unit = "rpm",
|
||
AggregateFunction = function(self, base, val)
|
||
if !self:HasFiremode(1) then return end
|
||
local valfunc = base and self.GetBaseValue or self.GetValue
|
||
return math.Round(val * valfunc(self, "RPM"), 0)
|
||
end,
|
||
DefaultValue = 1,
|
||
},
|
||
{
|
||
Name = "stat.shotstofail",
|
||
Description = "stat.shotstofail.desc",
|
||
AggregateFunction = function(self, base, val)
|
||
return math.Round(1 / self:GetJamChance(base), 0)
|
||
end,
|
||
DisplayFunction = function(self, base, val)
|
||
if val == 0 then return "∞" end
|
||
return math.Round(1 / self:GetJamChance(base), 0)
|
||
end,
|
||
DefaultValue = 0,
|
||
Value = "JamFactor",
|
||
},
|
||
{
|
||
Name = "stat.postburstdelay",
|
||
Description = "stat.postburstdelay.desc",
|
||
Value = "PostBurstDelay",
|
||
AggregateFunction = function(self, base, val)
|
||
if !self:HasFiremode(-1) then return end
|
||
return math.Round(val, 2)
|
||
end,
|
||
Unit = "unit.second",
|
||
LowerIsBetter = true,
|
||
DefaultValue = 0,
|
||
},
|
||
{
|
||
Name = "stat.firemode",
|
||
Description = "stat.firemode.desc",
|
||
AggregateFunction = function(self, base, val)
|
||
if !val then
|
||
val = {base and self:GetTable()["Firemode"] or self:GetValue("Firemode")}
|
||
end
|
||
if #val == 1 then
|
||
if val[1] == 2 then
|
||
return "Auto"
|
||
elseif val[1] == 1 then
|
||
return "Semi"
|
||
elseif val[1] < 0 then
|
||
return (-val[1]) .. "-Burst"
|
||
end
|
||
else
|
||
local tbl = table.Copy(val)
|
||
table.sort(tbl, function(a, b)
|
||
if a == 2 then
|
||
return b == 2
|
||
elseif b == 2 then
|
||
return a != 2
|
||
end
|
||
return math.abs(a) <= math.abs(b)
|
||
end)
|
||
local str = "S-"
|
||
for i = 1, #tbl do
|
||
str = str .. (tbl[i] == 2 and "F" or math.abs(tbl[i])) .. (i < #tbl and "-" or "")
|
||
end
|
||
return str
|
||
end
|
||
return table.ToString(val)
|
||
end,
|
||
BetterFunction = function(self, old, new)
|
||
if !old then
|
||
old = {self:GetBaseValue("Firemode")}
|
||
end
|
||
if !new then
|
||
new = {self:GetValue("Firemode")}
|
||
end
|
||
local oldbest, newbest = 0, 0
|
||
for i = 1, #old do
|
||
local v = math.abs(old[i])
|
||
if math.abs(old[i]) > oldbest or old[i] == 2 then
|
||
oldbest = (old[i] == 2 and math.huge) or v
|
||
end
|
||
end
|
||
for i = 1, #new do
|
||
local v = math.abs(new[i])
|
||
if v > newbest or new[i] == 2 then
|
||
newbest = (new[i] == 2 and math.huge) or v
|
||
end
|
||
end
|
||
if oldbest == newbest then
|
||
return #old != #new , #old < #new
|
||
else
|
||
return true, oldbest < newbest
|
||
end
|
||
end,
|
||
DifferenceFunction = function(self, orig, value)
|
||
if !orig then
|
||
orig = {self:GetBaseValue("Firemode")}
|
||
end
|
||
if !value then
|
||
value = {self:GetValue("Firemode")}
|
||
end
|
||
local old_best = self:GetBestFiremode(true)
|
||
local new_best = self:GetBestFiremode(false)
|
||
if old_best == new_best then return end
|
||
if new_best == 2 then
|
||
return "+Auto"
|
||
elseif old_best == 2 then
|
||
return "-Auto"
|
||
elseif new_best < 0 then
|
||
return "+Burst"
|
||
end
|
||
end,
|
||
Value = "Firemodes",
|
||
-- HideIfSame = true,
|
||
},
|
||
{
|
||
Name = "stat.reloadtime",
|
||
Description = "stat.reloadtime.desc",
|
||
AggregateFunction = function(self, base, val)
|
||
return math.Round(self:GetReloadTime(base), 2)
|
||
end,
|
||
Value = "ReloadTimeMult",
|
||
LowerIsBetter = true,
|
||
Unit = "unit.second",
|
||
},
|
||
{
|
||
Name = "spacer.ballistics",
|
||
Description = "spacer.ballistics.desc",
|
||
Spacer = true,
|
||
},
|
||
{
|
||
Name = "stat.spread",
|
||
Description = "stat.spread.desc",
|
||
AggregateFunction = function(self, base, val)
|
||
return math.Round(math.deg(val) * 60, 1)
|
||
end,
|
||
Unit = "′",
|
||
Value = "Spread",
|
||
LowerIsBetter = true,
|
||
},
|
||
{
|
||
Name = "stat.muzzlevelocity",
|
||
Description = "stat.muzzlevelocity.desc",
|
||
AggregateFunction = function(self, base, val)
|
||
return math.Round(self:GetMuzzleVelocity(base), 2)
|
||
end,
|
||
ConVarCheck = "tacrp_physbullet",
|
||
Value = "MuzzleVelocity",
|
||
LowerIsBetter = false,
|
||
Unit = "unit.mps",
|
||
},
|
||
{
|
||
Name = "stat.penetration",
|
||
Description = "stat.penetration.desc",
|
||
Value = "Penetration",
|
||
Unit = "\""
|
||
},
|
||
{
|
||
Name = "stat.armorpenetration",
|
||
Description = "stat.armorpenetration.desc",
|
||
Value = "ArmorPenetration",
|
||
AggregateFunction = function(self, base, val)
|
||
return math.max(math.Round(val * 100, 1), 0)
|
||
end,
|
||
Unit = "%",
|
||
},
|
||
{
|
||
Name = "stat.armorbonus",
|
||
Description = "stat.armorbonus.desc",
|
||
Value = "ArmorBonus",
|
||
AggregateFunction = function(self, base, val)
|
||
return math.Round(val * 1, 2)
|
||
end,
|
||
Unit = "x",
|
||
},
|
||
{
|
||
Name = "spacer.recoilbloom",
|
||
Description = "spacer.recoilbloom.desc",
|
||
Spacer = true,
|
||
},
|
||
{
|
||
Name = "stat.recoilkick",
|
||
Description = "stat.recoilkick.desc",
|
||
Value = "RecoilKick",
|
||
LowerIsBetter = true,
|
||
},
|
||
{
|
||
Name = "stat.recoilstability",
|
||
Description = "stat.recoilstability.desc",
|
||
Value = "RecoilStability",
|
||
AggregateFunction = function(self, base, val)
|
||
return math.Clamp(math.Round(val * 100), 0, 90)
|
||
end,
|
||
Unit = "%",
|
||
LowerIsBetter = false,
|
||
},
|
||
-- For use when bloom is modifying spread. (default)
|
||
{
|
||
Name = "stat.recoilspread",
|
||
Description = "stat.recoilspread.desc",
|
||
AggregateFunction = function(self, base, val)
|
||
if self:UseAltRecoil(base) then return end
|
||
return math.Round(math.deg(val) * 60, 1)
|
||
end,
|
||
Unit = "′",
|
||
Value = "RecoilSpreadPenalty",
|
||
LowerIsBetter = true,
|
||
-- ConVarCheck = "tacrp_altrecoil",
|
||
-- ConVarInvert = true,
|
||
},
|
||
-- For use when in "Bloom Modifies Recoil"
|
||
{
|
||
Name = "stat.recoilspread2",
|
||
Description = "stat.recoilspread2.desc",
|
||
AggregateFunction = function(self, base, val)
|
||
if !self:UseAltRecoil(base) then return end
|
||
return math.Round(val * (base and self:GetBaseValue("RecoilAltMultiplier") or self:GetValue("RecoilAltMultiplier")), 2)
|
||
end,
|
||
Unit = nil,
|
||
Value = "RecoilSpreadPenalty",
|
||
LowerIsBetter = true,
|
||
-- ConVarCheck = "tacrp_altrecoil",
|
||
-- ConVarInvert = false,
|
||
},
|
||
{
|
||
Name = "stat.recoildissipation",
|
||
Description = "stat.recoildissipation.desc",
|
||
AggregateFunction = function(self, base, val)
|
||
return math.Round(val, 2)
|
||
--return math.Round(math.deg(val * (base and self:GetTable().RecoilSpreadPenalty or self:GetValue("RecoilSpreadPenalty"))), 1)
|
||
end,
|
||
Unit = "unit.persecond",
|
||
Value = "RecoilDissipationRate",
|
||
},
|
||
{
|
||
Name = "stat.recoilresettime",
|
||
Description = "stat.recoilresettime.desc",
|
||
Value = "RecoilResetTime",
|
||
LowerIsBetter = true,
|
||
Unit = "s",
|
||
},
|
||
{
|
||
Name = "stat.recoilmaximum",
|
||
Description = "stat.recoilmaximum.desc",
|
||
Value = "RecoilMaximum",
|
||
LowerIsBetter = true,
|
||
},
|
||
{
|
||
Name = "stat.recoilfirstshot",
|
||
Description = "stat.recoilfirstshot.desc",
|
||
Value = "RecoilFirstShotMult",
|
||
AggregateFunction = function(self, base, val)
|
||
return math.Round(val * (base and self:GetBaseValue("RecoilPerShot") or self:GetValue("RecoilPerShot")), 2)
|
||
end,
|
||
DefaultValue = 1,
|
||
LowerIsBetter = true,
|
||
},
|
||
{
|
||
Name = "stat.recoilpershot",
|
||
Description = "stat.recoilpershot.desc",
|
||
AggregateFunction = function(self, base, val)
|
||
return math.Round(val, 2)
|
||
end,
|
||
Unit = "x",
|
||
Value = "RecoilPerShot",
|
||
HideIfSame = true,
|
||
LowerIsBetter = true,
|
||
},
|
||
{
|
||
Name = "stat.recoilcrouch",
|
||
Description = "stat.recoilcrouch.desc",
|
||
AggregateFunction = function(self, base, val)
|
||
return math.min(100, math.Round(val * 100, 0))
|
||
end,
|
||
Unit = "%",
|
||
Value = "RecoilMultCrouch",
|
||
LowerIsBetter = true,
|
||
-- HideIfSame = true,
|
||
},
|
||
{
|
||
Name = "stat.recoilburst",
|
||
Description = "stat.recoilburst.desc",
|
||
Value = "RecoilMultBurst",
|
||
Unit = "%",
|
||
AggregateFunction = function(self, base, val)
|
||
return math.min(100, math.Round(val * 100, 0))
|
||
end,
|
||
LowerIsBetter = true,
|
||
DefaultValue = 1,
|
||
},
|
||
{
|
||
Name = "stat.recoilsemi",
|
||
Description = "stat.recoilsemi.desc",
|
||
Value = "RecoilMultSemi",
|
||
Unit = "%",
|
||
AggregateFunction = function(self, base, val)
|
||
return math.min(100, math.Round(val * 100, 0))
|
||
end,
|
||
LowerIsBetter = true,
|
||
DefaultValue = 1,
|
||
},
|
||
{
|
||
Name = "spacer.mobility",
|
||
Description = "spacer.mobility.desc",
|
||
Spacer = true,
|
||
},
|
||
{
|
||
Name = "stat.movespeed",
|
||
Description = "stat.movespeed.desc",
|
||
AggregateFunction = function(self, base, val)
|
||
return math.min(100, math.Round(val * 100, 0))
|
||
end,
|
||
Unit = "%",
|
||
Value = "MoveSpeedMult",
|
||
ConVarCheck = "tacrp_penalty_move"
|
||
},
|
||
{
|
||
Name = "stat.shootingspeed",
|
||
Description = "stat.shootingspeed.desc",
|
||
AggregateFunction = function(self, base, val)
|
||
return math.min(100, math.Round(val * 100, 0))
|
||
end,
|
||
Unit = "%",
|
||
Value = "ShootingSpeedMult",
|
||
ConVarCheck = "tacrp_penalty_firing"
|
||
},
|
||
{
|
||
Name = "stat.sightedspeed",
|
||
Description = "stat.sightedspeed.desc",
|
||
AggregateFunction = function(self, base, val)
|
||
return math.min(100, math.Round(val * 100, 0))
|
||
end,
|
||
Unit = "%",
|
||
Value = "SightedSpeedMult",
|
||
ValueCheck = "Scope",
|
||
ConVarCheck = "tacrp_penalty_aiming"
|
||
},
|
||
{
|
||
Name = "stat.reloadspeed",
|
||
Description = "stat.reloadspeed.desc",
|
||
AggregateFunction = function(self, base, val)
|
||
return math.min(100, math.Round(val * 100, 0))
|
||
end,
|
||
Unit = "%",
|
||
Value = "ReloadSpeedMult",
|
||
DefaultValue = 1,
|
||
ConVarCheck = "tacrp_penalty_reload"
|
||
},
|
||
{
|
||
Name = "stat.meleespeed",
|
||
Description = "stat.meleespeed.desc",
|
||
AggregateFunction = function(self, base, val)
|
||
return math.min(100, math.Round(val * 100, 0))
|
||
end,
|
||
Unit = "%",
|
||
Value = "MeleeSpeedMult",
|
||
DefaultValue = 1,
|
||
ConVarCheck = "tacrp_penalty_melee"
|
||
},
|
||
{
|
||
Name = "spacer.handling",
|
||
Description = "spacer.handling.desc",
|
||
Spacer = true,
|
||
},
|
||
{
|
||
Name = "stat.sprinttofire",
|
||
Description = "stat.sprinttofire.desc",
|
||
Value = "SprintToFireTime",
|
||
AggregateFunction = function(self, base, val)
|
||
return math.Round(self:GetSprintToFireTime(base), 3)
|
||
end,
|
||
Unit = "unit.second",
|
||
LowerIsBetter = true,
|
||
},
|
||
{
|
||
Name = "stat.aimdownsights",
|
||
Description = "stat.aimdownsights.desc",
|
||
Value = "AimDownSightsTime",
|
||
AggregateFunction = function(self, base, val)
|
||
return math.Round(self:GetAimDownSightsTime(base), 3)
|
||
end,
|
||
Unit = "unit.second",
|
||
LowerIsBetter = true,
|
||
ValueCheck = "Scope",
|
||
},
|
||
{
|
||
Name = "stat.deploytime",
|
||
Description = "stat.deploytime.desc",
|
||
AggregateFunction = function(self, base, val)
|
||
return math.Round(self:GetDeployTime(base), 2)
|
||
end,
|
||
Value = "DeployTimeMult",
|
||
LowerIsBetter = true,
|
||
-- HideIfSame = true,
|
||
Unit = "unit.second",
|
||
},
|
||
{
|
||
Name = "stat.holstertime",
|
||
Description = "stat.holstertime.desc",
|
||
AggregateFunction = function(self, base, val)
|
||
return math.Round(self:CalcHolsterTime(base), 2)
|
||
end,
|
||
Value = "HolsterTimeMult",
|
||
LowerIsBetter = true,
|
||
Unit = "unit.second",
|
||
ConVarCheck = "tacrp_holster",
|
||
},
|
||
{
|
||
Name = "spacer.maneuvering",
|
||
Description = "spacer.maneuvering.desc",
|
||
Spacer = true,
|
||
},
|
||
{
|
||
Name = "stat.freeaimangle",
|
||
Description = "stat.freeaimangle.desc",
|
||
Unit = "°",
|
||
Value = "FreeAimMaxAngle",
|
||
AggregateFunction = function(self, base, val)
|
||
return math.max(0, math.Round(val, 1))
|
||
end,
|
||
LowerIsBetter = true,
|
||
-- HideIfSame = true,
|
||
ConVarCheck = "tacrp_freeaim",
|
||
},
|
||
{
|
||
Name = "stat.midairspread",
|
||
Description = "stat.midairspread.desc",
|
||
AggregateFunction = function(self, base, val)
|
||
return math.Round(math.deg(val), 1)
|
||
end,
|
||
Unit = "°",
|
||
Value = "MidAirSpreadPenalty",
|
||
LowerIsBetter = true,
|
||
-- HideIfSame = true,
|
||
},
|
||
{
|
||
Name = "stat.hipfirespread",
|
||
Description = "stat.hipfirespread.desc",
|
||
AggregateFunction = function(self, base, val)
|
||
return math.Round(math.deg(val), 1)
|
||
end,
|
||
Unit = "°",
|
||
Value = "HipFireSpreadPenalty",
|
||
LowerIsBetter = true,
|
||
-- HideIfSame = true,
|
||
},
|
||
{
|
||
Name = "spacer.sway",
|
||
Description = "spacer.sway.desc",
|
||
Spacer = true,
|
||
ConVarCheck = "tacrp_sway",
|
||
},
|
||
{
|
||
Name = "stat.sway",
|
||
Description = "stat.sway.desc",
|
||
|
||
Value = "Sway",
|
||
LowerIsBetter = true,
|
||
ConVarCheck = "tacrp_sway",
|
||
},
|
||
{
|
||
Name = "stat.scopedsway",
|
||
Description = "stat.scopedsway.desc",
|
||
Value = "ScopedSway",
|
||
LowerIsBetter = true,
|
||
ConVarCheck = "tacrp_sway",
|
||
ValueCheck = "Scope",
|
||
},
|
||
{
|
||
Name = "stat.swaycrouch",
|
||
Description = "stat.swaycrouch.desc",
|
||
Value = "SwayCrouchMult",
|
||
AggregateFunction = function(self, base, val)
|
||
return math.min(100, math.Round(val * 100, 0))
|
||
end,
|
||
Unit = "%",
|
||
LowerIsBetter = true,
|
||
-- HideIfSame = true,
|
||
ConVarCheck = "tacrp_sway",
|
||
},
|
||
{
|
||
Name = "spacer.misc",
|
||
Description = "spacer.misc.desc",
|
||
Spacer = true,
|
||
},
|
||
{
|
||
Name = "stat.meleedamage",
|
||
Description = "stat.meleedamage.desc",
|
||
Value = "MeleeDamage",
|
||
HideIfSame = false,
|
||
},
|
||
{
|
||
Name = "stat.peekpenalty",
|
||
Description = "stat.peekpenalty.desc",
|
||
Value = "PeekPenaltyFraction",
|
||
AggregateFunction = function(self, base, val)
|
||
return math.min(100, math.Round(val * 100, 0))
|
||
end,
|
||
Unit = "%",
|
||
LowerIsBetter = true,
|
||
},
|
||
{
|
||
Name = "stat.quickscope",
|
||
Description = "stat.quickscope.desc",
|
||
Value = "QuickScopeSpreadPenalty",
|
||
AggregateFunction = function(self, base, val)
|
||
return math.Round(math.deg(val) * 60, 1)
|
||
end,
|
||
Unit = "′",
|
||
LowerIsBetter = true,
|
||
},
|
||
{
|
||
Name = "stat.vol_shoot",
|
||
Description = "stat.vol_shoot.desc",
|
||
Value = "Vol_Shoot",
|
||
AggregateFunction = function(self, base, val)
|
||
return math.Round(val, 1)
|
||
end,
|
||
Unit = "dB",
|
||
LowerIsBetter = true,
|
||
},
|
||
}
|
||
|
||
SWEP.StatGroupsMelee = {
|
||
{
|
||
Name = "stat.damage",
|
||
Description = "stat.damage.desc_melee",
|
||
RatingFunction = function(self, base)
|
||
local valfunc = base and self.GetBaseValue or self.GetValue
|
||
return Lerp((valfunc(self, "MeleeDamage") - 10) / 50, 0, 100)
|
||
end,
|
||
},
|
||
{
|
||
Name = "rating.meleeattacktime",
|
||
Description = "rating.meleeattacktime.desc",
|
||
RatingFunction = function(self, base)
|
||
local valfunc = base and self.GetBaseValue or self.GetValue
|
||
|
||
return Lerp(1 - (valfunc(self, "MeleeAttackTime") - 0.15) / 0.55, 0, 100)
|
||
end,
|
||
},
|
||
-- {
|
||
-- Name = "Reach",
|
||
-- Description = "Attack distance.",
|
||
-- RatingFunction = function(self, base)
|
||
-- local valfunc = base and self.GetBaseValue or self.GetValue
|
||
|
||
-- return Lerp((valfunc(self, "MeleeRange") - 64) / 128, 0, 100)
|
||
-- end,
|
||
-- },
|
||
{
|
||
Name = "stat.meleeperkstr",
|
||
Description = "stat.meleeperkstr.desc",
|
||
RatingFunction = function(self, base)
|
||
local valfunc = base and self.GetBaseValue or self.GetValue
|
||
return Lerp(valfunc(self, "MeleePerkStr"), 0, 100)
|
||
|
||
end,
|
||
},
|
||
{
|
||
Name = "stat.meleeperkagi",
|
||
Description = "stat.meleeperkagi.desc",
|
||
RatingFunction = function(self, base)
|
||
local valfunc = base and self.GetBaseValue or self.GetValue
|
||
return Lerp(valfunc(self, "MeleePerkAgi"), 0, 100)
|
||
end,
|
||
},
|
||
{
|
||
Name = "stat.meleeperkint",
|
||
Description = "stat.meleeperkint.desc",
|
||
RatingFunction = function(self, base)
|
||
local valfunc = base and self.GetBaseValue or self.GetValue
|
||
return Lerp(valfunc(self, "MeleePerkInt"), 0, 100)
|
||
end,
|
||
},
|
||
}
|
||
|
||
SWEP.StatDisplayMelee = {
|
||
{
|
||
Name = "stat.damage",
|
||
Description = "stat.damage.desc_melee",
|
||
Value = "MeleeDamage",
|
||
AggregateFunction = function(self, base, val)
|
||
return math.floor(val * self:GetConfigDamageMultiplier())
|
||
end,
|
||
},
|
||
{
|
||
Name = "stat.meleeattacktime",
|
||
Description = "stat.meleeattacktime.desc",
|
||
Value = "MeleeAttackTime",
|
||
Unit = "unit.second",
|
||
LowerIsBetter = true,
|
||
},
|
||
{
|
||
Name = "stat.meleeattackmisstime",
|
||
Description = "stat.meleeattackmisstime.desc",
|
||
Value = "MeleeAttackMissTime",
|
||
Unit = "unit.second",
|
||
LowerIsBetter = true,
|
||
},
|
||
{
|
||
Name = "stat.meleerange",
|
||
Description = "stat.meleerange.desc",
|
||
Value = "MeleeRange",
|
||
DisplayFunction = function(self, base, val)
|
||
return self:RangeUnitize(val)
|
||
end,
|
||
},
|
||
{
|
||
Name = "stat.meleedelay",
|
||
Description = "stat.meleedelay.desc",
|
||
Value = "MeleeDelay",
|
||
Unit = "unit.second",
|
||
LowerIsBetter = true,
|
||
},
|
||
{
|
||
Name = "stat.meleeperkstr",
|
||
Description = "stat.meleeperkstr.desc",
|
||
Value = "MeleePerkStr",
|
||
AggregateFunction = function(self, base, val)
|
||
return math.floor(val * 100)
|
||
end,
|
||
},
|
||
{
|
||
Name = "stat.meleeperkagi",
|
||
Description = "stat.meleeperkagi.desc",
|
||
Value = "MeleePerkAgi",
|
||
AggregateFunction = function(self, base, val)
|
||
return math.floor(val * 100)
|
||
end,
|
||
},
|
||
{
|
||
Name = "stat.meleeperkint",
|
||
Description = "stat.meleeperkint.desc",
|
||
Value = "MeleePerkInt",
|
||
AggregateFunction = function(self, base, val)
|
||
return math.floor(val * 100)
|
||
end,
|
||
},
|
||
|
||
|
||
{
|
||
Name = "stat.melee2damage",
|
||
Description = "stat.melee2damage.desc",
|
||
Value = "Melee2Damage",
|
||
ValueCheck = "HeavyAttack",
|
||
AggregateFunction = function(self, base, val)
|
||
return math.Round(self:GetHeavyAttackDamage(base) * self:GetConfigDamageMultiplier())
|
||
end,
|
||
},
|
||
{
|
||
Name = "stat.melee2attacktime",
|
||
Description = "stat.melee2attacktime.desc",
|
||
Value = "Melee2AttackTime",
|
||
ValueCheck = "HeavyAttack",
|
||
AggregateFunction = function(self, base, val)
|
||
return math.Round(self:GetHeavyAttackTime(false, base), 2)
|
||
end,
|
||
Unit = "unit.second",
|
||
LowerIsBetter = true,
|
||
},
|
||
{
|
||
Name = "stat.melee2attackmisstime",
|
||
Description = "stat.melee2attackmisstime.desc",
|
||
Value = "Melee2AttackMissTime",
|
||
ValueCheck = "HeavyAttack",
|
||
AggregateFunction = function(self, base, val)
|
||
return math.Round(self:GetHeavyAttackTime(true, base), 2)
|
||
end,
|
||
Unit = "unit.second",
|
||
LowerIsBetter = true,
|
||
},
|
||
{
|
||
Name = "stat.meleethrowdamage",
|
||
Description = "stat.meleethrowdamage.desc",
|
||
Value = "MeleeDamage",
|
||
ValueCheck = "ThrowAttack",
|
||
AggregateFunction = function(self, base, val)
|
||
return math.floor(val * self:GetMeleePerkDamage(base) * self:GetConfigDamageMultiplier())
|
||
end,
|
||
},
|
||
{
|
||
Name = "stat.meleethrowvelocity",
|
||
Description = "stat.meleethrowvelocity.desc",
|
||
Value = "MeleeThrowForce",
|
||
ValueCheck = "ThrowAttack",
|
||
AggregateFunction = function(self, base, val)
|
||
return math.Round(0.3048 * self:GetMeleePerkVelocity(base) / 12, 1)
|
||
end,
|
||
Unit = "unit.mps",
|
||
},
|
||
{
|
||
Name = "stat.meleethrowtime",
|
||
Description = "stat.meleethrowtime.desc",
|
||
Value = "MeleeAttackTime",
|
||
ValueCheck = "ThrowAttack",
|
||
AggregateFunction = function(self, base, val)
|
||
return math.Round(val * 3 * self:GetMeleePerkCooldown(base), 2)
|
||
end,
|
||
Unit = "unit.second",
|
||
LowerIsBetter = true,
|
||
},
|
||
|
||
{
|
||
Name = "stat.lifesteal",
|
||
Description = "stat.lifesteal.desc",
|
||
Value = "Lifesteal",
|
||
DefaultValue = 0,
|
||
AggregateFunction = function(self, base, val)
|
||
return math.Round(val * 100, 2)
|
||
end,
|
||
Unit = "%",
|
||
},
|
||
{
|
||
Name = "stat.damagecharge",
|
||
Description = "stat.damagecharge.desc",
|
||
Value = "DamageCharge",
|
||
DefaultValue = 0,
|
||
AggregateFunction = function(self, base, val)
|
||
return math.Round(val * 10000, 2)
|
||
end,
|
||
Unit = "%",
|
||
},
|
||
}
|