--[[
Version 2.3
Last updated 15/1/2026
Calculator made & maintained by Firewatch (navihurricane) <-- Blud who forced a DR rework after making a build with 96% DR
DR has a softcap
Damage Taken here refers to the difference between your HP before hit and your HP after hit (as that's the only way we can measure it)
Let x be the sum_of_all_selected_DR_source
TotalDR = [1 - 2 ^ (x/-75)] * 100
DamageTaken = baseDMG * 2 ^ (x/-75)
ADDITIVE DR = sum_of_all_selected_DR_source, this isn't your actual damage resistance
ACTUAL DR = Refer to TotalDR formula, this is your actual damage resistance converted over using 100% as maximum
From Laz:
Every 75 DR you have from any source (vet, savage, crc, tower specs, arch buffs, whatever, add it all up)
will cut damage recieved in half
hasArmor needs to be set to false if you want to calculate Enemy Plate Carrier & Matrix aswell
]]
local input = {
baseDmg = 20,
baseHP = 100, -- please add up hp buffs yourself its basic math i will cry if you tell me to make this easier
-------------------------------------
-- Check if you want to include armor
hasArmor = false,
-------------------------------------
-- TOWER
die_hard = false,
fury_road = false,
hasFaceOff = false,
old_boy = false,
hasMatrix = false, -- Must enable hasArmor
-- AVENGER
guardian_of_exile = false,
guardian_of_exile_allies = 0, -- Number of allies (0-5)
-- ARCHANGEL
resistantnanites_self = false,
resistantnanites_others = false,
command_surge = false,
adrenaline_shot = false,
-------------------------------------
-- CONTRACTOR
ARK_corps_guardian = false,
merc_vet_agent = false,
-- ARCHITECT
hasFort6B = false,
-- FRONTLINER
savage = false,
-- JUGGERNAUT
hasVET = false,
crc = false,
hasEnemyPlateCarrier = false, -- Must enable hasArmor
-- UTILITARIAN
arm_implants = false,
-- WILDCARD
foak_hearts = false
-------------------------------------
}
local function roundBankers(num)
if math.abs(num - math.floor(num)) < 0.0001 then
return math.floor(num)
end
local integer, fractional = math.modf(num)
fractional = math.abs(fractional)
if math.abs(fractional - 0.5) < 0.0001 then
return integer + 1
end
if fractional > 0.5001 then
return integer + 1
else
return integer
end
end
function calculateDamageResistance(input)
local baseDmg = input.baseDmg or 20
local baseHP = input.baseHP or 100
local totalDR = 0
local hasFaceOff = input.hasFaceOff or false
local command_surge = input.command_surge or false
-- Sum all DR sources for front
if input.die_hard then totalDR = totalDR + 15 end
if input.old_boy then totalDR = totalDR + 30 end
if input.crc then totalDR = totalDR + 30 end
if input.adrenaline_shot then totalDR = totalDR + 30 end
if input.resistantnanites_self then totalDR = totalDR + 20 end
if input.overwatch_on_standby then totalDR = totalDR - 15 end
if input.ARK_corps_guardian then totalDR = totalDR + 25 end
if input.merc_vet_agent then totalDR = totalDR + 20 end
if input.fury_road then totalDR = totalDR + 15 end
if input.savage then totalDR = totalDR + 25 end
if input.resistantnanites_others then totalDR = totalDR + 20 end
if input.berserker_essence then totalDR = totalDR + 30 end
if input.arm_implants then totalDR = totalDR + 20 end
if input.hasVET then totalDR = totalDR + 25 end
if input.hasMatrix and input.hasArmor then totalDR = totalDR + 15 end
if input.hasFort6B then totalDR = totalDR + 75 end
if input.foak_hearts then totalDR = totalDR + 44 end
local armor_multi = 1
if input.hasArmor then
if input.hasEnemyPlateCarrier then
armor_multi = 75
else
local log2 = math.log(0.67) / math.log(2)
armor_multi = -75 * log2 -- around 43.33252
end
totalDR = totalDR + armor_multi
end
if input.guardian_of_exile then
local alliesSheltered = math.min(input.guardian_of_exile_allies or 0, 5)
totalDR = totalDR + (0.125 * alliesSheltered)
end
if input.soultaker then
local soulstacks = math.min(input.soultaker_stacks or 0, 6)
totalDR = totalDR + (0.1 * soulstacks)
end
-- Face/off is a bitch
local back_requirements = hasFaceOff or command_surge
local totalDR_back
if back_requirements then
totalDR_back = totalDR
if hasFaceOff then totalDR = totalDR + 40 end
if command_surge then totalDR = totalDR + 45 end
end
-- Reusing code so this is messy
local generalResistance = totalDR
local backResistance = (back_requirements) and (totalDR_back) or nil
-- DR with decimals
local damageMultiplier = 2 ^ (totalDR / -75)
local backDamageMultiplier = (back_requirements) and 2 ^ (totalDR_back / -75) or nil
-- DR %-ified
local actualResistance = (1 - damageMultiplier) * 100
local actualResistance_back = (back_requirements) and (1 - backDamageMultiplier) * 100 or nil
local frontDamageRaw = baseDmg * damageMultiplier
local backDamageRaw = (back_requirements) and baseDmg * backDamageMultiplier * 1.4 or nil
local after_hit_hp = math.floor(baseHP - frontDamageRaw)
local after_hit_hp_back = (back_requirements) and math.floor(baseHP - backDamageRaw) or nil
local frontDamage = baseHP - after_hit_hp
local backDamage = (back_requirements) and baseHP - after_hit_hp_back or nil
-- EHP stuff
local EHP = roundBankers(baseHP / damageMultiplier)
local EHP_back = (back_requirements) and roundBankers(baseHP / backDamageMultiplier) or nil
local DTP = roundBankers(frontDamage / baseHP * 100)
local DTP_back = (back_requirements) and roundBankers(backDamage / baseHP * 100) or nil
return {
baseDamage = baseDmg,
baseHP = baseHP,
EHP = EHP,
EHP_back = EHP_back,
actualResistance = actualResistance,
actualResistance_back = actualResistance_back,
finalResistance = generalResistance,
backResistance = backResistance,
frontDamageRaw = frontDamageRaw,
frontDamage = frontDamage,
frontDamageMin = math.max(1, frontDamage - 2),
frontDamageMax = frontDamage + 2,
DTP = DTP,
backDamageRaw = backDamageRaw,
backDamage = backDamage,
backDamageMin = backDamage and math.max(1, backDamage - 2) or nil,
backDamageMax = backDamage and (backDamage + 2) or nil,
DTP_back = DTP_back,
hasFaceOff = hasFaceOff,
command_surge = command_surge
}
end
function printResults(results)
print("----------------------------")
print("BASE VALUES")
print(string.format("Base Damage: %5d", results.baseDamage))
print(string.format("Base HP: %5d", results.baseHP))
-- Print individual DR buffs
print("\nDAMAGE RESISTANCE BUFFS")
local hasDRBuffs = false
local drBuffs = {
-- Special conditional
{ name = "• Guardian of Exile:", value = 0,
condition = input.guardian_of_exile, special = function()
local alliesSheltered = math.min(input.guardian_of_exile_allies or 0, 5)
return string.format("%-25s%6.1f%%", "• Guardian of Exile (" .. alliesSheltered .. " allies):", 12.5 * alliesSheltered)
end },
{ name = "• Soultaker:", value = 0,
condition = input.soultaker, special = function()
local soulstacks = math.min(input.soultaker_stacks or 0, 3)
return string.format("%-25s%+6d", "• Soultaker (" .. soulstacks .. " stacks):", 10 * soulstacks)
end },
{ name = "• Res. Nanites (Self):", value = 20, condition = input.resistantnanites_self },
{ name = "• Res. Nanites (Other):", value = 20, condition = input.resistantnanites_others },
{ name = "• Adrenaline Shot:", value = 30, condition = input.adrenaline_shot },
{ name = "• Command Surge:", value = 45, condition = input.command_surge },
{ name = "• Berserker Essence:", value = 30, condition = input.berserker_essence },
{ name = "• Die Hard:", value = 15, condition = input.die_hard },
{ name = "• Old Boy:", value = 30, condition = input.old_boy },
-- { name = "• Overwatch on Standby:", value = -15, condition = input.overwatch_on_standby },
{ name = "• ARK Corps Guardian:", value = 25, condition = input.ARK_corps_guardian },
{ name = "• MERC Veteran Agent:", value = 20, condition = input.merc_vet_agent },
{ name = "• Fury Road:", value = 15, condition = input.fury_road },
{ name = "• CRC Light Vest:", value = 30, condition = input.crc },
{ name = "• Savage:", value = 25, condition = input.savage },
{ name = "• V.E.T. Suit:", value = 25, condition = input.hasVET },
{ name = "• ARM Implants:", value = 20, condition = input.arm_implants },
{ name = "• Fort-6B:", value = 75, condition = input.hasFort6B },
{ name = "• Four of a Kind (Hearts):", value = 44, condition = input.foak_hearts },
-- Armor
{ name = "• Matrix Plates:", value = 15, condition = input.hasArmor and input.hasMatrix },
{ name = "• Enemy Plate Carrier:", value = input.hasArmor and 75 or 0,
condition = input.hasArmor and input.hasEnemyPlateCarrier },
{ name = "• Base Armor:", value = input.hasArmor and 43 or 0,
condition = input.hasArmor and not input.hasEnemyPlateCarrier },
{ name = "• Face/Off Front Buff:", value = 40, condition = input.hasFaceOff },
}
for _, buff in ipairs(drBuffs) do
if buff.condition then
hasDRBuffs = true
if buff.special then
print(buff.special())
else
print(string.format("%-25s%+7d", buff.name, buff.value))
end
end
end
if not hasDRBuffs then
print(string.format("%-25s%s", "• None", ""))
end
print("\nTOTAL ADDITIVE RESISTANCE")
if results.hasFaceOff or results.command_surge then
print(string.format("Front Additive: %6d", roundBankers(results.finalResistance)))
print(string.format("Back Additive: %6d", roundBankers(results.backResistance)))
else
print(string.format("ADD. Resistance: %6d", roundBankers(results.finalResistance)))
end
print("\nACTUAL RESISTANCE")
if results.hasFaceOff or results.command_surge then
print(string.format("Front Resistance: %5d%%", roundBankers(results.actualResistance)))
print(string.format("Back Resistance: %5d%%", roundBankers(results.actualResistance_back)))
else
print(string.format("Final Resistance: %5d%%", roundBankers(results.actualResistance)))
end
print("\nEFFECTIVE HP")
if results.hasFaceOff or results.command_surge then
print(string.format("Front Effective HP: %5d", results.EHP))
print(string.format("Back Effective HP: %5d", results.EHP_back))
else
print(string.format("Effective HP: %5d", results.EHP))
end
print("\nDAMAGE TAKEN")
print(string.format("Damage Received: %2d (%.1f%% of HP)",
results.frontDamage, results.DTP))
if results.hasFaceOff or results.command_surge then
print(string.format("Back Damage: %2d (%.1f%% of HP)",
results.backDamage, results.DTP_back))
end
print("\nDAMAGE TAKEN RAW")
print(string.format("Damage Received: %.3f", results.frontDamageRaw))
if results.hasFaceOff or results.command_surge then
print(string.format("Back Damage: %.3f", results.backDamageRaw))
end
print("\n----------------------------")
end
local results = calculateDamageResistance(input)
printResults(results)
To embed this project on your website, copy the following code and paste it into your website's HTML: