diff --git a/eos/graph/fitDps.py b/eos/graph/fitDps.py index e427ba30c..dc402706d 100644 --- a/eos/graph/fitDps.py +++ b/eos/graph/fitDps.py @@ -78,9 +78,13 @@ class FitDpsGraph(Graph): dps, _ = drone.damageStats(fit.targetResists) total += dps * multiplier + # this is janky as fuck for fighter in fit.fighters: - dps, _ = fighter.damageStats(fit.targetResists) - total += dps + for ability in fighter.abilities: + if ability.dealsDamage and ability.active: + multiplier = self.calculateFighterMissileMultiplier(ability, data) + dps, _ = ability.damageStats(fit.targetResists) + total += dps * multiplier return total @@ -116,6 +120,35 @@ class FitDpsGraph(Graph): multiplier = min(1, (float(targetSigRad) / dmgScaling) ** 2) return multiplier + def calculateFighterMissileMultiplier(self, ability, data): + prefix = ability.attrPrefix + + targetSigRad = data["signatureRadius"] + targetVelocity = data["velocity"] + explosionRadius = ability.fighter.getModifiedItemAttr("{}ExplosionRadius".format(prefix)) + explosionVelocity = ability.fighter.getModifiedItemAttr("{}ExplosionVelocity".format(prefix)) + damageReductionFactor = ability.fighter.getModifiedItemAttr("{}ReductionFactor".format(prefix)) + + # the following conditionals are because CCP can't keep a decent naming convention, as if fighter implementation + # wasn't already fucked. + if damageReductionFactor is None: + damageReductionFactor = ability.fighter.getModifiedItemAttr("{}DamageReductionFactor".format(prefix)) + + damageReductionSensitivity = ability.fighter.getModifiedItemAttr("{}ReductionSensitivity".format(prefix)) + if damageReductionSensitivity is None: + damageReductionSensitivity = ability.fighter.getModifiedItemAttr("{}DamageReductionSensitivity".format(prefix)) + + targetSigRad = explosionRadius if targetSigRad is None else targetSigRad + sigRadiusFactor = targetSigRad / explosionRadius + + if targetVelocity: + velocityFactor = (explosionVelocity / explosionRadius * targetSigRad / targetVelocity) ** ( + log(damageReductionFactor) / log(damageReductionSensitivity)) + else: + velocityFactor = 1 + + return min(sigRadiusFactor, velocityFactor, 1) + def calculateTurretChanceToHit(self, mod, data): distance = data["distance"] * 1000 tracking = mod.getModifiedItemAttr("trackingSpeed") diff --git a/eos/saveddata/fighter.py b/eos/saveddata/fighter.py index 353273106..ebbffb814 100644 --- a/eos/saveddata/fighter.py +++ b/eos/saveddata/fighter.py @@ -159,25 +159,11 @@ class Fighter(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut): if self.__dps is None: self.__volley = 0 self.__dps = 0 - if self.active: + if self.active and self.amountActive > 0: for ability in self.abilities: - if ability.dealsDamage and ability.active and self.amountActive > 0: - - cycleTime = self.getModifiedItemAttr("{}Duration".format(ability.attrPrefix)) - if ability.attrPrefix == "fighterAbilityLaunchBomb": - # bomb calcs - volley = sum(map(lambda attr: (self.getModifiedChargeAttr("%sDamage" % attr) or 0) * (1 - getattr(targetResists, "%sAmount" % attr, 0)), self.DAMAGE_TYPES)) - print volley - else: - volley = sum(map(lambda d2, d: - (self.getModifiedItemAttr("{}Damage{}".format(ability.attrPrefix, d2)) or 0) * - (1-getattr(targetResists, "{}Amount".format(d), 0)), - self.DAMAGE_TYPES2, self.DAMAGE_TYPES)) - - volley *= self.amountActive - volley *= self.getModifiedItemAttr("{}DamageMultiplier".format(ability.attrPrefix)) or 1 - self.__volley += volley - self.__dps += volley / (cycleTime / 1000.0) + dps, volley = ability.damageStats(targetResists) + self.__dps += dps + self.__volley += volley return self.__dps, self.__volley @@ -222,6 +208,7 @@ class Fighter(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut): self.__miningyield = None self.itemModifiedAttributes.clear() self.chargeModifiedAttributes.clear() + [x.clear() for x in self.abilities] def canBeApplied(self, projectedOnto): """Check if fighter can engage specific fitting""" diff --git a/eos/saveddata/fighterAbility.py b/eos/saveddata/fighterAbility.py index 3956a2e4d..e7756bde1 100644 --- a/eos/saveddata/fighterAbility.py +++ b/eos/saveddata/fighterAbility.py @@ -23,6 +23,8 @@ import logging logger = logging.getLogger(__name__) class FighterAbility(object): + DAMAGE_TYPES = ("em", "kinetic", "explosive", "thermal") + DAMAGE_TYPES2 = ("EM", "Kin", "Exp", "Therm") def __init__(self, effect): """Initialize from the program""" @@ -67,4 +69,33 @@ class FighterAbility(object): @property def grouped(self): # is the ability applied per fighter (webs, returns False), or as a group (MWD, returned True) - return self.__effect.getattr('grouped') \ No newline at end of file + return self.__effect.getattr('grouped') + + def damageStats(self, targetResists=None): + if self.__dps is None: + self.__volley = 0 + self.__dps = 0 + if self.dealsDamage and self.active: + cycleTime = self.fighter.getModifiedItemAttr("{}Duration".format(self.attrPrefix)) + + if self.attrPrefix == "fighterAbilityLaunchBomb": + # bomb calcs + volley = sum(map(lambda attr: (self.fighter.getModifiedChargeAttr("%sDamage" % attr) or 0) * ( + 1 - getattr(targetResists, "%sAmount" % attr, 0)), self.DAMAGE_TYPES)) + else: + volley = sum(map(lambda d2, d: + (self.fighter.getModifiedItemAttr( + "{}Damage{}".format(self.attrPrefix, d2)) or 0) * + (1 - getattr(targetResists, "{}Amount".format(d), 0)), + self.DAMAGE_TYPES2, self.DAMAGE_TYPES)) + + volley *= self.fighter.amountActive + volley *= self.fighter.getModifiedItemAttr("{}DamageMultiplier".format(self.attrPrefix)) or 1 + self.__volley += volley + self.__dps += volley / (cycleTime / 1000.0) + + return self.__dps, self.__volley + + def clear(self): + self.__dps = None + self.__volley = None