Apply all webs including drones to target

This commit is contained in:
DarkPhoenix
2019-07-08 18:48:25 +03:00
parent d7e45b0f76
commit 1c120f2fd6
4 changed files with 55 additions and 11 deletions

View File

@@ -38,8 +38,8 @@ class GraphDmgDroneModeMenu(ContextMenuUnconditional):
self.idOptionMap = {}
optionMap = OrderedDict([
(GraphDpsDroneMode.auto, 'Auto'),
(GraphDpsDroneMode.followAttacker, 'Stick to Attacker'),
(GraphDpsDroneMode.followTarget, 'Stick to Target')])
(GraphDpsDroneMode.followTarget, 'Stick to Target'),
(GraphDpsDroneMode.followAttacker, 'Stick to Attacker')])
for option, label in optionMap.items():
menuId = ContextMenuUnconditional.nextID()
item = wx.MenuItem(m, menuId, label, kind=wx.ITEM_CHECK)

View File

@@ -171,7 +171,7 @@ def getFighterAbilityMult(fighter, ability, fit, distance, tgtSpeed, tgtSigRadiu
return mult
def applyWebs(tgt, currentUnwebbedSpeed, webMods, distance):
def applyWebs(fit, tgt, currentUnwebbedSpeed, webMods, webDrones, webFighters, distance):
if tgt.ship.getModifiedItemAttr('disallowOffensiveModifiers'):
return currentUnwebbedSpeed
unwebbedSpeed = tgt.ship.getModifiedItemAttr('maxVelocity')
@@ -181,11 +181,46 @@ def applyWebs(tgt, currentUnwebbedSpeed, webMods, distance):
currentWebbedSpeed = 0
else:
appliedMultipliers = {}
# Modules first, they are applied always the same way
for boost, optimal, falloff, stackingChain, resistanceAttrID in webMods:
appliedBoost = boost * _calcRangeFactor(atkOptimalRange=optimal, atkFalloffRange=falloff, distance=distance)
if appliedBoost:
appliedMultipliers.setdefault(stackingChain, []).append((1 + appliedBoost / 100, resistanceAttrID))
webbedSpeed = tgt.ship.getModifiedItemAttrWithExtraMods('maxVelocity', extraMultipliers=appliedMultipliers)
# Drones and fighters
mobileWebs = []
mobileWebs.extend(webFighters)
# Drones have range limit
if distance <= fit.extraAttributes['droneControlRange']:
mobileWebs.extend(webDrones)
atkRadius = fit.ship.getModifiedItemAttr('radius')
# As mobile webs either follow the target or stick to the attacking ship,
# if target is within mobile web optimal - it can be applied unconditionally
longEnoughMws = [mw for mw in mobileWebs if distance <= mw.optimal - atkRadius + mw.radius]
if longEnoughMws:
for mwData in longEnoughMws:
appliedMultipliers.setdefault(mwData.stackingGroup, []).append((1 + mwData.boost / 100, mwData.resAttrID))
mobileWebs.remove(mwData)
webbedSpeed = tgt.ship.getModifiedItemAttrWithExtraMods('maxVelocity', extraMultipliers=appliedMultipliers)
# Apply remaining webs, from fastest to slowest
droneOpt = GraphSettings.getInstance().get('mobileDroneMode')
while mobileWebs:
# Process in batches unified by speed to save up resources
fastestMwSpeed = max(mobileWebs, key=lambda mw: mw.speed).speed
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 >= webbedSpeed) or droneOpt == GraphDpsDroneMode.followTarget:
appliedMwBoost = mwData.boost
# Otherwise project from the center of the ship
else:
appliedMwBoost = mwData.boost * _calcRangeFactor(
atkOptimalRange=mwData.optimal,
atkFalloffRange=mwData.falloff,
distance=distance + fit.ship.getModifiedItemAttr('radius') - mwData.radius)
appliedMultipliers.setdefault(mwData.stackingGroup, []).append((1 + appliedMwBoost / 100, mwData.resAttrID))
mobileWebs.remove(mwData)
webbedSpeed = tgt.ship.getModifiedItemAttrWithExtraMods('maxVelocity', extraMultipliers=appliedMultipliers)
currentWebbedSpeed = webbedSpeed * speedRatio
return currentWebbedSpeed

View File

@@ -182,9 +182,12 @@ class FitDamageStatsGraph(FitGraph):
webDrones, tpDrones = self._projectedCache.getProjDroneData(fit)
webFighters, tpFighters = self._projectedCache.getProjFighterData(fit)
tgtSpeed = applyWebs(
fit=fit,
tgt=tgt,
currentUnwebbedSpeed=miscInputMap['tgtSpeed'],
webMods=webMods,
webDrones=webDrones,
webFighters=webFighters,
distance=distance)
tgtSigRadius = tgt.ship.getModifiedItemAttr('signatureRadius') * applyTps(
tgt=tgt,

View File

@@ -18,11 +18,17 @@
# =============================================================================
from collections import namedtuple
from gui.builtinGraphs.base import FitDataCache
from eos.const import FittingModuleState
from eos.modifiedAttributeDict import getResistanceAttrID
ModProjData = namedtuple('ModProjData', ('boost', 'optimal', 'falloff', 'stackingGroup', 'resAttrID'))
MobileProjData = namedtuple('MobileProjData', ('boost', 'optimal', 'falloff', 'stackingGroup', 'resAttrID', 'speed', 'radius'))
class ProjectedDataCache(FitDataCache):
def getProjModData(self, fit):
@@ -38,14 +44,14 @@ class ProjectedDataCache(FitDataCache):
continue
for webEffectName in ('remoteWebifierFalloff', 'structureModuleEffectStasisWebifier'):
if webEffectName in mod.item.effects:
webMods.append((
webMods.append(ModProjData(
mod.getModifiedItemAttr('speedFactor'),
mod.maxRange or 0,
mod.falloff or 0,
'default',
getResistanceAttrID(modifyingItem=mod, effect=mod.item.effects[webEffectName])))
if 'doomsdayAOEWeb' in mod.item.effects:
webMods.append((
webMods.append(ModProjData(
mod.getModifiedItemAttr('speedFactor'),
max(0, (mod.maxRange or 0) + mod.getModifiedItemAttr('doomsdayAOERange') - fit.ship.getModifiedItemAttr('radius')),
mod.falloff or 0,
@@ -53,14 +59,14 @@ class ProjectedDataCache(FitDataCache):
getResistanceAttrID(modifyingItem=mod, effect=mod.item.effects['doomsdayAOEWeb'])))
for tpEffectName in ('remoteTargetPaintFalloff', 'structureModuleEffectTargetPainter'):
if tpEffectName in mod.item.effects:
tpMods.append((
tpMods.append(ModProjData(
mod.getModifiedItemAttr('signatureRadiusBonus'),
mod.maxRange or 0,
mod.falloff or 0,
'default',
getResistanceAttrID(modifyingItem=mod, effect=mod.item.effects[tpEffectName])))
if 'doomsdayAOEPaint' in mod.item.effects:
tpMods.append((
tpMods.append(ModProjData(
mod.getModifiedItemAttr('signatureRadiusBonus'),
max(0, (mod.maxRange or 0) + mod.getModifiedItemAttr('doomsdayAOERange') - fit.ship.getModifiedItemAttr('radius')),
mod.falloff or 0,
@@ -80,7 +86,7 @@ class ProjectedDataCache(FitDataCache):
if drone.amountActive <= 0:
continue
if 'remoteWebifierEntity' in drone.item.effects:
webDrones.extend(drone.amountActive * ((
webDrones.extend(drone.amountActive * (MobileProjData(
drone.getModifiedItemAttr('speedFactor'),
drone.maxRange or 0,
drone.falloff or 0,
@@ -89,7 +95,7 @@ class ProjectedDataCache(FitDataCache):
drone.getModifiedItemAttr('maxVelocity'),
drone.getModifiedItemAttr('radius')),))
if 'remoteTargetPaintEntity' in drone.item.effects:
tpDrones.extend(drone.amountActive * ((
tpDrones.extend(drone.amountActive * (MobileProjData(
drone.getModifiedItemAttr('signatureRadiusBonus'),
drone.maxRange or 0,
drone.falloff or 0,
@@ -103,7 +109,7 @@ class ProjectedDataCache(FitDataCache):
try:
projectedData = self._data[fit.ID]['fighters']
except KeyError:
# Format of items for both: (boost strength, optimal, falloff, stacking group, resistance attr ID, drone speed, drone radius)
# Format of items for both: (boost strength, optimal, falloff, stacking group, resistance attr ID, fighter speed, fighter radius)
webFighters = []
tpFighters = []
projectedData = self._data.setdefault(fit.ID, {})['fighters'] = (webFighters, tpFighters)
@@ -114,7 +120,7 @@ class ProjectedDataCache(FitDataCache):
if not ability.active:
continue
if ability.effect.name == 'fighterAbilityStasisWebifier':
webFighters.extend((
webFighters.append(MobileProjData(
fighter.getModifiedItemAttr('fighterAbilityStasisWebifierSpeedPenalty') * fighter.amountActive,
fighter.getModifiedItemAttr('fighterAbilityStasisWebifierOptimalRange'),
fighter.getModifiedItemAttr('fighterAbilityStasisWebifierFalloffRange'),