I've written a terrible program in terribly written Python that attempts to do DPS calculation at a very basic level. I've been using it to compare weapons for a while and it doesn't seem terribly wrong most of the time.
What it does is simulate firing a gun for 60 seconds, then divide the damage dealt by 60. It keeps count of:
- Weapon damage
- Fire rate
- Magazine
- Elemental damage
- Damage type (vs flesh, shield, armor)
- Playthrough (by default it uses the second)
- Optionally accuracy in mostly bogus ways (but not by default)
- Optionally recoil in definitely bogus ways (but not by default)
- Optionally bonus stats from badass ranks (but not by default)
It does not work well if:
- The weapon has any fancy attributes (= red text)
- You're comparing shotguns with non-shotguns (because by default all pellets hit all the time)
- You're comparing sniper rifles with non-sniper rifles (because calculating critical hits is rather complicated... and why would you do that to begin with?)
- It's a pistol with a "x2" damage multiplier (unless that means it fires two pellets at once, then see above remarks about shotguns)
- It's an e-tech gun (you really need to see how the e-tech gun works, if at all, before you start comparing damage outputs)
- The game doesn't behave like I modeled it
I'll put here the bulk of the calculation for easier peer review:
def dps(weapon,
playthrough = 2,
bonusStats = zeroStats,
referenceTime = 60,
accuracyAdjusting = lambda x: 1, # lambda x: x**(1/3),
accountForRecoilInVastlyBogusWays = False):
time = 0
damage = Damage(0,0,0)
ammoCount = weapon.magazine
recoilMalus = 0
while time <= referenceTime:
time += 1/(weapon.fireRate * bonusStats.rate)
for i in xrange(weapon.pelletCount):
if random() < accuracyAdjusting(weapon.accuracy/100 * bonusStats.accuracy + recoilMalus):
damage.add(weapon.damage * bonusStats.damage, weapon.element, playthrough)
if weapon.element:
if random() < weapon.elementChance/100 * bonusStats.elementChance:
damage.add(weapon.elementDPS * bonusStats.elementDamage * elementLength[weapon.element],
weapon.element, playthrough) #this adjusts damage type vs health type
ammoCount -= 1
if accountForRecoilInVastlyBogusWays:
recoilMalus -= 0.01 * 1/bonusStats.recoil
if ammoCount == 0:
time += weapon.reloadTime * bonusStats.reload
ammoCount = weapon.magazine
recoilMalus = 0
return damage/time
As is the program runs in the console and asks you to pretty much type in the weapon card, spitting out the DPS in return. It's licensed as WTFPL so feel free to improve it in all the ways.