129 lines
7.1 KiB
Python
129 lines
7.1 KiB
Python
# adaptiveArmorHardener
|
|
#
|
|
# Used by:
|
|
# Module: Reactive Armor Hardener
|
|
from logbook import Logger
|
|
import eos.config
|
|
|
|
pyfalog = Logger(__name__)
|
|
|
|
runTime = "late"
|
|
type = "active"
|
|
|
|
|
|
def handler(fit, module, context):
|
|
damagePattern = fit.damagePattern
|
|
# pyfalog.debug("==============================")
|
|
|
|
static_adaptive_behavior = eos.config.settings['useStaticAdaptiveArmorHardener']
|
|
|
|
if (damagePattern.emAmount == damagePattern.thermalAmount == damagePattern.kineticAmount == damagePattern.explosiveAmount) and static_adaptive_behavior:
|
|
# pyfalog.debug("Setting adaptivearmorhardener resists to uniform profile.")
|
|
for attr in ("armorEmDamageResonance", "armorThermalDamageResonance", "armorKineticDamageResonance", "armorExplosiveDamageResonance"):
|
|
fit.ship.multiplyItemAttr(attr, module.getModifiedItemAttr(attr), stackingPenalties=True, penaltyGroup="preMul")
|
|
return
|
|
|
|
# Skip if there is no damage pattern. Example: projected ships or fleet boosters
|
|
if damagePattern:
|
|
|
|
# Populate a tuple with the damage profile modified by current armor resists.
|
|
baseDamageTaken = (
|
|
damagePattern.emAmount * fit.ship.getModifiedItemAttr('armorEmDamageResonance'),
|
|
damagePattern.thermalAmount * fit.ship.getModifiedItemAttr('armorThermalDamageResonance'),
|
|
damagePattern.kineticAmount * fit.ship.getModifiedItemAttr('armorKineticDamageResonance'),
|
|
damagePattern.explosiveAmount * fit.ship.getModifiedItemAttr('armorExplosiveDamageResonance'),
|
|
)
|
|
# pyfalog.debug("Damage Adjusted for Armor Resists: %f/%f/%f/%f" % (baseDamageTaken[0], baseDamageTaken[1], baseDamageTaken[2], baseDamageTaken[3]))
|
|
|
|
resistanceShiftAmount = module.getModifiedItemAttr(
|
|
'resistanceShiftAmount') / 100 # The attribute is in percent and we want a fraction
|
|
RAHResistance = [
|
|
module.getModifiedItemAttr('armorEmDamageResonance'),
|
|
module.getModifiedItemAttr('armorThermalDamageResonance'),
|
|
module.getModifiedItemAttr('armorKineticDamageResonance'),
|
|
module.getModifiedItemAttr('armorExplosiveDamageResonance'),
|
|
]
|
|
|
|
# Simulate RAH cycles until the RAH either stops changing or enters a loop.
|
|
# The number of iterations is limited to prevent an infinite loop if something goes wrong.
|
|
cycleList = []
|
|
loopStart = -20
|
|
for num in range(50):
|
|
# pyfalog.debug("Starting cycle %d." % num)
|
|
# The strange order is to emulate the ingame sorting when different types have taken the same amount of damage.
|
|
# This doesn't take into account stacking penalties. In a few cases fitting a Damage Control causes an inaccurate result.
|
|
damagePattern_tuples = [
|
|
(0, baseDamageTaken[0] * RAHResistance[0], RAHResistance[0]),
|
|
(3, baseDamageTaken[3] * RAHResistance[3], RAHResistance[3]),
|
|
(2, baseDamageTaken[2] * RAHResistance[2], RAHResistance[2]),
|
|
(1, baseDamageTaken[1] * RAHResistance[1], RAHResistance[1]),
|
|
]
|
|
|
|
# Sort the tuple to drop the highest damage value to the bottom
|
|
sortedDamagePattern_tuples = sorted(damagePattern_tuples, key=lambda damagePattern: damagePattern[1])
|
|
|
|
if sortedDamagePattern_tuples[2][1] == 0:
|
|
# One damage type: the top damage type takes from the other three
|
|
# Since the resistances not taking damage will end up going to the type taking damage we just do the whole thing at once.
|
|
change0 = 1 - sortedDamagePattern_tuples[0][2]
|
|
change1 = 1 - sortedDamagePattern_tuples[1][2]
|
|
change2 = 1 - sortedDamagePattern_tuples[2][2]
|
|
change3 = -(change0 + change1 + change2)
|
|
elif sortedDamagePattern_tuples[1][1] == 0:
|
|
# Two damage types: the top two damage types take from the other two
|
|
# Since the resistances not taking damage will end up going equally to the types taking damage we just do the whole thing at once.
|
|
change0 = 1 - sortedDamagePattern_tuples[0][2]
|
|
change1 = 1 - sortedDamagePattern_tuples[1][2]
|
|
change2 = -(change0 + change1) / 2
|
|
change3 = -(change0 + change1) / 2
|
|
else:
|
|
# Three or four damage types: the top two damage types take from the other two
|
|
change0 = min(resistanceShiftAmount, 1 - sortedDamagePattern_tuples[0][2])
|
|
change1 = min(resistanceShiftAmount, 1 - sortedDamagePattern_tuples[1][2])
|
|
change2 = -(change0 + change1) / 2
|
|
change3 = -(change0 + change1) / 2
|
|
|
|
RAHResistance[sortedDamagePattern_tuples[0][0]] = sortedDamagePattern_tuples[0][2] + change0
|
|
RAHResistance[sortedDamagePattern_tuples[1][0]] = sortedDamagePattern_tuples[1][2] + change1
|
|
RAHResistance[sortedDamagePattern_tuples[2][0]] = sortedDamagePattern_tuples[2][2] + change2
|
|
RAHResistance[sortedDamagePattern_tuples[3][0]] = sortedDamagePattern_tuples[3][2] + change3
|
|
# pyfalog.debug("Resistances shifted to %f/%f/%f/%f" % ( RAHResistance[0], RAHResistance[1], RAHResistance[2], RAHResistance[3]))
|
|
|
|
# See if the current RAH profile has been encountered before, indicating a loop.
|
|
for i, val in enumerate(cycleList):
|
|
tolerance = 1e-06
|
|
if abs(RAHResistance[0] - val[0]) <= tolerance and \
|
|
abs(RAHResistance[1] - val[1]) <= tolerance and \
|
|
abs(RAHResistance[2] - val[2]) <= tolerance and \
|
|
abs(RAHResistance[3] - val[3]) <= tolerance:
|
|
loopStart = i
|
|
# pyfalog.debug("Loop found: %d-%d" % (loopStart, num))
|
|
break
|
|
if loopStart >= 0:
|
|
break
|
|
|
|
cycleList.append(list(RAHResistance))
|
|
|
|
# if loopStart < 0:
|
|
# pyfalog.error("Reactive Armor Hardener failed to find equilibrium. Damage profile after armor: {0}/{1}/{2}/{3}".format(
|
|
# baseDamageTaken[0], baseDamageTaken[1], baseDamageTaken[2], baseDamageTaken[3]))
|
|
|
|
# Average the profiles in the RAH loop, or the last 20 if it didn't find a loop.
|
|
loopCycles = cycleList[loopStart:]
|
|
numCycles = len(loopCycles)
|
|
average = [0, 0, 0, 0]
|
|
for cycle in loopCycles:
|
|
for i in range(4):
|
|
average[i] += cycle[i]
|
|
|
|
for i in range(4):
|
|
average[i] = round(average[i] / numCycles, 3)
|
|
|
|
# Set the new resistances
|
|
# pyfalog.debug("Setting new resist profile: %f/%f/%f/%f" % ( average[0], average[1], average[2],average[3]))
|
|
for i, attr in enumerate((
|
|
'armorEmDamageResonance', 'armorThermalDamageResonance', 'armorKineticDamageResonance',
|
|
'armorExplosiveDamageResonance')):
|
|
module.increaseItemAttr(attr, average[i] - module.getModifiedItemAttr(attr))
|
|
fit.ship.multiplyItemAttr(attr, average[i], stackingPenalties=True, penaltyGroup="preMul")
|