From 19d03591b174835a850ab074c59792ca8dd7335a Mon Sep 17 00:00:00 2001 From: DarkPhoenix Date: Thu, 25 Jul 2019 20:37:35 +0300 Subject: [PATCH] Process targets in DPS calculation code --- gui/builtinGraphs/base.py | 12 ++++- gui/builtinGraphs/fitDamageStats/calc.py | 29 +++++++----- gui/builtinGraphs/fitDamageStats/graph.py | 15 ++++--- gui/builtinGraphs/fitDamageStats/helper.py | 52 ++++++++++++++++++++++ gui/graphFrame/lists.py | 10 +++-- gui/graphFrame/panel.py | 2 +- 6 files changed, 94 insertions(+), 26 deletions(-) create mode 100644 gui/builtinGraphs/fitDamageStats/helper.py diff --git a/gui/builtinGraphs/base.py b/gui/builtinGraphs/base.py index 44ed72200..84e24ccb8 100644 --- a/gui/builtinGraphs/base.py +++ b/gui/builtinGraphs/base.py @@ -21,6 +21,8 @@ from abc import ABCMeta, abstractmethod from collections import OrderedDict, namedtuple +from eos.saveddata.fit import Fit +from eos.saveddata.targetProfile import TargetProfile from service.const import GraphCacheCleanupReason @@ -94,7 +96,13 @@ class FitGraph(metaclass=ABCMeta): hasTargets = False def getPlotPoints(self, mainInput, miscInputs, xSpec, ySpec, fit, tgt=None): - cacheKey = (fit.ID, None, tgt.ID) + if isinstance(tgt, Fit): + tgtType = 'fit' + elif isinstance(tgt, TargetProfile): + tgtType = 'profile' + else: + tgtType = None + cacheKey = (fit.ID, tgtType, getattr(tgt, 'ID', None)) try: plotData = self._plotCache[cacheKey][(ySpec, xSpec)] except KeyError: @@ -111,7 +119,7 @@ class FitGraph(metaclass=ABCMeta): cacheFitID, cacheTgtType, cacheTgtID = cacheKey if extraData == cacheFitID: plotKeysToClear.add(cacheKey) - elif extraData == cacheTgtID: + elif cacheTgtType == 'fit' and extraData == cacheTgtID: plotKeysToClear.add(cacheKey) for cacheKey in plotKeysToClear: del self._plotCache[cacheKey] diff --git a/gui/builtinGraphs/fitDamageStats/calc.py b/gui/builtinGraphs/fitDamageStats/calc.py index 9d2d04bdc..0d100308a 100644 --- a/gui/builtinGraphs/fitDamageStats/calc.py +++ b/gui/builtinGraphs/fitDamageStats/calc.py @@ -21,8 +21,10 @@ import math from functools import lru_cache +from eos.saveddata.fit import Fit from service.const import GraphDpsDroneMode from service.settings import GraphSettings +from .helper import getTgtMaxVelocity, getTgtSigRadius, getTgtRadius def getTurretMult(mod, fit, tgt, atkSpeed, atkAngle, distance, tgtSpeed, tgtAngle, tgtSigRadius): @@ -37,7 +39,7 @@ def getTurretMult(mod, fit, tgt, atkSpeed, atkAngle, distance, tgtSpeed, tgtAngl distance=distance, tgtSpeed=tgtSpeed, tgtAngle=tgtAngle, - tgtRadius=tgt.ship.getModifiedItemAttr('radius'), + tgtRadius=getTgtRadius(tgt), tgtSigRadius=tgtSigRadius) mult = _calcTurretMult(cth) return mult @@ -74,7 +76,8 @@ def getDoomsdayMult(mod, tgt, distance, tgtSigRadius): return 0 # Single-target titan DDs are vs capitals only if {'superWeaponAmarr', 'superWeaponCaldari', 'superWeaponGallente', 'superWeaponMinmatar'}.intersection(mod.item.effects): - if not tgt.ship.item.requiresSkill('Capital Ships'): + # Disallow only against subcap fits, allow against cap fits and tgt profiles + if isinstance(tgt, Fit) and not tgt.ship.item.requiresSkill('Capital Ships'): return 0 damageSig = mod.getModifiedItemAttr('doomsdayDamageRadius') or mod.getModifiedItemAttr('signatureRadius') if not damageSig: @@ -88,7 +91,7 @@ def getBombMult(mod, fit, tgt, distance, tgtSigRadius): return 0 blastRadius = mod.getModifiedChargeAttr('explosionRange') atkRadius = fit.ship.getModifiedItemAttr('radius') - tgtRadius = tgt.ship.getModifiedItemAttr('radius') + tgtRadius = getTgtRadius(tgt) # Bomb starts in the center of the ship # Also here we assume that it affects target as long as blast # touches its surface, not center - I did not check this @@ -144,7 +147,7 @@ def getDroneMult(drone, fit, tgt, atkSpeed, atkAngle, distance, tgtSpeed, tgtAng distance=distance + fit.ship.getModifiedItemAttr('radius') - droneRadius, tgtSpeed=tgtSpeed, tgtAngle=tgtAngle, - tgtRadius=tgt.ship.getModifiedItemAttr('radius'), + tgtRadius=getTgtRadius(tgt), tgtSigRadius=tgtSigRadius) mult = _calcTurretMult(cth) return mult @@ -187,9 +190,10 @@ def getFighterAbilityMult(fighter, ability, fit, distance, tgtSpeed, tgtSigRadiu def getWebbedSpeed(fit, tgt, currentUnwebbedSpeed, webMods, webDrones, webFighters, distance): - if tgt.ship.getModifiedItemAttr('disallowOffensiveModifiers'): + # Can slow down non-immune fits and target profiles + if isinstance(tgt, Fit) and tgt.ship.getModifiedItemAttr('disallowOffensiveModifiers'): return currentUnwebbedSpeed - maxUnwebbedSpeed = tgt.ship.getModifiedItemAttr('maxVelocity') + maxUnwebbedSpeed = getTgtMaxVelocity(tgt) try: speedRatio = currentUnwebbedSpeed / maxUnwebbedSpeed except ZeroDivisionError: @@ -204,7 +208,7 @@ def getWebbedSpeed(fit, tgt, currentUnwebbedSpeed, webMods, webDrones, webFighte distance=distance) if appliedBoost: appliedMultipliers.setdefault(wData.stackingGroup, []).append((1 + appliedBoost / 100, wData.resAttrID)) - maxWebbedSpeed = tgt.ship.getModifiedItemAttrWithExtraMods('maxVelocity', extraMultipliers=appliedMultipliers) + maxWebbedSpeed = getTgtMaxVelocity(tgt, extraMultipliers=appliedMultipliers) currentWebbedSpeed = maxWebbedSpeed * speedRatio # Drones and fighters mobileWebs = [] @@ -220,7 +224,7 @@ def getWebbedSpeed(fit, tgt, currentUnwebbedSpeed, webMods, webDrones, webFighte for mwData in longEnoughMws: appliedMultipliers.setdefault(mwData.stackingGroup, []).append((1 + mwData.boost / 100, mwData.resAttrID)) mobileWebs.remove(mwData) - maxWebbedSpeed = tgt.ship.getModifiedItemAttrWithExtraMods('maxVelocity', extraMultipliers=appliedMultipliers) + maxWebbedSpeed = getTgtMaxVelocity(tgt, extraMultipliers=appliedMultipliers) currentWebbedSpeed = maxWebbedSpeed * speedRatio # Apply remaining webs, from fastest to slowest droneOpt = GraphSettings.getInstance().get('mobileDroneMode') @@ -240,15 +244,16 @@ def getWebbedSpeed(fit, tgt, currentUnwebbedSpeed, webMods, webDrones, webFighte distance=distance + atkRadius - mwData.radius) appliedMultipliers.setdefault(mwData.stackingGroup, []).append((1 + appliedMwBoost / 100, mwData.resAttrID)) mobileWebs.remove(mwData) - maxWebbedSpeed = tgt.ship.getModifiedItemAttrWithExtraMods('maxVelocity', extraMultipliers=appliedMultipliers) + maxWebbedSpeed = getTgtMaxVelocity(tgt, extraMultipliers=appliedMultipliers) currentWebbedSpeed = maxWebbedSpeed * speedRatio return currentWebbedSpeed def getTpMult(fit, tgt, tgtSpeed, tpMods, tpDrones, tpFighters, distance): - if tgt.ship.getModifiedItemAttr('disallowOffensiveModifiers'): + # Can blow non-immune fits and target profiles + if isinstance(tgt, Fit) and tgt.ship.getModifiedItemAttr('disallowOffensiveModifiers'): return 1 - untpedSig = tgt.ship.getModifiedItemAttr('signatureRadius') + untpedSig = getTgtSigRadius(tgt) # Modules appliedMultipliers = {} for tpData in tpMods: @@ -277,7 +282,7 @@ def getTpMult(fit, tgt, tgtSpeed, tpMods, tpDrones, tpFighters, distance): atkFalloffRange=mtpData.falloff, distance=distance + atkRadius - mtpData.radius) appliedMultipliers.setdefault(mtpData.stackingGroup, []).append((1 + appliedMtpBoost / 100, mtpData.resAttrID)) - tpedSig = tgt.ship.getModifiedItemAttrWithExtraMods('signatureRadius', extraMultipliers=appliedMultipliers) + tpedSig = getTgtSigRadius(tgt, extraMultipliers=appliedMultipliers) mult = tpedSig / untpedSig return mult diff --git a/gui/builtinGraphs/fitDamageStats/graph.py b/gui/builtinGraphs/fitDamageStats/graph.py index 8bdd43b93..2f4cf2604 100644 --- a/gui/builtinGraphs/fitDamageStats/graph.py +++ b/gui/builtinGraphs/fitDamageStats/graph.py @@ -29,6 +29,7 @@ from .calc import ( getTurretMult, getLauncherMult, getDroneMult, getFighterAbilityMult, getSmartbombMult, getDoomsdayMult, getBombMult, getGuidedBombMult, getWebbedSpeed, getTpMult) +from .helper import getTgtMaxVelocity, getTgtSigRadius from .projectedCache import ProjectedDataCache from .timeCache import TimeCache @@ -82,14 +83,14 @@ class FitDamageStatsGraph(FitGraph): _normalizers = { ('distance', 'km'): lambda v, fit, tgt: v * 1000, ('atkSpeed', '%'): lambda v, fit, tgt: v / 100 * fit.ship.getModifiedItemAttr('maxVelocity'), - ('tgtSpeed', '%'): lambda v, fit, tgt: v / 100 * tgt.ship.getModifiedItemAttr('maxVelocity'), - ('tgtSigRad', '%'): lambda v, fit, tgt: v / 100 * tgt.ship.getModifiedItemAttr('signatureRadius')} + ('tgtSpeed', '%'): lambda v, fit, tgt: v / 100 * getTgtMaxVelocity(tgt), + ('tgtSigRad', '%'): lambda v, fit, tgt: v / 100 * getTgtSigRadius(tgt)} _limiters = { 'time': lambda fit, tgt: (0, 2500)} _denormalizers = { ('distance', 'km'): lambda v, fit, tgt: v / 1000, - ('tgtSpeed', '%'): lambda v, fit, tgt: v * 100 / tgt.ship.getModifiedItemAttr('maxVelocity'), - ('tgtSigRad', '%'): lambda v, fit, tgt: v * 100 / tgt.ship.getModifiedItemAttr('signatureRadius')} + ('tgtSpeed', '%'): lambda v, fit, tgt: v * 100 / getTgtMaxVelocity(tgt), + ('tgtSigRad', '%'): lambda v, fit, tgt: v * 100 / getTgtSigRadius(tgt)} def _distance2dps(self, mainInput, miscInputs, fit, tgt): return self._xDistanceGetter( @@ -178,7 +179,7 @@ class FitDamageStatsGraph(FitGraph): # Go through distances and calculate distance-dependent data for distance in self._iterLinear(mainInput[1]): tgtSpeed = miscInputMap['tgtSpeed'] - tgtSigRadius = tgt.ship.getModifiedItemAttr('signatureRadius') + tgtSigRadius = getTgtSigRadius(tgt) if applyProjected: webMods, tpMods = self._projectedCache.getProjModData(fit) webDrones, tpDrones = self._projectedCache.getProjDroneData(fit) @@ -220,7 +221,7 @@ class FitDamageStatsGraph(FitGraph): # Process inputs into more convenient form miscInputMap = dict(miscInputs) tgtSpeed = miscInputMap['tgtSpeed'] - tgtSigRadius = tgt.ship.getModifiedItemAttr('signatureRadius') + tgtSigRadius = getTgtSigRadius(tgt) if GraphSettings.getInstance().get('applyProjected'): webMods, tpMods = self._projectedCache.getProjModData(fit) webDrones, tpDrones = self._projectedCache.getProjDroneData(fit) @@ -308,7 +309,7 @@ class FitDamageStatsGraph(FitGraph): # Get separate internal speed to calculate proper application, for graph # itself we still want to show pre-modification speed on X axis tgtSpeedInternal = tgtSpeed - tgtSigRadius = tgt.ship.getModifiedItemAttr('signatureRadius') + tgtSigRadius = getTgtSigRadius(tgt) if applyProjected: webMods, tpMods = self._projectedCache.getProjModData(fit) webDrones, tpDrones = self._projectedCache.getProjDroneData(fit) diff --git a/gui/builtinGraphs/fitDamageStats/helper.py b/gui/builtinGraphs/fitDamageStats/helper.py new file mode 100644 index 000000000..ce5253eba --- /dev/null +++ b/gui/builtinGraphs/fitDamageStats/helper.py @@ -0,0 +1,52 @@ +# ============================================================================= +# Copyright (C) 2010 Diego Duclos +# +# This file is part of pyfa. +# +# pyfa is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# pyfa is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with pyfa. If not, see . +# ============================================================================= + + +from eos.saveddata.fit import Fit +from eos.saveddata.targetProfile import TargetProfile + + +def getTgtMaxVelocity(tgt, extraMultipliers=None): + if isinstance(tgt, Fit): + if extraMultipliers: + return tgt.ship.getModifiedItemAttrWithExtraMods('maxVelocity', extraMultipliers=extraMultipliers) + else: + return tgt.ship.getModifiedItemAttr('maxVelocity') + elif isinstance(tgt, TargetProfile): + return tgt.maxVelocity + return None + + +def getTgtSigRadius(tgt, extraMultipliers=None): + if isinstance(tgt, Fit): + if extraMultipliers: + return tgt.ship.getModifiedItemAttrWithExtraMods('signatureRadius', extraMultipliers=extraMultipliers) + else: + return tgt.ship.getModifiedItemAttr('signatureRadius') + elif isinstance(tgt, TargetProfile): + return tgt.signatureRadius + return None + + +def getTgtRadius(tgt): + if isinstance(tgt, Fit): + return tgt.ship.getModifiedItemAttr('radius') + elif isinstance(tgt, TargetProfile): + return tgt.radius + return None diff --git a/gui/graphFrame/lists.py b/gui/graphFrame/lists.py index 85b7ec239..cbe971923 100644 --- a/gui/graphFrame/lists.py +++ b/gui/graphFrame/lists.py @@ -205,9 +205,11 @@ class TargetList(BaseList): super().__init__(graphFrame, parent) self.profiles = [] self.profiles.append(TargetProfile.getIdeal()) - stuff = self.fits + self.profiles - self.update(stuff) + self.update(self.targets) def refreshView(self): - stuff = self.fits + self.profiles - self.refresh(stuff) + self.refresh(self.targets) + + @property + def targets(self): + return self.fits + self.profiles diff --git a/gui/graphFrame/panel.py b/gui/graphFrame/panel.py index d5afd2d64..70ebc95c2 100644 --- a/gui/graphFrame/panel.py +++ b/gui/graphFrame/panel.py @@ -318,7 +318,7 @@ class GraphControlPanel(wx.Panel): @property def targets(self): - return self.targetList.fits + return self.targetList.targets def unbindExternalEvents(self): self.fitList.unbindExternalEvents()