class FitCapRegenGraph(FitGraph): # UI stuff internalName = 'capRegenGraph' name = 'Capacitor Regeneration' xDefs = [ XDef(handle='time', unit='s', label='Time', mainInput=('time', 's')), XDef(handle='capAmount', unit='GJ', label='Cap amount', mainInput=('capAmount', '%')), XDef(handle='capAmount', unit='%', label='Cap amount', mainInput=('capAmount', '%')) ] yDefs = [ YDef(handle='capAmount', unit='GJ', label='Cap amount'), YDef(handle='capRegen', unit='GJ/s', label='Cap regen') ] inputs = [ Input(handle='time', unit='s', label='Time', iconID=1392, defaultValue=120, defaultRange=(0, 300), mainOnly=True), Input(handle='capAmount', unit='%', label='Cap amount', iconID=1668, defaultValue=25, defaultRange=(0, 100), mainOnly=True) ] srcExtraCols = ('CapAmount', 'CapTime') # Calculation stuff _normalizers = { ('capAmount', '%'): lambda v, src, tgt: v / 100 * src.item.ship.getModifiedItemAttr( 'capacitorCapacity') } _limiters = { 'capAmount': lambda src, tgt: (0, src.item.ship.getModifiedItemAttr('capacitorCapacity')) } _getters = { ('time', 'capAmount'): Time2CapAmountGetter, ('time', 'capRegen'): Time2CapRegenGetter, ('capAmount', 'capAmount'): CapAmount2CapAmountGetter, ('capAmount', 'capRegen'): CapAmount2CapRegenGetter } _denormalizers = { ('capAmount', '%'): lambda v, src, tgt: v * 100 / src.item.ship.getModifiedItemAttr( 'capacitorCapacity') }
class FitWarpTimeGraph(FitGraph): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._subspeedCache = SubwarpSpeedCache() def _clearInternalCache(self, reason, extraData): if reason in (GraphCacheCleanupReason.fitChanged, GraphCacheCleanupReason.fitRemoved): self._subspeedCache.clearForFit(extraData) elif reason == GraphCacheCleanupReason.graphSwitched: self._subspeedCache.clearAll() # UI stuff internalName = 'warpTimeGraph' name = 'Warp Time' xDefs = [ XDef(handle='distance', unit='AU', label='Distance', mainInput=('distance', 'AU')), XDef(handle='distance', unit='km', label='Distance', mainInput=('distance', 'km')) ] yDefs = [YDef(handle='time', unit='s', label='Warp time')] inputs = [ Input(handle='distance', unit='AU', label='Distance', iconID=1391, defaultValue=20, defaultRange=(0, 50)), Input(handle='distance', unit='km', label='Distance', iconID=1391, defaultValue=1000, defaultRange=(150, 5000)) ] srcExtraCols = ('WarpSpeed', 'WarpDistance') # Calculation stuff _normalizers = { ('distance', 'AU'): lambda v, src, tgt: v * AU_METERS, ('distance', 'km'): lambda v, src, tgt: v * 1000 } _limiters = { 'distance': lambda src, tgt: (0, src.item.maxWarpDistance * AU_METERS) } _getters = {('distance', 'time'): Distance2TimeGetter} _denormalizers = { ('distance', 'AU'): lambda v, src, tgt: v / AU_METERS, ('distance', 'km'): lambda v, src, tgt: v / 1000 }
def xDefs(self): return [ XDef(handle='time', unit='s', label='Time', mainInput=('time', 's')), XDef(handle='shieldAmount', unit='EHP' if self.isEffective else 'HP', label='Shield amount', mainInput=('shieldAmount', '%')), XDef(handle='shieldAmount', unit='%', label='Shield amount', mainInput=('shieldAmount', '%')) ]
class FitMobilityGraph(FitGraph): # UI stuff internalName = 'mobilityGraph' name = 'Mobility' xDefs = [XDef(handle='time', unit='s', label='Time', mainInput=('time', 's'))] yDefs = [ YDef(handle='speed', unit='m/s', label='Speed'), YDef(handle='distance', unit='km', label='Distance'), YDef(handle='momentum', unit='Gkg⋅m/s', label='Momentum'), YDef(handle='bumpSpeed', unit='m/s', label='Target speed', selectorLabel='Bump speed'), YDef(handle='bumpDistance', unit='km', label='Target distance traveled', selectorLabel='Bump distance')] inputs = [ Input(handle='time', unit='s', label='Time', iconID=1392, defaultValue=10, defaultRange=(0, 30)), # Default values in target fields correspond to a random carrier/fax Input(handle='tgtMass', unit='Mkg', label='Target mass', iconID=76, defaultValue=1300, defaultRange=(100, 2500), conditions=[(None, ('bumpSpeed', 'm/s')), (None, ('bumpDistance', 'km'))], secondaryTooltip='Defined in millions of kilograms'), Input(handle='tgtInertia', unit=None, label='Target inertia factor', iconID=1401, defaultValue=0.015, defaultRange=(0.03, 0.1), conditions=[(None, ('bumpDistance', 'km'))], secondaryTooltip='Inertia Modifier attribute value of the target ship')] srcExtraCols = ('Speed', 'Agility') # Calculation stuff _normalizers = {('tgtMass', 'Mkg'): lambda v, src, tgt: None if v is None else v * 10 ** 6} _getters = { ('time', 'speed'): Time2SpeedGetter, ('time', 'distance'): Time2DistanceGetter, ('time', 'momentum'): Time2MomentumGetter, ('time', 'bumpSpeed'): Time2BumpSpeedGetter, ('time', 'bumpDistance'): Time2BumpDistanceGetter} _denormalizers = { ('distance', 'km'): lambda v, src, tgt: v / 1000, ('momentum', 'Gkg⋅m/s'): lambda v, src, tgt: v / 10 ** 9, ('bumpDistance', 'km'): lambda v, src, tgt: v / 1000}
class FitLockTimeGraph(FitGraph): # UI stuff internalName = 'lockTimeGraph' 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')] inputs = [ Input(handle='tgtSigRad', unit='m', label='Target signature', iconID=1390, defaultValue=None, defaultRange=(25, 500)) ] srcExtraCols = ('ScanResolution', ) # Calculation stuff _limiters = {'tgtSigRad': lambda src, tgt: (1, math.inf)} _getters = {('tgtSigRad', 'time'): TgtSigRadius2LockTimeGetter}
class FitMobilityGraph(FitGraph): # UI stuff internalName = 'mobilityGraph' name = 'Mobility' xDefs = [ XDef(handle='time', unit='s', label='Time', mainInput=('time', 's')) ] yDefs = [ YDef(handle='speed', unit='m/s', label='Speed'), YDef(handle='distance', unit='km', label='Distance') ] inputs = [ Input(handle='time', unit='s', label='Time', iconID=1392, defaultValue=10, defaultRange=(0, 30)) ] srcExtraCols = ('Speed', 'Agility') # Calculation stuff _getters = { ('time', 'speed'): Time2SpeedGetter, ('time', 'distance'): Time2DistanceGetter } _denormalizers = {('distance', 'km'): lambda v, src, tgt: v / 1000}
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='lockTime', unit='s', label='Lock time'), YDef(handle='lockUptime', unit='s', label='Lock uptime') ] 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', 'lockTime'): ScanRes2LockTimeGetter, ('scanRes', 'lockUptime'): ScanRes2LockUptimeGetter }
class FitDamageStatsGraph(FitGraph): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._timeCache = TimeCache() self._projectedCache = ProjectedDataCache() def _clearInternalCache(self, reason, extraData): # Here, we care only about fit changes and graph changes. # - Input changes are irrelevant as time cache cares only about # time input, and it regenerates once time goes beyond cached value # - Option changes are irrelevant as cache contains "raw" damage # values which do not rely on any graph options if reason in (GraphCacheCleanupReason.fitChanged, GraphCacheCleanupReason.fitRemoved): self._timeCache.clearForFit(extraData) self._projectedCache.clearForFit(extraData) elif reason == GraphCacheCleanupReason.graphSwitched: self._timeCache.clearAll() self._projectedCache.clearAll() # UI stuff internalName = 'dmgStatsGraph' name = 'Damage Stats' xDefs = [ XDef(handle='distance', unit='km', label='Distance', mainInput=('distance', 'km')), XDef(handle='time', unit='s', label='Time', mainInput=('time', 's')), XDef(handle='tgtSpeed', unit='m/s', label='Target speed', mainInput=('tgtSpeed', '%')), XDef(handle='tgtSpeed', unit='%', label='Target speed', mainInput=('tgtSpeed', '%')), XDef(handle='tgtSigRad', unit='m', label='Target signature radius', mainInput=('tgtSigRad', '%')), XDef(handle='tgtSigRad', unit='%', label='Target signature radius', mainInput=('tgtSigRad', '%')) ] inputs = [ Input( handle='distance', unit='km', label='Distance', iconID=1391, defaultValue=None, defaultRange=(0, 100), mainTooltip= 'Distance between the attacker and the target, as seen in overview (surface-to-surface)', secondaryTooltip= 'Distance between the attacker and the target, as seen in overview (surface-to-surface)\nWhen set, places the target that far away from the attacker\nWhen not set, attacker\'s weapons always hit the target' ), Input( handle='time', unit='s', label='Time', iconID=1392, defaultValue=None, defaultRange=(0, 80), secondaryTooltip= 'When set, uses attacker\'s exact damage stats at a given time\nWhen not set, uses attacker\'s damage stats as shown in stats panel of main window' ), Input(handle='tgtSpeed', unit='%', label='Target speed', iconID=1389, defaultValue=100, defaultRange=(0, 100)), Input(handle='tgtSigRad', unit='%', label='Target signature', iconID=1390, defaultValue=100, defaultRange=(100, 200), conditions=[(('tgtSigRad', 'm'), None), (('tgtSigRad', '%'), None)]) ] srcVectorDef = VectorDef(lengthHandle='atkSpeed', lengthUnit='%', angleHandle='atkAngle', angleUnit='degrees', label='Attacker') tgtVectorDef = VectorDef(lengthHandle='tgtSpeed', lengthUnit='%', angleHandle='tgtAngle', angleUnit='degrees', label='Target') hasTargets = True srcExtraCols = ('Dps', 'Volley', 'Speed', 'Radius') @property def yDefs(self): ignoreResists = GraphSettings.getInstance().get('ignoreResists') return [ YDef(handle='dps', unit=None, label='DPS' if ignoreResists else 'Effective DPS'), YDef(handle='volley', unit=None, label='Volley' if ignoreResists else 'Effective volley'), YDef(handle='damage', unit=None, label='Damage inflicted' if ignoreResists else 'Effective damage inflicted') ] @property def tgtExtraCols(self): cols = [] if not GraphSettings.getInstance().get('ignoreResists'): cols.append('Target Resists') cols.extend(('Speed', 'SigRadius', 'Radius')) return cols # Calculation stuff _normalizers = { ('distance', 'km'): lambda v, src, tgt: None if v is None else v * 1000, ('atkSpeed', '%'): lambda v, src, tgt: v / 100 * src.getMaxVelocity(), ('tgtSpeed', '%'): lambda v, src, tgt: v / 100 * tgt.getMaxVelocity(), ('tgtSigRad', '%'): lambda v, src, tgt: v / 100 * tgt.getSigRadius() } _limiters = {'time': lambda src, tgt: (0, 2500)} _getters = { ('distance', 'dps'): Distance2DpsGetter, ('distance', 'volley'): Distance2VolleyGetter, ('distance', 'damage'): Distance2InflictedDamageGetter, ('time', 'dps'): Time2DpsGetter, ('time', 'volley'): Time2VolleyGetter, ('time', 'damage'): Time2InflictedDamageGetter, ('tgtSpeed', 'dps'): TgtSpeed2DpsGetter, ('tgtSpeed', 'volley'): TgtSpeed2VolleyGetter, ('tgtSpeed', 'damage'): TgtSpeed2InflictedDamageGetter, ('tgtSigRad', 'dps'): TgtSigRadius2DpsGetter, ('tgtSigRad', 'volley'): TgtSigRadius2VolleyGetter, ('tgtSigRad', 'damage'): TgtSigRadius2InflictedDamageGetter } _denormalizers = { ('distance', 'km'): lambda v, src, tgt: None if v is None else v / 1000, ('tgtSpeed', '%'): lambda v, src, tgt: v * 100 / tgt.getMaxVelocity(), ('tgtSigRad', '%'): lambda v, src, tgt: v * 100 / tgt.getSigRadius() }
class FitRemoteRepsGraph(FitGraph): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._timeCache = TimeCache() def _clearInternalCache(self, reason, extraData): # Here, we care only about fit changes, graph changes and option switches # - Input changes are irrelevant as time cache cares only about # time input, and it regenerates once time goes beyond cached value if reason in (GraphCacheCleanupReason.fitChanged, GraphCacheCleanupReason.fitRemoved): self._timeCache.clearForFit(extraData) elif reason == GraphCacheCleanupReason.graphSwitched: self._timeCache.clearAll() # UI stuff internalName = 'remoteRepsGraph' name = 'Remote Repairs' xDefs = [ XDef(handle='distance', unit='km', label='Distance', mainInput=('distance', 'km')), XDef(handle='time', unit='s', label='Time', mainInput=('time', 's')) ] yDefs = [ YDef(handle='rps', unit='HP/s', label='Repair speed'), YDef(handle='total', unit='HP', label='Total repaired') ] inputs = [ Input( handle='time', unit='s', label='Time', iconID=1392, defaultValue=None, defaultRange=(0, 80), secondaryTooltip= 'When set, uses repairing ship\'s exact RR stats at a given time\nWhen not set, uses repairing ship\'s RR stats as shown in stats panel of main window' ), Input( handle='distance', unit='km', label='Distance', iconID=1391, defaultValue=None, defaultRange=(0, 100), mainTooltip= 'Distance between the repairing ship and the target, as seen in overview (surface-to-surface)', secondaryTooltip= 'Distance between the repairing ship and the target, as seen in overview (surface-to-surface)' ) ] srcExtraCols = ('ShieldRR', 'ArmorRR', 'HullRR') checkboxes = [ InputCheckbox(handle='ancReload', label='Reload ancillary RRs', defaultValue=True) ] # Calculation stuff _normalizers = { ('distance', 'km'): lambda v, src, tgt: None if v is None else v * 1000 } _limiters = {'time': lambda src, tgt: (0, 2500)} _getters = { ('distance', 'rps'): Distance2RpsGetter, ('distance', 'total'): Distance2RepAmountGetter, ('time', 'rps'): Time2RpsGetter, ('time', 'total'): Time2RepAmountGetter } _denormalizers = { ('distance', 'km'): lambda v, src, tgt: None if v is None else v / 1000 }
class FitCapacitorGraph(FitGraph): # UI stuff internalName = 'capacitorGraph' name = _t('Capacitor') xDefs = [ XDef(handle='time', unit='s', label=_t('Time'), mainInput=('time', 's')), XDef(handle='capAmount', unit='GJ', label=_t('Cap amount'), mainInput=('capAmount', '%')), XDef(handle='capAmount', unit='%', label=_t('Cap amount'), mainInput=('capAmount', '%')) ] yDefs = [ YDef(handle='capAmount', unit='GJ', label=_t('Cap amount')), YDef(handle='capRegen', unit='GJ/s', label=_t('Cap regen')) ] inputs = [ Input(handle='time', unit='s', label=_t('Time'), iconID=1392, defaultValue=120, defaultRange=(0, 300), conditions=[(('time', 's'), None)]), Input(handle='capAmount', unit='%', label=_t('Cap amount'), iconID=1668, defaultValue=25, defaultRange=(0, 100), conditions=[(('capAmount', 'GJ'), None), (('capAmount', '%'), None)]), Input(handle='capAmountT0', unit='%', label=_t('Starting cap amount'), iconID=1668, defaultValue=100, defaultRange=(0, 100), conditions=[(('time', 's'), None)]) ] checkboxes = [ InputCheckbox(handle='useCapsim', label=_t('Use capacitor simulator'), defaultValue=True, conditions=[(('time', 's'), ('capAmount', 'GJ'))]) ] srcExtraCols = ('CapAmount', 'CapTime') # Calculation stuff _normalizers = { ('capAmount', '%'): lambda v, src, tgt: v / 100 * src.item.ship.getModifiedItemAttr( 'capacitorCapacity'), ('capAmountT0', '%'): lambda v, src, tgt: None if v is None else v / 100 * src.item.ship. getModifiedItemAttr('capacitorCapacity') } _limiters = { 'time': lambda src, tgt: (0, 3600), 'capAmount': lambda src, tgt: (0, src.item.ship.getModifiedItemAttr('capacitorCapacity')), 'capAmountT0': lambda src, tgt: (0, src.item.ship.getModifiedItemAttr('capacitorCapacity')) } _getters = { ('time', 'capAmount'): Time2CapAmountGetter, ('time', 'capRegen'): Time2CapRegenGetter, ('capAmount', 'capAmount'): CapAmount2CapAmountGetter, ('capAmount', 'capRegen'): CapAmount2CapRegenGetter } _denormalizers = { ('capAmount', '%'): lambda v, src, tgt: v * 100 / src.item.ship.getModifiedItemAttr( 'capacitorCapacity') }
class FitEwarStatsGraph(FitGraph): # UI stuff internalName = 'ewarStatsGraph' name = 'Electronic Warfare Stats' xDefs = [ XDef(handle='distance', unit='km', label='Distance', mainInput=('distance', 'km')) ] yDefs = [ YDef(handle='neutStr', unit=None, label='Cap neutralized per second', selectorLabel='Neuts: cap per second'), YDef(handle='webStr', unit='%', label='Speed reduction', selectorLabel='Webs: speed reduction'), YDef(handle='ecmStrMax', unit=None, label='Combined ECM strength', selectorLabel='ECM: combined strength'), YDef(handle='dampStrLockRange', unit='%', label='Lock range reduction', selectorLabel='Damps: lock range reduction'), YDef(handle='tdStrOptimal', unit='%', label='Turret optimal range reduction', selectorLabel='TDs: turret optimal range reduction'), YDef(handle='gdStrRange', unit='%', label='Missile flight range reduction', selectorLabel='GDs: missile flight range reduction'), YDef(handle='tpStr', unit='%', label='Signature radius increase', selectorLabel='TPs: signature radius increase') ] inputs = [ Input(handle='distance', unit='km', label='Distance', iconID=1391, defaultValue=None, defaultRange=(0, 100)), Input(handle='resist', unit='%', label='Target resistance', iconID=1393, defaultValue=0, defaultRange=(0, 100)) ] # Calculation stuff _normalizers = { ('distance', 'km'): lambda v, src, tgt: None if v is None else v * 1000, ('resist', '%'): lambda v, src, tgt: None if v is None else v / 100 } _limiters = {'resist': lambda src, tgt: (0, 1)} _getters = { ('distance', 'neutStr'): Distance2NeutingStrGetter, ('distance', 'webStr'): Distance2WebbingStrGetter, ('distance', 'ecmStrMax'): Distance2EcmStrMaxGetter, ('distance', 'dampStrLockRange'): Distance2DampStrLockRangeGetter, ('distance', 'tdStrOptimal'): Distance2TdStrOptimalGetter, ('distance', 'gdStrRange'): Distance2GdStrRangeGetter, ('distance', 'tpStr'): Distance2TpStrGetter } _denormalizers = { ('distance', 'km'): lambda v, src, tgt: None if v is None else v / 1000 }
class FitEcmBurstScanresDampsGraph(FitGraph): # UI stuff hidden = True internalName = 'ecmBurstScanresDamps' name = 'ECM Burst + Scanres Damps' xDefs = [ XDef(handle='tgtDps', unit=None, label='Enemy DPS', mainInput=('tgtDps', None)), XDef(handle='tgtScanRes', unit='mm', label='Enemy scanres', mainInput=('tgtScanRes', 'mm')) ] yDefs = [ YDef(handle='srcDmg', unit=None, label='Damage inflicted'), YDef(handle='tgtLockTime', unit='s', label='Lock time'), YDef(handle='tgtLockUptime', unit='s', label='Lock uptime') ] inputs = [ Input(handle='tgtScanRes', unit='mm', label='Enemy scanres', iconID=74, defaultValue=700, defaultRange=(100, 1000)), Input(handle='tgtDps', unit=None, label='Enemy DPS', iconID=1432, defaultValue=200, defaultRange=(100, 600)), Input(handle='uptimeAdj', unit='s', label='Uptime adjustment', iconID=1392, defaultValue=1, defaultRange=(None, None), conditions=[(None, ('srcDmg', None))]), Input(handle='uptimeAmtLimit', unit=None, label='Max amount of uptimes', iconID=1397, defaultValue=3, defaultRange=(None, None), conditions=[(None, ('srcDmg', None))]) ] checkboxes = [ InputCheckbox(handle='applyDamps', label='Apply sensor dampeners', defaultValue=True), InputCheckbox(handle='applyDrones', label='Use drones', defaultValue=True, conditions=[(None, ('srcDmg', None))]) ] srcExtraCols = ('SigRadius', 'Damp ScanRes') # Calculation stuff _limiters = {'tgtScanRes': lambda src, tgt: (1, math.inf)} _getters = { ('tgtScanRes', 'tgtLockTime'): TgtScanRes2TgtLockTimeGetter, ('tgtScanRes', 'tgtLockUptime'): TgtScanRes2TgtLockUptimeGetter, ('tgtScanRes', 'srcDmg'): TgtScanRes2SrcDmgGetter, ('tgtDps', 'srcDmg'): TgtDps2SrcDmgGetter }
class FitShieldRegenGraph(FitGraph): # UI stuff internalName = 'shieldRegenGraph' name = 'Shield Regeneration' xDefs = [ XDef(handle='time', unit='s', label='Time', mainInput=('time', 's')), XDef(handle='shieldAmount', unit='EHP', label='Shield amount', mainInput=('shieldAmount', '%')), XDef(handle='shieldAmount', unit='HP', label='Shield amount', mainInput=('shieldAmount', '%')), XDef(handle='shieldAmount', unit='%', label='Shield amount', mainInput=('shieldAmount', '%')) ] yDefs = [ YDef(handle='shieldAmount', unit='EHP', label='Shield amount'), YDef(handle='shieldAmount', unit='HP', label='Shield amount'), YDef(handle='shieldRegen', unit='EHP/s', label='Shield regen'), YDef(handle='shieldRegen', unit='HP/s', label='Shield regen') ] inputs = [ Input(handle='time', unit='s', label='Time', iconID=1392, defaultValue=120, defaultRange=(0, 300), mainOnly=True), Input(handle='shieldAmount', unit='%', label='Shield amount', iconID=1384, defaultValue=25, defaultRange=(0, 100), mainOnly=True) ] srcExtraCols = ('ShieldAmount', 'ShieldTime') # Calculation stuff _normalizers = { ('shieldAmount', '%'): lambda v, src, tgt: v / 100 * src.item.ship.getModifiedItemAttr( 'shieldCapacity') } _limiters = { 'shieldAmount': lambda src, tgt: (0, src.item.ship.getModifiedItemAttr('shieldCapacity')) } _getters = { ('time', 'shieldAmount'): Time2ShieldAmountGetter, ('time', 'shieldRegen'): Time2ShieldRegenGetter, ('shieldAmount', 'shieldAmount'): ShieldAmount2ShieldAmountGetter, ('shieldAmount', 'shieldRegen'): ShieldAmount2ShieldRegenGetter } _denormalizers = { ('shieldAmount', '%'): lambda v, src, tgt: v * 100 / src.item.ship.getModifiedItemAttr( 'shieldCapacity'), ('shieldAmount', 'EHP'): lambda v, src, tgt: src.item.damagePattern.effectivify( src.item, v, 'shield'), ('shieldRegen', 'EHP/s'): lambda v, src, tgt: src.item.damagePattern.effectivify( src.item, v, 'shield') }