diff --git a/.appveyor.yml b/.appveyor.yml
index 9bfedf65b..f2c16787f 100644
--- a/.appveyor.yml
+++ b/.appveyor.yml
@@ -33,11 +33,14 @@ for:
- sh: rm AppDir/python*.desktop
- sh: rm AppDir/usr/share/applications/*.desktop
- sh: rm AppDir/usr/share/metainfo/*.appdata.xml
+ - sh: unlink AppDir/AppRun
- sh: mkdir -p $DEPLOY_DIR
# run install pyfa packages and any other requirements
- sh: AppDir/usr/bin/python -s -m pip install -U pip setuptools==41.6.0 wheel pathlib2
- sh: AppDir/usr/bin/python -s -m pip install -r ../requirements.txt
+ # Speedup, but causes runtime incompatiblities
+ #- sh: AppDir/usr/bin/python -s -m pip install -f https://extras.wxpython.org/wxPython4/extras/linux/gtk3/ubuntu-18.04 -r ../requirements.txt
# Run scripts to prep pyfa data and build database
- sh: cd ../
@@ -53,9 +56,10 @@ for:
# Copy static AppImage files
- sh: cd dist_assets/linux
+ - sh: chmod +x AppRun
- sh: cp AppRun pyfa.desktop ../../build/AppDir/
- sh: cp pyfa.desktop ../../build/AppDir/usr/share/applications/
- - sh: cp org.pyfa.pyfa.appdata.xml ../../build/AppDir/usr/share/metainfo/
+ - sh: cp pyfa.appdata.xml ../../build/AppDir/usr/share/metainfo/
- sh: chmod +x pyfa && cp pyfa ../../build/AppDir/usr/bin
- sh: cd ../../
diff --git a/dist_assets/linux/AppRun b/dist_assets/linux/AppRun
old mode 100644
new mode 100755
diff --git a/dist_assets/linux/org.pyfa.pyfa.appdata.xml b/dist_assets/linux/pyfa.appdata.xml
similarity index 100%
rename from dist_assets/linux/org.pyfa.pyfa.appdata.xml
rename to dist_assets/linux/pyfa.appdata.xml
diff --git a/eos/saveddata/damagePattern.py b/eos/saveddata/damagePattern.py
index 3a9357873..bd792e733 100644
--- a/eos/saveddata/damagePattern.py
+++ b/eos/saveddata/damagePattern.py
@@ -216,11 +216,11 @@ class DamagePattern:
pattern.builtin = True
cls._builtins[id] = pattern
- def calculateEhp(self, fit):
+ def calculateEhp(self, item):
ehp = {}
for (type, attr) in (('shield', 'shieldCapacity'), ('armor', 'armorHP'), ('hull', 'hp')):
- rawCapacity = fit.ship.getModifiedItemAttr(attr)
- ehp[type] = self.effectivify(fit, rawCapacity, type)
+ rawCapacity = item.getModifiedItemAttr(attr)
+ ehp[type] = self.effectivify(item, rawCapacity, type)
return ehp
@@ -236,10 +236,10 @@ class DamagePattern:
ereps = {}
for field in tankInfo:
if field in typeMap:
- ereps[field] = self.effectivify(fit, tankInfo[field], typeMap[field])
+ ereps[field] = self.effectivify(fit.ship, tankInfo[field], typeMap[field])
return ereps
- def effectivify(self, fit, amount, type):
+ def effectivify(self, item, amount, type):
type = type if type != "hull" else ""
totalDamage = sum((self.emAmount, self.thermalAmount, self.kineticAmount, self.explosiveAmount))
specificDivider = 0
@@ -248,7 +248,7 @@ class DamagePattern:
attrName = "%s%sDamageResonance" % (type, damageType.capitalize())
attrName = attrName[0].lower() + attrName[1:]
- resonance = fit.ship.getModifiedItemAttr(attrName)
+ resonance = item.getModifiedItemAttr(attrName)
damage = getattr(self, "%sAmount" % damageType)
specificDivider += damage / float(totalDamage or 1) * resonance
diff --git a/eos/saveddata/drone.py b/eos/saveddata/drone.py
index 93c037bbd..cdefc1799 100644
--- a/eos/saveddata/drone.py
+++ b/eos/saveddata/drone.py
@@ -82,6 +82,7 @@ class Drone(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut, Mu
self.__baseRRAmount = None
self.__miningYield = None
self.__miningWaste = None
+ self.__ehp = None
self.__itemModifiedAttributes = ModifiedAttributeDict()
self.__itemModifiedAttributes.original = self._item.attributes
self.__itemModifiedAttributes.overrides = self._item.overrides
@@ -287,6 +288,29 @@ class Drone(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut, Mu
if delay is not None and speed is not None:
return delay / 1000.0 * speed
+ @property
+ def hp(self):
+ hp = {}
+ for (type, attr) in (('shield', 'shieldCapacity'), ('armor', 'armorHP'), ('hull', 'hp')):
+ hp[type] = self.getModifiedItemAttr(attr)
+
+ return hp
+
+ @property
+ def ehp(self):
+ if self.__ehp is None:
+ if self.owner is None or self.owner.damagePattern is None:
+ ehp = self.hp
+ else:
+ ehp = self.owner.damagePattern.calculateEhp(self)
+ self.__ehp = ehp
+ return self.__ehp
+
+ def calculateShieldRecharge(self):
+ capacity = self.getModifiedItemAttr("shieldCapacity")
+ rechargeRate = self.getModifiedItemAttr("shieldRechargeRate") / 1000.0
+ return 10 / rechargeRate * math.sqrt(0.25) * (1 - math.sqrt(0.25)) * capacity
+
# Had to add this to match the falloff property in modules.py
# Fscking ship scanners. If you find any other falloff attributes,
# Put them in the attrs tuple.
@@ -318,6 +342,7 @@ class Drone(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut, Mu
self.__baseRRAmount = None
self.__miningYield = None
self.__miningWaste = None
+ self.__ehp = None
self.itemModifiedAttributes.clear()
self.chargeModifiedAttributes.clear()
diff --git a/eos/saveddata/fighter.py b/eos/saveddata/fighter.py
index 2192aaeea..012e0b8ce 100644
--- a/eos/saveddata/fighter.py
+++ b/eos/saveddata/fighter.py
@@ -96,6 +96,7 @@ class Fighter(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
self.__charge = None
self.__baseVolley = None
self.__miningyield = None
+ self.__ehp = None
self.__itemModifiedAttributes = ModifiedAttributeDict()
self.__chargeModifiedAttributes = ModifiedAttributeDict()
@@ -345,6 +346,29 @@ class Fighter(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
if falloff is not None:
return falloff
+ @property
+ def hp(self):
+ hp = {}
+ for (type, attr) in (('shield', 'shieldCapacity'), ('armor', 'armorHP'), ('hull', 'hp')):
+ hp[type] = self.getModifiedItemAttr(attr)
+
+ return hp
+
+ @property
+ def ehp(self):
+ if self.__ehp is None:
+ if self.owner is None or self.owner.damagePattern is None:
+ ehp = self.hp
+ else:
+ ehp = self.owner.damagePattern.calculateEhp(self)
+ self.__ehp = ehp
+ return self.__ehp
+
+ def calculateShieldRecharge(self):
+ capacity = self.getModifiedItemAttr("shieldCapacity")
+ rechargeRate = self.getModifiedItemAttr("shieldRechargeRate") / 1000.0
+ return 10 / rechargeRate * math.sqrt(0.25) * (1 - math.sqrt(0.25)) * capacity
+
@validates("ID", "itemID", "chargeID", "amount")
def validator(self, key, val):
map = {
@@ -361,6 +385,7 @@ class Fighter(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
def clear(self):
self.__baseVolley = None
self.__miningyield = None
+ self.__ehp = None
self.itemModifiedAttributes.clear()
self.chargeModifiedAttributes.clear()
[x.clear() for x in self.abilities]
diff --git a/eos/saveddata/fit.py b/eos/saveddata/fit.py
index 700643ec9..64d8de84c 100644
--- a/eos/saveddata/fit.py
+++ b/eos/saveddata/fit.py
@@ -1469,7 +1469,7 @@ class Fit:
if self.damagePattern is None:
ehp = self.hp
else:
- ehp = self.damagePattern.calculateEhp(self)
+ ehp = self.damagePattern.calculateEhp(self.ship)
self.__ehp = ehp
return self.__ehp
diff --git a/graphs/wrapper.py b/graphs/wrapper.py
index 566d3a1c4..5d8992391 100644
--- a/graphs/wrapper.py
+++ b/graphs/wrapper.py
@@ -199,7 +199,7 @@ def _getAutoResists(fit):
armorHp = hpData['armor']
hullHp = hpData['hull']
uniformDamagePattern = DamagePattern(emAmount=25, thermalAmount=25, kineticAmount=25, explosiveAmount=25)
- ehpData = uniformDamagePattern.calculateEhp(fit)
+ ehpData = uniformDamagePattern.calculateEhp(fit.ship)
shieldEhp = ehpData['shield']
armorEhp = ehpData['armor']
hullEhp = ehpData['hull']
diff --git a/gui/builtinAdditionPanes/droneView.py b/gui/builtinAdditionPanes/droneView.py
index 209f7fc00..f8db01b7c 100644
--- a/gui/builtinAdditionPanes/droneView.py
+++ b/gui/builtinAdditionPanes/droneView.py
@@ -66,6 +66,8 @@ class DroneView(Display):
"Max Range",
"Miscellanea",
"attr:maxVelocity",
+ "Drone HP",
+ "Drone Regen",
"Price",
]
diff --git a/gui/builtinAdditionPanes/fighterView.py b/gui/builtinAdditionPanes/fighterView.py
index ccb92c5e1..40279b9bf 100644
--- a/gui/builtinAdditionPanes/fighterView.py
+++ b/gui/builtinAdditionPanes/fighterView.py
@@ -151,6 +151,8 @@ class FighterDisplay(d.Display):
# "Max Range",
# "Miscellanea",
"attr:maxVelocity",
+ "Drone HP",
+ "Drone Regen",
"Fighter Abilities",
"Price",
]
diff --git a/gui/builtinViewColumns/droneEhp.py b/gui/builtinViewColumns/droneEhp.py
new file mode 100644
index 000000000..865e03a60
--- /dev/null
+++ b/gui/builtinViewColumns/droneEhp.py
@@ -0,0 +1,87 @@
+# =============================================================================
+# Copyright (C) 2010 Diego Duclos
+#
+# This file is part of pyfa.
+#
+# pyfa is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# pyfa is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with pyfa. If not, see .
+# =============================================================================
+
+# noinspection PyPackageRequirements
+import wx
+
+import gui.mainFrame
+from eos.saveddata.drone import Drone
+from eos.saveddata.fighter import Fighter
+from service.attribute import Attribute
+from gui.viewColumn import ViewColumn
+from gui.bitmap_loader import BitmapLoader
+from gui.utils.numberFormatter import formatAmount
+
+
+_t = wx.GetTranslation
+
+
+class DroneEhpColumn(ViewColumn):
+ name = "Drone HP"
+
+ def __init__(self, fittingView, params=None):
+ self.mainFrame = gui.mainFrame.MainFrame.getInstance()
+ if params is None:
+ params = {"showIcon": True, "displayName": False}
+
+ ViewColumn.__init__(self, fittingView)
+
+ sAttr = Attribute.getInstance()
+ info = sAttr.getAttributeInfo("shieldCapacity")
+ self.info = info
+ if params["showIcon"]:
+ iconFile = info.iconID
+ if iconFile:
+ self.imageId = fittingView.imageList.GetImageIndex(iconFile, "icons")
+ self.bitmap = BitmapLoader.getBitmap(iconFile, "icons")
+ else:
+ self.imageId = -1
+ self.mask = wx.LIST_MASK_IMAGE
+ else:
+ self.imageId = -1
+
+ if params["displayName"] or self.imageId == -1:
+ self.columnText = info.displayName if info.displayName != "" else info.name
+ self.mask |= wx.LIST_MASK_TEXT
+
+ def getText(self, stuff):
+ if not isinstance(stuff, (Drone, Fighter)):
+ return ""
+ if self.mainFrame.statsPane.nameViewMap["resistancesViewFull"].showEffective:
+ ehp = sum(stuff.ehp.values())
+ else:
+ ehp = sum(stuff.hp.values())
+ return formatAmount(ehp, 3, 0, 9)
+
+ def getImageId(self, mod):
+ return -1
+
+ def getParameters(self):
+ return ("displayName", bool, False), ("showIcon", bool, True)
+
+ def getToolTip(self, stuff):
+ if not isinstance(stuff, (Drone, Fighter)):
+ return ""
+ if self.mainFrame.statsPane.nameViewMap["resistancesViewFull"].showEffective:
+ return _t("Effective HP")
+ else:
+ return _t("HP")
+
+
+DroneEhpColumn.register()
diff --git a/gui/builtinViewColumns/droneRegen.py b/gui/builtinViewColumns/droneRegen.py
new file mode 100644
index 000000000..4fba6a2c5
--- /dev/null
+++ b/gui/builtinViewColumns/droneRegen.py
@@ -0,0 +1,81 @@
+# =============================================================================
+# Copyright (C) 2010 Diego Duclos
+#
+# This file is part of pyfa.
+#
+# pyfa is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# pyfa is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with pyfa. If not, see .
+# =============================================================================
+
+# noinspection PyPackageRequirements
+import wx
+
+import gui.mainFrame
+from eos.saveddata.drone import Drone
+from eos.saveddata.fighter import Fighter
+from gui.viewColumn import ViewColumn
+from gui.bitmap_loader import BitmapLoader
+from gui.utils.numberFormatter import formatAmount
+
+
+_t = wx.GetTranslation
+
+
+class DroneRegenColumn(ViewColumn):
+ name = "Drone Regen"
+
+ def __init__(self, fittingView, params=None):
+ self.mainFrame = gui.mainFrame.MainFrame.getInstance()
+ if params is None:
+ params = {"showIcon": True, "displayName": False}
+
+ ViewColumn.__init__(self, fittingView)
+
+ if params["showIcon"]:
+ self.imageId = fittingView.imageList.GetImageIndex("shieldPassive_small", "gui")
+ self.bitmap = BitmapLoader.getBitmap("shieldPassive_small", "gui")
+ self.mask = wx.LIST_MASK_IMAGE
+ else:
+ self.imageId = -1
+
+ if params["displayName"] or self.imageId == -1:
+ self.columnText = _("Misc data")
+ self.mask |= wx.LIST_MASK_TEXT
+
+ def getText(self, stuff):
+ if not isinstance(stuff, (Drone, Fighter)):
+ return ""
+ regen = stuff.calculateShieldRecharge()
+ if (
+ self.mainFrame.statsPane.nameViewMap["resistancesViewFull"].showEffective
+ and stuff.owner and stuff.owner.damagePattern is not None
+ ):
+ regen = stuff.owner.damagePattern.effectivify(stuff, regen, 'shield')
+ return '{}/s'.format(formatAmount(regen, 3, 0, 9))
+
+ def getImageId(self, mod):
+ return -1
+
+ def getParameters(self):
+ return ("displayName", bool, False), ("showIcon", bool, True)
+
+ def getToolTip(self, stuff):
+ if not isinstance(stuff, (Drone, Fighter)):
+ return ""
+ if self.mainFrame.statsPane.nameViewMap["resistancesViewFull"].showEffective:
+ return _t("Effective Shield Regeneration")
+ else:
+ return _t("Shield Regeneration")
+
+
+DroneRegenColumn.register()
diff --git a/gui/viewColumn.py b/gui/viewColumn.py
index 43bed258c..0c904fa27 100644
--- a/gui/viewColumn.py
+++ b/gui/viewColumn.py
@@ -78,6 +78,8 @@ from gui.builtinViewColumns import ( # noqa: E402, F401
baseName,
capacitorUse,
dampScanRes,
+ droneEhp,
+ droneRegen,
graphColor,
graphLightness,
graphLineStyle,
diff --git a/imgs/gui/shieldPassive_small.png b/imgs/gui/shieldPassive_small.png
new file mode 100644
index 000000000..65a205f0e
Binary files /dev/null and b/imgs/gui/shieldPassive_small.png differ
diff --git a/service/port/shipstats.py b/service/port/shipstats.py
index 0f4108ba5..fc2f67d04 100644
--- a/service/port/shipstats.py
+++ b/service/port/shipstats.py
@@ -36,7 +36,7 @@ def tankSection(fit):
ehp.append(sum(ehp))
ehpStr = [formatAmount(ehpVal, 3, 0, 9) for ehpVal in ehp]
resists = {tankType: [1 - fit.ship.getModifiedItemAttr(s) for s in resonanceNames[tankType]] for tankType in tankTypes}
- ehpAgainstDamageType = [sum(pattern.calculateEhp(fit).values()) for pattern in damagePatterns]
+ ehpAgainstDamageType = [sum(pattern.calculateEhp(fit.ship).values()) for pattern in damagePatterns]
ehpAgainstDamageTypeStr = [formatAmount(ehpVal, 3, 0, 9) for ehpVal in ehpAgainstDamageType]
# not used for now. maybe will be improved later