Apply all webs including drones to target
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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'),
|
||||
|
||||
Reference in New Issue
Block a user