From 7c37d8fd74fcef8b98b0f2679f161935995c1bbe Mon Sep 17 00:00:00 2001 From: DarkPhoenix Date: Mon, 11 Nov 2024 14:12:06 +0100 Subject: [PATCH] Add a few bits to breacher volley calculation --- eos/saveddata/module.py | 58 ++++++++++++++++++++++++----------------- eos/utils/stats.py | 10 ++++++- 2 files changed, 43 insertions(+), 25 deletions(-) diff --git a/eos/saveddata/module.py b/eos/saveddata/module.py index e271e2b9f..429d75535 100644 --- a/eos/saveddata/module.py +++ b/eos/saveddata/module.py @@ -33,7 +33,7 @@ from eos.utils.cycles import CycleInfo, CycleSequence from eos.utils.default import DEFAULT from eos.utils.float import floatUnerr from eos.utils.spoolSupport import calculateSpoolup, resolveSpoolOptions -from eos.utils.stats import DmgTypes, RRTypes +from eos.utils.stats import BreacherInfo, DmgTypes, RRTypes pyfalog = Logger(__name__) @@ -472,28 +472,37 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut, M return {0: DmgTypes(0, 0, 0, 0)} if self.__baseVolley is None: self.__baseVolley = {} - dmgGetter = self.getModifiedChargeAttr if self.charge else self.getModifiedItemAttr - dmgMult = self.getModifiedItemAttr("damageMultiplier", 1) - # Some delay attributes have non-0 default value, so we have to pick according to effects - if {'superWeaponAmarr', 'superWeaponCaldari', 'superWeaponGallente', 'superWeaponMinmatar', 'lightningWeapon'}.intersection(self.item.effects): - dmgDelay = self.getModifiedItemAttr("damageDelayDuration", 0) - elif {'doomsdayBeamDOT', 'doomsdaySlash', 'doomsdayConeDOT', 'debuffLance'}.intersection(self.item.effects): - dmgDelay = self.getModifiedItemAttr("doomsdayWarningDuration", 0) + if self.charge and 'dotMissileLaunching' in self.charge.item.effects: + dmgDelay = 1 + subcycles = math.floor(self.getModifiedChargeAttr("dotDuration", 0)) + breacher_info = BreacherInfo( + absolute=self.getModifiedChargeAttr("dotMaxDamagePerTick", 0), + relative=self.getModifiedChargeAttr("dotMaxHPPercentagePerTick", 0)) + for i in range(subcycles): + self.__baseVolley[dmgDelay + i] = DmgTypes(0, 0, 0, 0, breacher=breacher_info) else: - dmgDelay = 0 - dmgDuration = self.getModifiedItemAttr("doomsdayDamageDuration", 0) - dmgSubcycle = self.getModifiedItemAttr("doomsdayDamageCycleTime", 0) - # Reaper DD can damage each target only once - if dmgDuration != 0 and dmgSubcycle != 0 and 'doomsdaySlash' not in self.item.effects: - subcycles = math.floor(floatUnerr(dmgDuration / dmgSubcycle)) - else: - subcycles = 1 - for i in range(subcycles): - self.__baseVolley[dmgDelay + dmgSubcycle * i] = DmgTypes( - em=(dmgGetter("emDamage", 0)) * dmgMult, - thermal=(dmgGetter("thermalDamage", 0)) * dmgMult, - kinetic=(dmgGetter("kineticDamage", 0)) * dmgMult, - explosive=(dmgGetter("explosiveDamage", 0)) * dmgMult) + dmgGetter = self.getModifiedChargeAttr if self.charge else self.getModifiedItemAttr + dmgMult = self.getModifiedItemAttr("damageMultiplier", 1) + # Some delay attributes have non-0 default value, so we have to pick according to effects + if {'superWeaponAmarr', 'superWeaponCaldari', 'superWeaponGallente', 'superWeaponMinmatar', 'lightningWeapon'}.intersection(self.item.effects): + dmgDelay = self.getModifiedItemAttr("damageDelayDuration", 0) + elif {'doomsdayBeamDOT', 'doomsdaySlash', 'doomsdayConeDOT', 'debuffLance'}.intersection(self.item.effects): + dmgDelay = self.getModifiedItemAttr("doomsdayWarningDuration", 0) + else: + dmgDelay = 0 + dmgDuration = self.getModifiedItemAttr("doomsdayDamageDuration", 0) + dmgSubcycle = self.getModifiedItemAttr("doomsdayDamageCycleTime", 0) + # Reaper DD can damage each target only once + if dmgDuration != 0 and dmgSubcycle != 0 and 'doomsdaySlash' not in self.item.effects: + subcycles = math.floor(floatUnerr(dmgDuration / dmgSubcycle)) + else: + subcycles = 1 + for i in range(subcycles): + self.__baseVolley[dmgDelay + dmgSubcycle * i] = DmgTypes( + em=(dmgGetter("emDamage", 0)) * dmgMult, + thermal=(dmgGetter("thermalDamage", 0)) * dmgMult, + kinetic=(dmgGetter("kineticDamage", 0)) * dmgMult, + explosive=(dmgGetter("explosiveDamage", 0)) * dmgMult) spoolType, spoolAmount = resolveSpoolOptions(spoolOptions, self) spoolBoost = calculateSpoolup( self.getModifiedItemAttr("damageMultiplierBonusMax", 0), @@ -506,7 +515,8 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut, M em=volleyValue.em * spoolMultiplier * (1 - getattr(targetProfile, "emAmount", 0)), thermal=volleyValue.thermal * spoolMultiplier * (1 - getattr(targetProfile, "thermalAmount", 0)), kinetic=volleyValue.kinetic * spoolMultiplier * (1 - getattr(targetProfile, "kineticAmount", 0)), - explosive=volleyValue.explosive * spoolMultiplier * (1 - getattr(targetProfile, "explosiveAmount", 0))) + explosive=volleyValue.explosive * spoolMultiplier * (1 - getattr(targetProfile, "explosiveAmount", 0)), + breacher=volleyValue.breacher) return adjustedVolley def getVolley(self, spoolOptions=None, targetProfile=None, ignoreState=False): @@ -534,7 +544,7 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut, M explosive=dmgDuringCycle.explosive * dpsFactor) if not getSpreadDPS: return dps - return {'em':dmgDuringCycle.em * dpsFactor, + return {'em': dmgDuringCycle.em * dpsFactor, 'therm': dmgDuringCycle.thermal * dpsFactor, 'kin': dmgDuringCycle.kinetic * dpsFactor, 'exp': dmgDuringCycle.explosive * dpsFactor} diff --git a/eos/utils/stats.py b/eos/utils/stats.py index 5b6329c16..3e88a6799 100644 --- a/eos/utils/stats.py +++ b/eos/utils/stats.py @@ -18,6 +18,8 @@ # =============================================================================== +from typing import NamedTuple + from eos.utils.float import floatUnerr from utils.repr import makeReprStr @@ -26,14 +28,20 @@ def _t(x): return x +class BreacherInfo(NamedTuple): + absolute: float + relative: float + + class DmgTypes: """Container for damage data stats.""" - def __init__(self, em, thermal, kinetic, explosive): + def __init__(self, em, thermal, kinetic, explosive, breacher=None): self.em = em self.thermal = thermal self.kinetic = kinetic self.explosive = explosive + self.breacher = [] if breacher is None else breacher self._calcTotal() # Iterator is needed to support tuple-style unpacking