Add scanres vs locktime on active fit graph as experimental feature

This commit is contained in:
DarkPhoenix
2019-10-24 13:52:34 +03:00
parent 536eb1efa5
commit d1be0bb680
15 changed files with 242 additions and 44 deletions

View File

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

View File

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