Merge branch 'master' into singularity

This commit is contained in:
DarkPhoenix
2019-08-23 13:24:29 +03:00
9 changed files with 183 additions and 111 deletions

View File

@@ -67,14 +67,8 @@ class ItemAttrShortcut:
return_value = self.itemModifiedAttributes.get(key)
return return_value or default
def getModifiedItemAttrWithExtraMods(self, key, extraMultipliers=None, default=0):
"""Returns attribute value with passed modifiers applied to it."""
return_value = self.itemModifiedAttributes.getWithExtraMods(key, extraMultipliers=extraMultipliers)
return return_value or default
def getModifiedItemAttrWithoutAfflictor(self, key, afflictor, default=0):
"""Returns attribute value with passed afflictor modification removed."""
return_value = self.itemModifiedAttributes.getWithoutAfflictor(key, afflictor)
def getModifiedItemAttrExtended(self, key, extraMultipliers=None, ignoreAfflictors=(), default=0):
return_value = self.itemModifiedAttributes.getExtended(key, extraMultipliers=extraMultipliers, ignoreAfflictors=ignoreAfflictors)
return return_value or default
def getItemBaseAttrValue(self, key, default=0):
@@ -88,14 +82,8 @@ class ChargeAttrShortcut:
return_value = self.chargeModifiedAttributes.get(key)
return return_value or default
def getModifiedChargeAttrWithExtraMods(self, key, extraMultipliers=None, default=0):
"""Returns attribute value with passed modifiers applied to it."""
return_value = self.chargeModifiedAttributes.getWithExtraMods(key, extraMultipliers=extraMultipliers)
return return_value or default
def getModifiedChargeAttrWithoutAfflictor(self, key, afflictor, default=0):
"""Returns attribute value with passed modifiers applied to it."""
return_value = self.chargeModifiedAttributes.getWithoutAfflictor(key, afflictor)
def getModifiedChargeAttrExtended(self, key, extraMultipliers=None, ignoreAfflictors=(), default=0):
return_value = self.chargeModifiedAttributes.getExtended(key, extraMultipliers=extraMultipliers, ignoreAfflictors=ignoreAfflictors)
return return_value or default
def getChargeBaseAttrValue(self, key, default=0):
@@ -211,32 +199,11 @@ class ModifiedAttributeDict(collections.MutableMapping):
# Original value is the least priority
return self.getOriginal(key)
def getWithExtraMods(self, key, extraMultipliers=None, default=0):
"""Copy of __getitem__ with some modifications."""
if not extraMultipliers:
return self.get(key, default=default)
val = self.__calculateValue(key, extraMultipliers=extraMultipliers)
if val is not None:
return val
# Then in values which are not yet calculated
if self.__intermediary:
val = self.__intermediary.get(key)
else:
val = None
if val is not None:
return val
# Original value
val = self.getOriginal(key)
if val is not None:
return val
# Passed in default value
return default
def getWithoutAfflictor(self, key, afflictor, default=0):
def getExtended(self, key, extraMultipliers=None, ignoreAfflictors=None, default=0):
"""
Here we consider couple of parameters. If they affect final result, we do
not store result, and if they are - we do.
"""
# Here we do not have support for preAssigns/forceds, as doing them would
# mean that we have to store all of them in a list which increases memory use,
# and we do not actually need those operators atm
@@ -245,8 +212,8 @@ class ModifiedAttributeDict(collections.MutableMapping):
ignorePenalizedMultipliers = {}
postIncreaseAdjustment = 0
for fit, afflictors in self.getAfflictions(key).items():
for innerAfflictor, operator, stackingGroup, preResAmount, postResAmount, used in afflictors:
if innerAfflictor is afflictor:
for afflictor, operator, stackingGroup, preResAmount, postResAmount, used in afflictors:
if afflictor in ignoreAfflictors:
if operator == Operator.MULTIPLY:
if stackingGroup is None:
multiplierAdjustment /= postResAmount
@@ -257,29 +224,31 @@ class ModifiedAttributeDict(collections.MutableMapping):
elif operator == Operator.POSTINCREASE:
postIncreaseAdjustment -= postResAmount
if preIncreaseAdjustment == 0 and multiplierAdjustment == 1 and postIncreaseAdjustment == 0 and len(ignorePenalizedMultipliers) == 0:
# If we apply no customizations - use regular getter
if (
not extraMultipliers and
preIncreaseAdjustment == 0 and multiplierAdjustment == 1 and
postIncreaseAdjustment == 0 and len(ignorePenalizedMultipliers) == 0
):
return self.get(key, default=default)
# Try to calculate custom values
val = self.__calculateValue(
key, preIncAdj=preIncreaseAdjustment, multAdj=multiplierAdjustment,
key, extraMultipliers=extraMultipliers, preIncAdj=preIncreaseAdjustment, multAdj=multiplierAdjustment,
postIncAdj=postIncreaseAdjustment, ignorePenMult=ignorePenalizedMultipliers)
if val is not None:
return val
# Then in values which are not yet calculated
# Then the same fallbacks as in regular getter
if self.__intermediary:
val = self.__intermediary.get(key)
else:
val = None
if val is not None:
return val
# Original value
val = self.getOriginal(key)
if val is not None:
return val
# Passed in default value
return default
def __delitem__(self, key):

View File

@@ -1320,8 +1320,8 @@ class Fit:
"""Return how much cap regen do we gain from having this module"""
currentRegen = self.calculateCapRecharge()
nomodRegen = self.calculateCapRecharge(
capacity=self.ship.getModifiedItemAttrWithoutAfflictor("capacitorCapacity", mod),
rechargeRate=self.ship.getModifiedItemAttrWithoutAfflictor("rechargeRate", mod) / 1000.0)
capacity=self.ship.getModifiedItemAttrExtended("capacitorCapacity", ignoreAfflictors=[mod]),
rechargeRate=self.ship.getModifiedItemAttrExtended("rechargeRate", ignoreAfflictors=[mod]) / 1000.0)
return currentRegen - nomodRegen
def getRemoteReps(self, spoolOptions=None):

View File

@@ -77,6 +77,8 @@ class TargetProfile:
@signatureRadius.setter
def signatureRadius(self, val):
if val is not None and math.isinf(val):
val = None
self._signatureRadius = val
@property
@@ -106,7 +108,7 @@ class TargetProfile:
continue
line = line.split('#', 1)[0] # allows for comments
type, data = line.rsplit('=', 1)
type, data = type.strip(), data.split(',')
type, data = type.strip(), [d.strip() for d in data.split(',')]
except:
pyfalog.warning("Data isn't in correct format, continue to next line.")
continue
@@ -115,11 +117,13 @@ class TargetProfile:
continue
numPatterns += 1
name, data = data[0], data[1:5]
name, dataRes, dataMisc = data[0], data[1:5], data[5:8]
fields = {}
for index, val in enumerate(data):
val = float(val)
for index, val in enumerate(dataRes):
val = float(val) if val else 0
if math.isinf(val):
val = 0
try:
assert 0 <= val <= 100
fields["%sAmount" % cls.DAMAGE_TYPES[index]] = val / 100
@@ -127,7 +131,18 @@ class TargetProfile:
pyfalog.warning("Caught unhandled exception in import patterns.")
continue
if len(fields) == 4: # Avoid possible blank lines
if len(dataMisc) == 3:
for index, val in enumerate(dataMisc):
try:
fieldName = ("maxVelocity", "signatureRadius", "radius")[index]
except IndexError:
break
val = float(val) if val else 0
if fieldName != "signatureRadius" and math.isinf(val):
val = 0
fields[fieldName] = val
if len(fields) in (4, 7): # Avoid possible blank lines
if name.strip() in lookup:
pattern = lookup[name.strip()]
pattern.update(**fields)
@@ -142,20 +157,23 @@ class TargetProfile:
return patterns, numPatterns
EXPORT_FORMAT = "TargetProfile = %s,%.1f,%.1f,%.1f,%.1f\n"
EXPORT_FORMAT = "TargetProfile = %s,%.1f,%.1f,%.1f,%.1f,%.1f,%.1f,%.1f\n"
@classmethod
def exportPatterns(cls, *patterns):
out = "# Exported from pyfa\n#\n"
out += "# Values are in following format:\n"
out += "# TargetProfile = [name],[EM %],[Thermal %],[Kinetic %],[Explosive %]\n\n"
out += "# TargetProfile = [name],[EM %],[Thermal %],[Kinetic %],[Explosive %],[Max velocity m/s],[Signature radius m],[Radius m]\n\n"
for dp in patterns:
out += cls.EXPORT_FORMAT % (
dp.name,
dp.emAmount * 100,
dp.thermalAmount * 100,
dp.kineticAmount * 100,
dp.explosiveAmount * 100
dp.explosiveAmount * 100,
dp.maxVelocity,
dp.signatureRadius,
dp.radius
)
return out.strip()

View File

@@ -26,15 +26,59 @@ from service.const import GraphDpsDroneMode
from service.settings import GraphSettings
def getWebbedSpeed(src, tgt, currentUnwebbedSpeed, webMods, webDrones, webFighters, distance):
def _isRegularScram(mod):
if not mod.item:
return False
if not {'warpScrambleBlockMWDWithNPCEffect', 'structureWarpScrambleBlockMWDWithNPCEffect'}.intersection(mod.item.effects):
return False
if not mod.getModifiedItemAttr('activationBlockedStrenght', 0):
return False
return True
def _isHicScram(mod):
if not mod.item:
return False
if 'warpDisruptSphere' not in mod.item.effects:
return False
if not mod.charge:
return False
if 'shipModuleFocusedWarpScramblingScript' not in mod.charge.effects:
return False
return True
def getScramRange(src):
scramRange = None
for mod in src.item.modules:
if _isRegularScram(mod) or _isHicScram(mod):
scramRange = max(scramRange or 0, mod.maxRange or 0)
return scramRange
def getScrammables(tgt):
scrammables = []
if tgt.isFit:
for mod in tgt.item.modules:
if not mod.item:
continue
if {'moduleBonusMicrowarpdrive', 'microJumpDrive', 'microJumpPortalDrive'}.intersection(mod.item.effects):
scrammables.append(mod)
return scrammables
def getTackledSpeed(src, tgt, currentUntackledSpeed, srcScramRange, tgtScrammables, webMods, webDrones, webFighters, distance):
# Can slow down non-immune ships and target profiles
if tgt.isFit and tgt.item.ship.getModifiedItemAttr('disallowOffensiveModifiers'):
return currentUnwebbedSpeed
maxUnwebbedSpeed = tgt.getMaxVelocity()
return currentUntackledSpeed
maxUntackledSpeed = tgt.getMaxVelocity()
# What's immobile cannot be slowed
if maxUnwebbedSpeed == 0:
return maxUnwebbedSpeed
speedRatio = currentUnwebbedSpeed / maxUnwebbedSpeed
if maxUntackledSpeed == 0:
return maxUntackledSpeed
speedRatio = currentUntackledSpeed / maxUntackledSpeed
# No scrams or distance is longer than longest scram - nullify scrammables list
if srcScramRange is None or (distance is not None and distance > srcScramRange):
tgtScrammables = ()
appliedMultipliers = {}
# Modules first, they are applied always the same way
for wData in webMods:
@@ -44,8 +88,8 @@ def getWebbedSpeed(src, tgt, currentUnwebbedSpeed, webMods, webDrones, webFighte
distance=distance)
if appliedBoost:
appliedMultipliers.setdefault(wData.stackingGroup, []).append((1 + appliedBoost / 100, wData.resAttrID))
maxWebbedSpeed = tgt.getMaxVelocity(extraMultipliers=appliedMultipliers)
currentWebbedSpeed = maxWebbedSpeed * speedRatio
maxTackledSpeed = tgt.getMaxVelocity(extraMultipliers=appliedMultipliers, ignoreAfflictors=tgtScrammables)
currentTackledSpeed = maxTackledSpeed * speedRatio
# Drones and fighters
mobileWebs = []
mobileWebs.extend(webFighters)
@@ -60,8 +104,8 @@ def getWebbedSpeed(src, 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.getMaxVelocity(extraMultipliers=appliedMultipliers)
currentWebbedSpeed = maxWebbedSpeed * speedRatio
maxTackledSpeed = tgt.getMaxVelocity(extraMultipliers=appliedMultipliers, ignoreAfflictors=tgtScrammables)
currentTackledSpeed = maxTackledSpeed * speedRatio
# Apply remaining webs, from fastest to slowest
droneOpt = GraphSettings.getInstance().get('mobileDroneMode')
while mobileWebs:
@@ -70,7 +114,7 @@ def getWebbedSpeed(src, tgt, currentUnwebbedSpeed, webMods, webDrones, webFighte
fastestMws = [mw for mw in mobileWebs if mw.speed == fastestMwSpeed]
for mwData in fastestMws:
# Faster than target or set to follow it - apply full slowdown
if (droneOpt == GraphDpsDroneMode.auto and mwData.speed >= currentWebbedSpeed) or droneOpt == GraphDpsDroneMode.followTarget:
if (droneOpt == GraphDpsDroneMode.auto and mwData.speed >= currentTackledSpeed) or droneOpt == GraphDpsDroneMode.followTarget:
appliedMwBoost = mwData.boost
# Otherwise project from the center of the ship
else:
@@ -84,18 +128,21 @@ def getWebbedSpeed(src, tgt, currentUnwebbedSpeed, webMods, webDrones, webFighte
distance=rangeFactorDistance)
appliedMultipliers.setdefault(mwData.stackingGroup, []).append((1 + appliedMwBoost / 100, mwData.resAttrID))
mobileWebs.remove(mwData)
maxWebbedSpeed = tgt.getMaxVelocity(extraMultipliers=appliedMultipliers)
currentWebbedSpeed = maxWebbedSpeed * speedRatio
maxTackledSpeed = tgt.getMaxVelocity(extraMultipliers=appliedMultipliers, ignoreAfflictors=tgtScrammables)
currentTackledSpeed = maxTackledSpeed * speedRatio
# Ensure consistent results - round off a little to avoid float errors
return floatUnerr(currentWebbedSpeed)
return floatUnerr(currentTackledSpeed)
def getTpMult(src, tgt, tgtSpeed, tpMods, tpDrones, tpFighters, distance):
def getSigRadiusMult(src, tgt, tgtSpeed, srcScramRange, tgtScrammables, tpMods, tpDrones, tpFighters, distance):
# Can blow non-immune ships and target profiles
if tgt.isFit and tgt.item.ship.getModifiedItemAttr('disallowOffensiveModifiers'):
return 1
untpedSig = tgt.getSigRadius()
# Modules
initSig = tgt.getSigRadius()
# No scrams or distance is longer than longest scram - nullify scrammables list
if srcScramRange is None or (distance is not None and distance > srcScramRange):
tgtScrammables = ()
# TPing modules
appliedMultipliers = {}
for tpData in tpMods:
appliedBoost = tpData.boost * calculateRangeFactor(
@@ -104,7 +151,7 @@ def getTpMult(src, tgt, tgtSpeed, tpMods, tpDrones, tpFighters, distance):
distance=distance)
if appliedBoost:
appliedMultipliers.setdefault(tpData.stackingGroup, []).append((1 + appliedBoost / 100, tpData.resAttrID))
# Drones and fighters
# TPing drones
mobileTps = []
mobileTps.extend(tpFighters)
# Drones have range limit
@@ -127,9 +174,9 @@ def getTpMult(src, tgt, tgtSpeed, tpMods, tpDrones, tpFighters, distance):
srcFalloffRange=mtpData.falloff,
distance=rangeFactorDistance)
appliedMultipliers.setdefault(mtpData.stackingGroup, []).append((1 + appliedMtpBoost / 100, mtpData.resAttrID))
tpedSig = tgt.getSigRadius(extraMultipliers=appliedMultipliers)
if tpedSig == math.inf and untpedSig == math.inf:
modifiedSig = tgt.getSigRadius(extraMultipliers=appliedMultipliers, ignoreAfflictors=tgtScrammables)
if modifiedSig == math.inf and initSig == math.inf:
return 1
mult = tpedSig / untpedSig
mult = modifiedSig / initSig
# Ensure consistent results - round off a little to avoid float errors
return floatUnerr(mult)

View File

@@ -24,7 +24,7 @@ from eos.utils.stats import DmgTypes
from graphs.data.base import PointGetter, SmoothPointGetter
from service.settings import GraphSettings
from .calc.application import getApplicationPerKey
from .calc.projected import getTpMult, getWebbedSpeed
from .calc.projected import getScramRange, getScrammables, getTackledSpeed, getSigRadiusMult
def applyDamage(dmgMap, applicationMap, tgtResists):
@@ -138,8 +138,11 @@ class XDistanceMixin(SmoothPointGetter):
# Prepare time cache here because we need to do it only once,
# and this function is called once per point info fetch
self._prepareTimeCache(src=src, maxTime=miscParams['time'])
applyProjected = GraphSettings.getInstance().get('applyProjected')
return {
'applyProjected': GraphSettings.getInstance().get('applyProjected'),
'applyProjected': applyProjected,
'srcScramRange': getScramRange(src=src) if applyProjected else None,
'tgtScrammables': getScrammables(tgt=tgt) if applyProjected else (),
'dmgMap': self._getDamagePerKey(src=src, time=miscParams['time']),
'tgtResists': tgt.getResists()}
@@ -151,18 +154,22 @@ class XDistanceMixin(SmoothPointGetter):
webMods, tpMods = self.graph._projectedCache.getProjModData(src)
webDrones, tpDrones = self.graph._projectedCache.getProjDroneData(src)
webFighters, tpFighters = self.graph._projectedCache.getProjFighterData(src)
tgtSpeed = getWebbedSpeed(
tgtSpeed = getTackledSpeed(
src=src,
tgt=tgt,
currentUnwebbedSpeed=tgtSpeed,
currentUntackledSpeed=tgtSpeed,
srcScramRange=commonData['srcScramRange'],
tgtScrammables=commonData['tgtScrammables'],
webMods=webMods,
webDrones=webDrones,
webFighters=webFighters,
distance=distance)
tgtSigRadius = tgtSigRadius * getTpMult(
tgtSigRadius = tgtSigRadius * getSigRadiusMult(
src=src,
tgt=tgt,
tgtSpeed=tgtSpeed,
srcScramRange=commonData['srcScramRange'],
tgtScrammables=commonData['tgtScrammables'],
tpMods=tpMods,
tpDrones=tpDrones,
tpFighters=tpFighters,
@@ -189,21 +196,27 @@ class XTimeMixin(PointGetter):
tgtSpeed = miscParams['tgtSpeed']
tgtSigRadius = tgt.getSigRadius()
if GraphSettings.getInstance().get('applyProjected'):
srcScramRange = getScramRange(src=src)
tgtScrammables = getScrammables(tgt=tgt)
webMods, tpMods = self.graph._projectedCache.getProjModData(src)
webDrones, tpDrones = self.graph._projectedCache.getProjDroneData(src)
webFighters, tpFighters = self.graph._projectedCache.getProjFighterData(src)
tgtSpeed = getWebbedSpeed(
tgtSpeed = getTackledSpeed(
src=src,
tgt=tgt,
currentUnwebbedSpeed=tgtSpeed,
currentUntackledSpeed=tgtSpeed,
srcScramRange=srcScramRange,
tgtScrammables=tgtScrammables,
webMods=webMods,
webDrones=webDrones,
webFighters=webFighters,
distance=miscParams['distance'])
tgtSigRadius = tgtSigRadius * getTpMult(
tgtSigRadius = tgtSigRadius * getSigRadiusMult(
src=src,
tgt=tgt,
tgtSpeed=tgtSpeed,
srcScramRange=srcScramRange,
tgtScrammables=tgtScrammables,
tpMods=tpMods,
tpDrones=tpDrones,
tpFighters=tpFighters,
@@ -303,21 +316,27 @@ class XTgtSpeedMixin(SmoothPointGetter):
tgtSpeed = x
tgtSigRadius = tgt.getSigRadius()
if commonData['applyProjected']:
srcScramRange = getScramRange(src=src)
tgtScrammables = getScrammables(tgt=tgt)
webMods, tpMods = self.graph._projectedCache.getProjModData(src)
webDrones, tpDrones = self.graph._projectedCache.getProjDroneData(src)
webFighters, tpFighters = self.graph._projectedCache.getProjFighterData(src)
tgtSpeed = getWebbedSpeed(
tgtSpeed = getTackledSpeed(
src=src,
tgt=tgt,
currentUnwebbedSpeed=tgtSpeed,
currentUntackledSpeed=tgtSpeed,
srcScramRange=srcScramRange,
tgtScrammables=tgtScrammables,
webMods=webMods,
webDrones=webDrones,
webFighters=webFighters,
distance=miscParams['distance'])
tgtSigRadius = tgtSigRadius * getTpMult(
tgtSigRadius = tgtSigRadius * getSigRadiusMult(
src=src,
tgt=tgt,
tgtSpeed=tgtSpeed,
srcScramRange=srcScramRange,
tgtScrammables=tgtScrammables,
tpMods=tpMods,
tpDrones=tpDrones,
tpFighters=tpFighters,
@@ -347,21 +366,27 @@ class XTgtSigRadiusMixin(SmoothPointGetter):
tgtSpeed = miscParams['tgtSpeed']
tgtSigMult = 1
if GraphSettings.getInstance().get('applyProjected'):
srcScramRange = getScramRange(src=src)
tgtScrammables = getScrammables(tgt=tgt)
webMods, tpMods = self.graph._projectedCache.getProjModData(src)
webDrones, tpDrones = self.graph._projectedCache.getProjDroneData(src)
webFighters, tpFighters = self.graph._projectedCache.getProjFighterData(src)
tgtSpeed = getWebbedSpeed(
tgtSpeed = getTackledSpeed(
src=src,
tgt=tgt,
currentUnwebbedSpeed=tgtSpeed,
currentUntackledSpeed=tgtSpeed,
srcScramRange=srcScramRange,
tgtScrammables=tgtScrammables,
webMods=webMods,
webDrones=webDrones,
webFighters=webFighters,
distance=miscParams['distance'])
tgtSigMult = getTpMult(
tgtSigMult = getSigRadiusMult(
src=src,
tgt=tgt,
tgtSpeed=tgtSpeed,
srcScramRange=srcScramRange,
tgtScrammables=tgtScrammables,
tpMods=tpMods,
tpDrones=tpDrones,
tpFighters=tpFighters,

View File

@@ -106,7 +106,9 @@ class GraphCanvasPanel(wx.Panel):
legendData = []
chosenX = self.graphFrame.ctrlPanel.xType
chosenY = self.graphFrame.ctrlPanel.yType
self.subplot.set(xlabel=self.graphFrame.ctrlPanel.formatLabel(chosenX), ylabel=self.graphFrame.ctrlPanel.formatLabel(chosenY))
self.subplot.set(
xlabel=self.graphFrame.ctrlPanel.formatLabel(chosenX),
ylabel=self.graphFrame.ctrlPanel.formatLabel(chosenY))
mainInput, miscInputs = self.graphFrame.ctrlPanel.getValues()
view = self.graphFrame.getView()
@@ -212,14 +214,11 @@ class GraphCanvasPanel(wx.Panel):
def addYMark(val):
if val is None:
return
rounded = roundToPrec(val, 4)
# If due to some bug or insufficient plot density we're
# out of bounds, do not add anything
if minY <= val <= maxY:
if abs(val) < 0.0001:
val = 0
else:
val = roundToPrec(val, 4)
yMarks.add(val)
if minY <= val <= maxY or minY <= rounded <= maxY:
yMarks.add(rounded)
for source, target in iterList:
xs, ys = plotData[(source, target)]

View File

@@ -54,10 +54,13 @@ class BaseWrapper:
return self.item.name
return ''
def getMaxVelocity(self, extraMultipliers=None):
def getMaxVelocity(self, extraMultipliers=None, ignoreAfflictors=()):
if self.isFit:
if extraMultipliers:
maxVelocity = self.item.ship.getModifiedItemAttrWithExtraMods('maxVelocity', extraMultipliers=extraMultipliers)
if extraMultipliers or ignoreAfflictors:
maxVelocity = self.item.ship.getModifiedItemAttrExtended(
'maxVelocity',
extraMultipliers=extraMultipliers,
ignoreAfflictors=ignoreAfflictors)
else:
maxVelocity = self.item.ship.getModifiedItemAttr('maxVelocity')
elif self.isProfile:
@@ -68,10 +71,13 @@ class BaseWrapper:
maxVelocity = None
return maxVelocity
def getSigRadius(self, extraMultipliers=None):
def getSigRadius(self, extraMultipliers=None, ignoreAfflictors=()):
if self.isFit:
if extraMultipliers:
sigRadius = self.item.ship.getModifiedItemAttrWithExtraMods('signatureRadius', extraMultipliers=extraMultipliers)
if extraMultipliers or ignoreAfflictors:
sigRadius = self.item.ship.getModifiedItemAttrExtended(
'signatureRadius',
extraMultipliers=extraMultipliers,
ignoreAfflictors=ignoreAfflictors)
else:
sigRadius = self.item.ship.getModifiedItemAttr('signatureRadius')
elif self.isProfile:

View File

@@ -17,7 +17,7 @@ class GraphDmgApplyProjectedMenu(ContextMenuUnconditional):
return srcContext == 'dmgStatsGraph'
def getText(self, callingWindow, itmContext):
return 'Apply Attacker Webs and TPs'
return 'Apply Projected Items'
def activate(self, callingWindow, fullContext, i):
self.settings.set('applyProjected', not self.settings.get('applyProjected'))

View File

@@ -273,7 +273,15 @@ class ExportToEve(AuxiliaryFrame):
sEsi = Esi.getInstance()
sFit = Fit.getInstance()
data = sPort.exportESI(sFit.getFit(fitID))
try:
data = sPort.exportESI(sFit.getFit(fitID))
except ESIExportException as e:
msg = str(e)
if not msg:
msg = "Failed to generate export data"
pyfalog.warning(msg)
self.statusbar.SetStatusText(msg, 1)
return
activeChar = self.getActiveCharacter()
if activeChar is None:
msg = "Need at least one ESI character to export"