Process targets in DPS calculation code

This commit is contained in:
DarkPhoenix
2019-07-25 20:37:35 +03:00
parent 6f1321aa13
commit 19d03591b1
6 changed files with 94 additions and 26 deletions

View File

@@ -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]

View File

@@ -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

View File

@@ -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)

View File

@@ -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 <http://www.gnu.org/licenses/>.
# =============================================================================
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

View File

@@ -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

View File

@@ -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()