Merge branch 'spoolup_support'

This commit is contained in:
DarkPhoenix
2018-12-10 09:19:40 +03:00
7 changed files with 120 additions and 86 deletions

View File

@@ -75,7 +75,7 @@ class FitDpsGraph(Graph):
pyfalog.critical(e) pyfalog.critical(e)
for mod in fit.modules: for mod in fit.modules:
dps, _ = mod.damageStats(fit.targetResists) dps = mod.damageStats(fit.targetResists)[1]
if mod.hardpoint == Hardpoint.TURRET: if mod.hardpoint == Hardpoint.TURRET:
if mod.state >= State.ACTIVE: if mod.state >= State.ACTIVE:
total += dps * self.calculateTurretMultiplier(mod, data) total += dps * self.calculateTurretMultiplier(mod, data)
@@ -88,7 +88,7 @@ class FitDpsGraph(Graph):
for drone in fit.drones: for drone in fit.drones:
multiplier = 1 if drone.getModifiedItemAttr("maxVelocity") > 1 else self.calculateTurretMultiplier( multiplier = 1 if drone.getModifiedItemAttr("maxVelocity") > 1 else self.calculateTurretMultiplier(
drone, data) drone, data)
dps, _ = drone.damageStats(fit.targetResists) dps = drone.damageStats(fit.targetResists)[0]
total += dps * multiplier total += dps * multiplier
# this is janky as fuck # this is janky as fuck
@@ -98,7 +98,7 @@ class FitDpsGraph(Graph):
for ability in fighter.abilities: for ability in fighter.abilities:
if ability.dealsDamage and ability.active: if ability.dealsDamage and ability.active:
multiplier = self.calculateFighterMissileMultiplier(ability, data) multiplier = self.calculateFighterMissileMultiplier(ability, data)
dps, _ = ability.damageStats(fit.targetResists) dps = ability.damageStats(fit.targetResists)[0]
total += dps * multiplier total += dps * multiplier
return total return total

View File

@@ -120,9 +120,11 @@ class Drone(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
def hasAmmo(self): def hasAmmo(self):
return self.charge is not None return self.charge is not None
@property def getDps(self):
def dps(self): return self.damageStats()[0]
return self.damageStats()
def getVolley(self):
return self.damageStats()[1]
def changeType(self, typeID): def changeType(self, typeID):
self.itemID = typeID self.itemID = typeID

View File

@@ -172,9 +172,11 @@ class Fighter(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
def hasAmmo(self): def hasAmmo(self):
return self.charge is not None return self.charge is not None
@property def getDps(self):
def dps(self): return self.damageStats()[0]
return self.damageStats()
def getVolley(self):
return self.damageStats()[1]
def damageStats(self, targetResists=None): def damageStats(self, targetResists=None):
if self.__dps is None: if self.__dps is None:

View File

@@ -120,10 +120,10 @@ class Fit(object):
def build(self): def build(self):
self.__extraDrains = [] self.__extraDrains = []
self.__ehp = None self.__ehp = None
self.__weaponDPS = None self.__weaponDps = None
self.__minerYield = None self.__minerYield = None
self.__weaponVolley = None self.__weaponVolley = None
self.__droneDPS = None self.__droneDps = None
self.__droneVolley = None self.__droneVolley = None
self.__droneYield = None self.__droneYield = None
self.__sustainableTank = None self.__sustainableTank = None
@@ -154,9 +154,11 @@ class Fit(object):
@targetResists.setter @targetResists.setter
def targetResists(self, targetResists): def targetResists(self, targetResists):
self.__targetResists = targetResists self.__targetResists = targetResists
self.__weaponDPS = None self.__weaponDps = None
self.__weaponDpsSpool = None
self.__weaponVolley = None self.__weaponVolley = None
self.__droneDPS = None self.__weaponVolleySpool = None
self.__droneDps = None
self.__droneVolley = None self.__droneVolley = None
@property @property
@@ -277,41 +279,41 @@ class Fit(object):
def projectedFighters(self): def projectedFighters(self):
return self.__projectedFighters return self.__projectedFighters
@property def getWeaponDps(self, spool=False):
def weaponDPS(self): if spool:
if self.__weaponDPS is None: if self.__weaponDpsSpool is None:
self.calculateWeaponStats()
return self.__weaponDpsSpool
else:
if self.__weaponDps is None:
self.calculateWeaponStats()
return self.__weaponDps
def getWeaponVolley(self, spool=False):
if spool:
if self.__weaponVolleySpool is None:
self.calculateWeaponStats()
return self.__weaponVolleySpool
else:
if self.__weaponVolley is None:
self.calculateWeaponStats()
return self.__weaponVolley
def getDroneDps(self):
if self.__droneDps is None:
self.calculateWeaponStats() self.calculateWeaponStats()
return self.__droneDps
return self.__weaponDPS def getDroneVolley(self):
@property
def weaponVolley(self):
if self.__weaponVolley is None:
self.calculateWeaponStats()
return self.__weaponVolley
@property
def droneDPS(self):
if self.__droneDPS is None:
self.calculateWeaponStats()
return self.__droneDPS
@property
def droneVolley(self):
if self.__droneVolley is None: if self.__droneVolley is None:
self.calculateWeaponStats() self.calculateWeaponStats()
return self.__droneVolley return self.__droneVolley
@property def getTotalDps(self, spool=False):
def totalDPS(self): return self.getDroneDps() + self.getWeaponDps(spool=spool)
return self.droneDPS + self.weaponDPS
@property def getTotalVolley(self, spool=False):
def totalVolley(self): return self.getDroneVolley() + self.getWeaponVolley(spool=spool)
return self.droneVolley + self.weaponVolley
@property @property
def minerYield(self): def minerYield(self):
@@ -409,12 +411,14 @@ class Fit(object):
def clear(self, projected=False, command=False): def clear(self, projected=False, command=False):
self.__effectiveTank = None self.__effectiveTank = None
self.__weaponDPS = None self.__weaponDps = None
self.__minerYield = None self.__weaponDpsSpool = None
self.__weaponVolley = None self.__weaponVolley = None
self.__weaponVolleySpool = None
self.__minerYield = None
self.__effectiveSustainableTank = None self.__effectiveSustainableTank = None
self.__sustainableTank = None self.__sustainableTank = None
self.__droneDPS = None self.__droneDps = None
self.__droneVolley = None self.__droneVolley = None
self.__droneYield = None self.__droneYield = None
self.__ehp = None self.__ehp = None
@@ -1538,29 +1542,35 @@ class Fit(object):
self.__droneYield = droneYield self.__droneYield = droneYield
def calculateWeaponStats(self): def calculateWeaponStats(self):
weaponDPS = 0 weaponDps = 0
droneDPS = 0 weaponDpsSpool = 0
droneDps = 0
weaponVolley = 0 weaponVolley = 0
weaponVolleySpool = 0
droneVolley = 0 droneVolley = 0
for mod in self.modules: for mod in self.modules:
dps, volley = mod.damageStats(self.targetResists) dps, dpsSpool, volley, volleySpool = mod.damageStats(self.targetResists)
weaponDPS += dps weaponDps += dps
weaponDpsSpool += dpsSpool
weaponVolley += volley weaponVolley += volley
weaponVolleySpool += volleySpool
for drone in self.drones: for drone in self.drones:
dps, volley = drone.damageStats(self.targetResists) dps, volley = drone.damageStats(self.targetResists)
droneDPS += dps droneDps += dps
droneVolley += volley droneVolley += volley
for fighter in self.fighters: for fighter in self.fighters:
dps, volley = fighter.damageStats(self.targetResists) dps, volley = fighter.damageStats(self.targetResists)
droneDPS += dps droneDps += dps
droneVolley += volley droneVolley += volley
self.__weaponDPS = weaponDPS self.__weaponDps = weaponDps
self.__weaponDpsSpool = weaponDpsSpool
self.__weaponVolley = weaponVolley self.__weaponVolley = weaponVolley
self.__droneDPS = droneDPS self.__weaponVolleySpool = weaponVolleySpool
self.__droneDps = droneDps
self.__droneVolley = droneVolley self.__droneVolley = droneVolley
@property @property

View File

@@ -169,8 +169,10 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
self.__charge = None self.__charge = None
self.__dps = None self.__dps = None
self.__miningyield = None self.__dpsSpool = None
self.__volley = None self.__volley = None
self.__volleySpool = None
self.__miningyield = None
self.__reloadTime = None self.__reloadTime = None
self.__reloadForce = None self.__reloadForce = None
self.__chargeCycles = None self.__chargeCycles = None
@@ -414,7 +416,9 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
def damageStats(self, targetResists): def damageStats(self, targetResists):
if self.__dps is None: if self.__dps is None:
self.__dps = 0 self.__dps = 0
self.__dpsSpool = 0
self.__volley = 0 self.__volley = 0
self.__volleySpool = 0
if not self.isEmpty and self.state >= State.ACTIVE: if not self.isEmpty and self.state >= State.ACTIVE:
if self.charge: if self.charge:
@@ -425,7 +429,7 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
volley = sum([(func("%sDamage" % attr) or 0) * (1 - getattr(targetResists, "%sAmount" % attr, 0)) for attr in self.DAMAGE_TYPES]) volley = sum([(func("%sDamage" % attr) or 0) * (1 - getattr(targetResists, "%sAmount" % attr, 0)) for attr in self.DAMAGE_TYPES])
volley *= self.getModifiedItemAttr("damageMultiplier") or 1 volley *= self.getModifiedItemAttr("damageMultiplier") or 1
# Disintegrator-specific ramp-up multiplier # Disintegrator-specific ramp-up multiplier
volley *= (self.getModifiedItemAttr("damageMultiplierBonusMax") or 0) + 1 volleySpool = volley * ((self.getModifiedItemAttr("damageMultiplierBonusMax") or 0) + 1)
if volley: if volley:
cycleTime = self.cycleTime cycleTime = self.cycleTime
# Some weapons repeat multiple times in one cycle (think doomsdays) # Some weapons repeat multiple times in one cycle (think doomsdays)
@@ -436,9 +440,12 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
) )
self.__volley = volley self.__volley = volley
self.__dps = (volley * weaponDoT) / (cycleTime / 1000.0) self.__volleySpool = volleySpool
dpsFactor = weaponDoT / (cycleTime / 1000.0)
self.__dps = volley * dpsFactor
self.__dpsSpool = volleySpool * dpsFactor
return self.__dps, self.__volley return self.__dps, self.__dpsSpool, self.__volley, self.__volleySpool
@property @property
def miningStats(self): def miningStats(self):
@@ -459,13 +466,17 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
return self.__miningyield return self.__miningyield
@property def getDps(self, spool=False):
def dps(self): if spool:
return self.damageStats(None)[0] return self.damageStats(None)[1]
else:
return self.damageStats(None)[0]
@property def getVolley(self, spool=False):
def volley(self): if spool:
return self.damageStats(None)[1] return self.damageStats(None)[3]
else:
return self.damageStats(None)[2]
@property @property
def reloadTime(self): def reloadTime(self):

View File

@@ -147,28 +147,36 @@ class FirepowerViewFull(StatsView):
self.stEff.Show() self.stEff.Show()
else: else:
self.stEff.Hide() self.stEff.Hide()
def dpsToolTip(preSpool, postSpool, fmt_options):
if preSpool == postSpool:
return "{}".format(formatAmount(preSpool, *fmt_options))
else:
return "{}-{}".format(formatAmount(preSpool, *fmt_options), formatAmount(postSpool, *fmt_options))
stats = (("labelFullDpsWeapon", lambda: fit.weaponDPS, 3, 0, 0, "%s DPS", None), stats = (("labelFullDpsWeapon", lambda: fit.getWeaponDps(spool=False), lambda: fit.getWeaponDps(spool=True), 3, 0, 0, "%s DPS", None),
("labelFullDpsDrone", lambda: fit.droneDPS, 3, 0, 0, "%s DPS", None), ("labelFullDpsDrone", lambda: fit.getDroneDps(), lambda: fit.getDroneDps(), 3, 0, 0, "%s DPS", None),
("labelFullVolleyTotal", lambda: fit.totalVolley, 3, 0, 0, "%s", "Volley: %.1f"), ("labelFullVolleyTotal", lambda: fit.getTotalVolley(spool=False), lambda: fit.getTotalVolley(spool=True), 3, 0, 0, "%s", "Volley: %.1f"),
("labelFullDpsTotal", lambda: fit.totalDPS, 3, 0, 0, "%s", None)) ("labelFullDpsTotal", lambda: fit.getTotalDps(spool=False), lambda: fit.getTotalDps(spool=True), 3, 0, 0, "%s", "DPS: %s"))
# See GH issue # # See GH issue #
# if fit is not None and fit.totalYield > 0: # if fit is not None and fit.totalYield > 0:
# self.miningyield.Show() # self.miningyield.Show()
# else: # else:
# self.miningyield.Hide() # self.miningyield.Hide()
showPostSpool = True
counter = 0 counter = 0
for labelName, value, prec, lowest, highest, valueFormat, altFormat in stats: for labelName, preSpoolVal, postSpoolVal, prec, lowest, highest, valueFormat, altFormat in stats:
label = getattr(self, labelName) label = getattr(self, labelName)
value = value() if fit is not None else 0 val = (postSpoolVal() if showPostSpool else preSpoolVal()) if fit is not None else 0
value = value if value is not None else 0 val = val if val is not None else 0
if self._cachedValues[counter] != value: if self._cachedValues[counter] != val:
valueStr = formatAmount(value, prec, lowest, highest) valueStr = formatAmount(val, prec, lowest, highest)
label.SetLabel(valueFormat % valueStr) label.SetLabel(valueFormat % valueStr)
tipStr = valueFormat % valueStr if altFormat is None else altFormat % value valueStrTooltip = dpsToolTip(preSpoolVal(), postSpoolVal(), (prec, lowest, highest))
tipStr = valueFormat % valueStrTooltip # if altFormat is None else altFormat % val
label.SetToolTip(wx.ToolTip(tipStr)) label.SetToolTip(wx.ToolTip(tipStr))
self._cachedValues[counter] = value self._cachedValues[counter] = val
counter += 1 counter += 1
self.panel.Layout() self.panel.Layout()

View File

@@ -303,7 +303,7 @@ class EfsPort():
weaponSystems = [] weaponSystems = []
groups = {} groups = {}
for mod in fit.modules: for mod in fit.modules:
if mod.dps > 0: if mod.getDps() > 0:
# Group weapon + ammo combinations that occur more than once # Group weapon + ammo combinations that occur more than once
keystr = str(mod.itemID) + "-" + str(mod.chargeID) keystr = str(mod.itemID) + "-" + str(mod.chargeID)
if keystr in groups: if keystr in groups:
@@ -320,6 +320,7 @@ class EfsPort():
explosionRadius = 0 explosionRadius = 0
explosionVelocity = 0 explosionVelocity = 0
aoeFieldRange = 0 aoeFieldRange = 0
typeing = 'None'
if stats.charge: if stats.charge:
name = stats.item.name + ", " + stats.charge.name name = stats.item.name + ", " + stats.charge.name
else: else:
@@ -345,10 +346,10 @@ class EfsPort():
else: else:
maxRange = stats.maxRange maxRange = stats.maxRange
statDict = { statDict = {
"dps": stats.dps * n, "capUse": stats.capUse * n, "falloff": stats.falloff, "dps": stats.getDps(spool=True) * n, "capUse": stats.capUse * n, "falloff": stats.falloff,
"type": typeing, "name": name, "optimal": maxRange, "type": typeing, "name": name, "optimal": maxRange,
"numCharges": stats.numCharges, "numShots": stats.numShots, "reloadTime": stats.reloadTime, "numCharges": stats.numCharges, "numShots": stats.numShots, "reloadTime": stats.reloadTime,
"cycleTime": stats.cycleTime, "volley": stats.volley * n, "tracking": tracking, "cycleTime": stats.cycleTime, "volley": stats.getVolley(spool=True) * n, "tracking": tracking,
"maxVelocity": maxVelocity, "explosionDelay": explosionDelay, "damageReductionFactor": damageReductionFactor, "maxVelocity": maxVelocity, "explosionDelay": explosionDelay, "damageReductionFactor": damageReductionFactor,
"explosionRadius": explosionRadius, "explosionVelocity": explosionVelocity, "aoeFieldRange": aoeFieldRange, "explosionRadius": explosionRadius, "explosionVelocity": explosionVelocity, "aoeFieldRange": aoeFieldRange,
"damageMultiplierBonusMax": stats.getModifiedItemAttr("damageMultiplierBonusMax"), "damageMultiplierBonusMax": stats.getModifiedItemAttr("damageMultiplierBonusMax"),
@@ -356,19 +357,19 @@ class EfsPort():
} }
weaponSystems.append(statDict) weaponSystems.append(statDict)
for drone in fit.drones: for drone in fit.drones:
if drone.dps[0] > 0 and drone.amountActive > 0: if drone.getDps() > 0 and drone.amountActive > 0:
droneAttr = drone.getModifiedItemAttr droneAttr = drone.getModifiedItemAttr
# Drones are using the old tracking formula for trackingSpeed. This updates it to match turrets. # Drones are using the old tracking formula for trackingSpeed. This updates it to match turrets.
newTracking = droneAttr("trackingSpeed") / (droneAttr("optimalSigRadius") / 40000) newTracking = droneAttr("trackingSpeed") / (droneAttr("optimalSigRadius") / 40000)
statDict = { statDict = {
"dps": drone.dps[0], "cycleTime": drone.cycleTime, "type": "Drone", "dps": drone.getDps(), "cycleTime": drone.cycleTime, "type": "Drone",
"optimal": drone.maxRange, "name": drone.item.name, "falloff": drone.falloff, "optimal": drone.maxRange, "name": drone.item.name, "falloff": drone.falloff,
"maxSpeed": droneAttr("maxVelocity"), "tracking": newTracking, "maxSpeed": droneAttr("maxVelocity"), "tracking": newTracking,
"volley": drone.dps[1] "volley": drone.getVolley()
} }
weaponSystems.append(statDict) weaponSystems.append(statDict)
for fighter in fit.fighters: for fighter in fit.fighters:
if fighter.dps[0] > 0 and fighter.amountActive > 0: if fighter.getDps() > 0 and fighter.amountActive > 0:
fighterAttr = fighter.getModifiedItemAttr fighterAttr = fighter.getModifiedItemAttr
abilities = [] abilities = []
if "fighterAbilityAttackMissileDamageEM" in fighter.item.attributes.keys(): if "fighterAbilityAttackMissileDamageEM" in fighter.item.attributes.keys():
@@ -380,10 +381,10 @@ class EfsPort():
ability = EfsPort.getFighterAbilityData(fighterAttr, fighter, baseRef) ability = EfsPort.getFighterAbilityData(fighterAttr, fighter, baseRef)
abilities.append(ability) abilities.append(ability)
statDict = { statDict = {
"dps": fighter.dps[0], "type": "Fighter", "name": fighter.item.name, "dps": fighter.getDps(), "type": "Fighter", "name": fighter.item.name,
"maxSpeed": fighterAttr("maxVelocity"), "abilities": abilities, "maxSpeed": fighterAttr("maxVelocity"), "abilities": abilities,
"ehp": fighterAttr("shieldCapacity") / 0.8875 * fighter.amountActive, "ehp": fighterAttr("shieldCapacity") / 0.8875 * fighter.amountActive,
"volley": fighter.dps[1], "signatureRadius": fighterAttr("signatureRadius") "volley": fighter.getVolley(), "signatureRadius": fighterAttr("signatureRadius")
} }
weaponSystems.append(statDict) weaponSystems.append(statDict)
return weaponSystems return weaponSystems
@@ -622,11 +623,11 @@ class EfsPort():
shipSize = EfsPort.getShipSize(fit.ship.item.groupID) shipSize = EfsPort.getShipSize(fit.ship.item.groupID)
try: try:
dataDict = { dataDict = {
"name": fitName, "ehp": fit.ehp, "droneDPS": fit.droneDPS, "name": fitName, "ehp": fit.ehp, "droneDPS": fit.getDroneDps(),
"droneVolley": fit.droneVolley, "hp": fit.hp, "maxTargets": fit.maxTargets, "droneVolley": fit.getDroneVolley(), "hp": fit.hp, "maxTargets": fit.maxTargets,
"maxSpeed": fit.maxSpeed, "weaponVolley": fit.weaponVolley, "totalVolley": fit.totalVolley, "maxSpeed": fit.maxSpeed, "weaponVolley": fit.getWeaponVolley(spool=True), "totalVolley": fit.getTotalVolley(spool=True),
"maxTargetRange": fit.maxTargetRange, "scanStrength": fit.scanStrength, "maxTargetRange": fit.maxTargetRange, "scanStrength": fit.scanStrength,
"weaponDPS": fit.weaponDPS, "alignTime": fit.alignTime, "signatureRadius": fitModAttr("signatureRadius"), "weaponDPS": fit.getWeaponDps(spool=True), "alignTime": fit.alignTime, "signatureRadius": fitModAttr("signatureRadius"),
"weapons": weaponSystems, "scanRes": fitModAttr("scanResolution"), "weapons": weaponSystems, "scanRes": fitModAttr("scanResolution"),
"capUsed": fit.capUsed, "capRecharge": fit.capRecharge, "capUsed": fit.capUsed, "capRecharge": fit.capRecharge,
"rigSlots": fitModAttr("rigSlots"), "lowSlots": fitModAttr("lowSlots"), "rigSlots": fitModAttr("rigSlots"), "lowSlots": fitModAttr("lowSlots"),