Add scanres vs locktime on active fit graph as experimental feature
This commit is contained in:
@@ -39,6 +39,7 @@ loggingLevel = None
|
||||
logging_setup = None
|
||||
cipher = None
|
||||
clientHash = None
|
||||
experimentalFeatures = None
|
||||
|
||||
ESI_CACHE = 'esi_cache'
|
||||
|
||||
@@ -103,6 +104,7 @@ def defPaths(customSavePath=None):
|
||||
global cipher
|
||||
global clientHash
|
||||
global version
|
||||
global experimentalFeatures
|
||||
|
||||
pyfalog.debug("Configuring Pyfa")
|
||||
|
||||
@@ -168,6 +170,10 @@ def defPaths(customSavePath=None):
|
||||
|
||||
logPath = os.path.join(savePath, logFile)
|
||||
|
||||
experimentalFeatures = getattr(configforced, "experimentalFeatures", experimentalFeatures)
|
||||
if experimentalFeatures is None:
|
||||
experimentalFeatures = False
|
||||
|
||||
# DON'T MODIFY ANYTHING BELOW
|
||||
import eos.config
|
||||
|
||||
|
||||
38
eos/calc.py
38
eos/calc.py
@@ -18,6 +18,38 @@
|
||||
# =============================================================================
|
||||
|
||||
|
||||
import math
|
||||
|
||||
|
||||
# Just copy-paste penalization chain calculation code (with some modifications,
|
||||
# as multipliers arrive in different form) in here to not make actual attribute
|
||||
# calculations slower than they already are due to extra function calls
|
||||
def calculateMultiplier(multipliers):
|
||||
"""
|
||||
multipliers: dictionary in format:
|
||||
{stacking group name: [(mult, resist attr ID), (mult, resist attr ID)]}
|
||||
"""
|
||||
val = 1
|
||||
for penalizedMultipliers in multipliers.values():
|
||||
# A quick explanation of how this works:
|
||||
# 1: Bonuses and penalties are calculated seperately, so we'll have to filter each of them
|
||||
l1 = [v[0] for v in penalizedMultipliers if v[0] > 1]
|
||||
l2 = [v[0] for v in penalizedMultipliers if v[0] < 1]
|
||||
# 2: The most significant bonuses take the smallest penalty,
|
||||
# This means we'll have to sort
|
||||
abssort = lambda _val: -abs(_val - 1)
|
||||
l1.sort(key=abssort)
|
||||
l2.sort(key=abssort)
|
||||
# 3: The first module doesn't get penalized at all
|
||||
# Any module after the first takes penalties according to:
|
||||
# 1 + (multiplier - 1) * math.exp(- math.pow(i, 2) / 7.1289)
|
||||
for l in (l1, l2):
|
||||
for i in range(len(l)):
|
||||
bonus = l[i]
|
||||
val *= 1 + (bonus - 1) * math.exp(- i ** 2 / 7.1289)
|
||||
return val
|
||||
|
||||
|
||||
def calculateRangeFactor(srcOptimalRange, srcFalloffRange, distance, restrictedRange=True):
|
||||
"""Range strength/chance factor, applicable to guns, ewar, RRs, etc."""
|
||||
if distance is None:
|
||||
@@ -31,3 +63,9 @@ def calculateRangeFactor(srcOptimalRange, srcFalloffRange, distance, restrictedR
|
||||
return 1
|
||||
else:
|
||||
return 0
|
||||
|
||||
|
||||
def calculateLockTime(srcScanRes, tgtSigRadius):
|
||||
if not srcScanRes or not tgtSigRadius:
|
||||
return None
|
||||
return min(40000 / srcScanRes / math.asinh(tgtSigRadius) ** 2, 30 * 60)
|
||||
|
||||
@@ -21,13 +21,14 @@ import datetime
|
||||
import time
|
||||
from copy import deepcopy
|
||||
from itertools import chain
|
||||
from math import asinh, log, sqrt
|
||||
from math import log, sqrt
|
||||
|
||||
from logbook import Logger
|
||||
from sqlalchemy.orm import reconstructor, validates
|
||||
|
||||
import eos.db
|
||||
from eos import capSim
|
||||
from eos.calc import calculateMultiplier, calculateLockTime
|
||||
from eos.const import CalcType, FitSystemSecurity, FittingHardpoint, FittingModuleState, FittingSlot, ImplantLocation
|
||||
from eos.effectHandlerHelpers import (
|
||||
HandledBoosterList, HandledDroneCargoList, HandledImplantList,
|
||||
@@ -1529,9 +1530,7 @@ class Fit:
|
||||
def calculateLockTime(self, radius):
|
||||
scanRes = self.ship.getModifiedItemAttr("scanResolution")
|
||||
if scanRes is not None and scanRes > 0:
|
||||
# Yes, this function returns time in seconds, not miliseconds.
|
||||
# 40,000 is indeed the correct constant here.
|
||||
return min(40000 / scanRes / asinh(radius) ** 2, 30 * 60)
|
||||
return calculateLockTime(srcScanRes=scanRes, tgtSigRadius=radius)
|
||||
else:
|
||||
return self.ship.getModifiedItemAttr("scanSpeed") / 1000.0
|
||||
|
||||
@@ -1626,6 +1625,22 @@ class Fit:
|
||||
if ability.active:
|
||||
yield fighter, ability
|
||||
|
||||
def getDampMultScanRes(self):
|
||||
damps = []
|
||||
for mod in self.activeModulesIter():
|
||||
for effectName in ('remoteSensorDampFalloff', 'structureModuleEffectRemoteSensorDampener'):
|
||||
if effectName in mod.item.effects:
|
||||
damps.append((mod.getModifiedItemAttr('scanResolutionBonus'), 'default'))
|
||||
if 'doomsdayAOEDamp' in mod.item.effects:
|
||||
damps.append((mod.getModifiedItemAttr('scanResolutionBonus'), 'default'))
|
||||
for drone in self.activeDronesIter():
|
||||
if 'remoteSensorDampEntity' in drone.item.effects:
|
||||
damps.extend(drone.amountActive * ((drone.getModifiedItemAttr('scanResolutionBonus'), 'default'),))
|
||||
mults = {}
|
||||
for strength, stackingGroup in damps:
|
||||
mults.setdefault(stackingGroup, []).append((1 + strength / 100, None))
|
||||
return calculateMultiplier(mults)
|
||||
|
||||
def __deepcopy__(self, memo=None):
|
||||
fitCopy = Fit()
|
||||
# Character and owner are not copied
|
||||
|
||||
@@ -18,40 +18,9 @@
|
||||
# =============================================================================
|
||||
|
||||
|
||||
import math
|
||||
|
||||
from service.settings import GraphSettings
|
||||
|
||||
|
||||
# Just copy-paste penalization chain calculation code (with some modifications,
|
||||
# as multipliers arrive in different form) in here to not make actual attribute
|
||||
# calculations slower than they already are due to extra function calls
|
||||
def calculateMultiplier(multipliers):
|
||||
"""
|
||||
multipliers: dictionary in format:
|
||||
{stacking group name: [(mult, resist attr ID), (mult, resist attr ID)]}
|
||||
"""
|
||||
val = 1
|
||||
for penalizedMultipliers in multipliers.values():
|
||||
# A quick explanation of how this works:
|
||||
# 1: Bonuses and penalties are calculated seperately, so we'll have to filter each of them
|
||||
l1 = [v[0] for v in penalizedMultipliers if v[0] > 1]
|
||||
l2 = [v[0] for v in penalizedMultipliers if v[0] < 1]
|
||||
# 2: The most significant bonuses take the smallest penalty,
|
||||
# This means we'll have to sort
|
||||
abssort = lambda _val: -abs(_val - 1)
|
||||
l1.sort(key=abssort)
|
||||
l2.sort(key=abssort)
|
||||
# 3: The first module doesn't get penalized at all
|
||||
# Any module after the first takes penalties according to:
|
||||
# 1 + (multiplier - 1) * math.exp(- math.pow(i, 2) / 7.1289)
|
||||
for l in (l1, l2):
|
||||
for i in range(len(l)):
|
||||
bonus = l[i]
|
||||
val *= 1 + (bonus - 1) * math.exp(- i ** 2 / 7.1289)
|
||||
return val
|
||||
|
||||
|
||||
def checkLockRange(src, distance):
|
||||
if distance is None:
|
||||
return True
|
||||
|
||||
@@ -18,6 +18,9 @@
|
||||
# =============================================================================
|
||||
|
||||
|
||||
import config as _config
|
||||
|
||||
|
||||
from . import fitDamageStats
|
||||
from . import fitEwarStats
|
||||
from . import fitRemoteReps
|
||||
@@ -25,4 +28,7 @@ from . import fitShieldRegen
|
||||
from . import fitCapacitor
|
||||
from . import fitMobility
|
||||
from . import fitWarpTime
|
||||
from . import fitLockTime
|
||||
from . import fitLockTimeOutgoing
|
||||
|
||||
if _config.experimentalFeatures:
|
||||
from . import fitLockTimeIncoming
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
|
||||
import math
|
||||
|
||||
from eos.calc import calculateRangeFactor
|
||||
from graphs.calc import calculateMultiplier, checkLockRange, checkDroneControlRange
|
||||
from eos.calc import calculateMultiplier, calculateRangeFactor
|
||||
from graphs.calc import checkLockRange, checkDroneControlRange
|
||||
from graphs.data.base import SmoothPointGetter
|
||||
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
# =============================================================================
|
||||
|
||||
|
||||
from .graph import FitLockTimeGraph
|
||||
from .graph import FitLockTimeIncomingGraph
|
||||
|
||||
|
||||
FitLockTimeGraph.register()
|
||||
FitLockTimeIncomingGraph.register()
|
||||
39
graphs/data/fitLockTimeIncoming/getter.py
Normal file
39
graphs/data/fitLockTimeIncoming/getter.py
Normal file
@@ -0,0 +1,39 @@
|
||||
# =============================================================================
|
||||
# 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.calc import calculateLockTime
|
||||
from graphs.data.base import SmoothPointGetter
|
||||
|
||||
|
||||
class ScanRes2LockTimeGetter(SmoothPointGetter):
|
||||
|
||||
def _getCommonData(self, miscParams, src, tgt):
|
||||
if miscParams['applyDamps']:
|
||||
scanResMult = src.item.getDampMultScanRes()
|
||||
else:
|
||||
scanResMult = 1
|
||||
return {'scanResMult': scanResMult}
|
||||
|
||||
def _calculatePoint(self, x, miscParams, src, tgt, commonData):
|
||||
scanRes = x
|
||||
time = calculateLockTime(
|
||||
srcScanRes=scanRes * commonData['scanResMult'],
|
||||
tgtSigRadius=src.item.ship.getModifiedItemAttr('signatureRadius'))
|
||||
return time
|
||||
40
graphs/data/fitLockTimeIncoming/graph.py
Normal file
40
graphs/data/fitLockTimeIncoming/graph.py
Normal file
@@ -0,0 +1,40 @@
|
||||
# =============================================================================
|
||||
# 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/>.
|
||||
# =============================================================================
|
||||
|
||||
|
||||
import math
|
||||
|
||||
from graphs.data.base import FitGraph, XDef, YDef, Input, InputCheckbox
|
||||
from .getter import ScanRes2LockTimeGetter
|
||||
|
||||
|
||||
class FitLockTimeIncomingGraph(FitGraph):
|
||||
|
||||
# UI stuff
|
||||
internalName = 'lockTimeIncomingGraph'
|
||||
name = 'Lock Time (Incoming)'
|
||||
xDefs = [XDef(handle='scanRes', unit='mm', label='Scan Resolution', mainInput=('scanRes', 'mm'))]
|
||||
yDefs = [YDef(handle='time', unit='s', label='Lock time')]
|
||||
inputs = [Input(handle='scanRes', unit='mm', label='Scan Resolution', iconID=74, defaultValue=None, defaultRange=(100, 1000))]
|
||||
checkboxes = [InputCheckbox(handle='applyDamps', label='Apply sensor dampeners', defaultValue=True)]
|
||||
srcExtraCols = ('SigRadius', 'Damp ScanRes')
|
||||
|
||||
# Calculation stuff
|
||||
_limiters = {'scanRes': lambda src, tgt: (1, math.inf)}
|
||||
_getters = {('scanRes', 'time'): ScanRes2LockTimeGetter}
|
||||
24
graphs/data/fitLockTimeOutgoing/__init__.py
Normal file
24
graphs/data/fitLockTimeOutgoing/__init__.py
Normal file
@@ -0,0 +1,24 @@
|
||||
# =============================================================================
|
||||
# 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 .graph import FitLockTimeOutgoingGraph
|
||||
|
||||
|
||||
FitLockTimeOutgoingGraph.register()
|
||||
@@ -20,14 +20,14 @@
|
||||
|
||||
import math
|
||||
|
||||
from graphs.data.base import FitGraph, Input, XDef, YDef
|
||||
from graphs.data.base import FitGraph, XDef, YDef, Input
|
||||
from .getter import TgtSigRadius2LockTimeGetter
|
||||
|
||||
|
||||
class FitLockTimeGraph(FitGraph):
|
||||
class FitLockTimeOutgoingGraph(FitGraph):
|
||||
|
||||
# UI stuff
|
||||
internalName = 'lockTimeGraph'
|
||||
internalName = 'lockTimeOutgoingGraph'
|
||||
name = 'Lock Time'
|
||||
xDefs = [XDef(handle='tgtSigRad', unit='m', label='Target signature radius', mainInput=('tgtSigRad', 'm'))]
|
||||
yDefs = [YDef(handle='time', unit='s', label='Lock time')]
|
||||
@@ -18,11 +18,11 @@
|
||||
# =============================================================================
|
||||
|
||||
|
||||
from eos.calc import calculateMultiplier
|
||||
from eos.saveddata.damagePattern import DamagePattern
|
||||
from eos.saveddata.fit import Fit
|
||||
from eos.saveddata.targetProfile import TargetProfile
|
||||
from service.const import TargetResistMode
|
||||
from .calc import calculateMultiplier
|
||||
|
||||
|
||||
class BaseWrapper:
|
||||
|
||||
60
gui/builtinViewColumns/dampScanRes.py
Normal file
60
gui/builtinViewColumns/dampScanRes.py
Normal file
@@ -0,0 +1,60 @@
|
||||
# =============================================================================
|
||||
# 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/>.
|
||||
# =============================================================================
|
||||
|
||||
# noinspection PyPackageRequirements
|
||||
import wx
|
||||
|
||||
from eos.saveddata.fit import Fit
|
||||
from graphs.wrapper import BaseWrapper
|
||||
from gui.bitmap_loader import BitmapLoader
|
||||
from eos.utils.float import floatUnerr
|
||||
from gui.utils.numberFormatter import formatAmount
|
||||
from gui.viewColumn import ViewColumn
|
||||
|
||||
|
||||
class DampScanResColumn(ViewColumn):
|
||||
|
||||
name = 'Damp ScanRes'
|
||||
|
||||
def __init__(self, fittingView, params):
|
||||
ViewColumn.__init__(self, fittingView)
|
||||
self.imageId = fittingView.imageList.GetImageIndex(74, 'icons')
|
||||
self.bitmap = BitmapLoader.getBitmap(74, 'icons')
|
||||
self.mask = wx.LIST_MASK_IMAGE
|
||||
|
||||
def getText(self, stuff):
|
||||
if isinstance(stuff, BaseWrapper):
|
||||
stuff = stuff.item
|
||||
mult = 1
|
||||
if isinstance(stuff, Fit):
|
||||
mult = floatUnerr(stuff.getDampMultScanRes())
|
||||
if mult == 1:
|
||||
text = ''
|
||||
else:
|
||||
text = '{}%'.format(formatAmount((mult - 1) * 100, 3, 0, 0, forceSign=True))
|
||||
return text
|
||||
|
||||
def getImageId(self, stuff):
|
||||
return -1
|
||||
|
||||
def getToolTip(self, stuff):
|
||||
return 'Scan resolution dampening'
|
||||
|
||||
|
||||
DampScanResColumn.register()
|
||||
@@ -77,6 +77,7 @@ from gui.builtinViewColumns import ( # noqa: E402, F401
|
||||
baseIcon,
|
||||
baseName,
|
||||
capacitorUse,
|
||||
dampScanRes,
|
||||
graphColor,
|
||||
graphLightness,
|
||||
graphLineStyle,
|
||||
|
||||
Reference in New Issue
Block a user