Compare commits
86 Commits
v2.44.0
...
v2.53.0dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
369f62bd68 | ||
|
|
885ad4deb3 | ||
|
|
0ce3b861a4 | ||
|
|
48ee543c00 | ||
|
|
e07e2bc4f7 | ||
|
|
17dec4d732 | ||
|
|
effb7e6429 | ||
|
|
63f7762e34 | ||
|
|
76ff52aea8 | ||
|
|
cd12279404 | ||
|
|
263929b6e3 | ||
|
|
759135d3fe | ||
|
|
d240f547cc | ||
|
|
0a4f3481da | ||
|
|
b248cdefdd | ||
|
|
6172ceda0f | ||
|
|
ba236bcb54 | ||
|
|
b4e115eb7b | ||
|
|
52b567a06d | ||
|
|
dd1f7e224c | ||
|
|
338b298077 | ||
|
|
512b370e3e | ||
|
|
a14210f356 | ||
|
|
f81cf4ee7b | ||
|
|
87b072b567 | ||
|
|
e21789d29c | ||
|
|
dd93f348e6 | ||
|
|
cae8088ad3 | ||
|
|
a92cbe92f1 | ||
|
|
52fd0bb13f | ||
|
|
afcddeea70 | ||
|
|
e5eb001cf3 | ||
|
|
0d186ba56b | ||
|
|
e2273f90b4 | ||
|
|
d6501df509 | ||
|
|
96d639996a | ||
|
|
625c52720d | ||
|
|
69221eac24 | ||
|
|
74daf99aed | ||
|
|
eaf637d1d9 | ||
|
|
c262ea6e35 | ||
|
|
1c541c82bf | ||
|
|
1824d1b866 | ||
|
|
90025f22e5 | ||
|
|
9e71ed88e9 | ||
|
|
be07d8e338 | ||
|
|
242fbba6d6 | ||
|
|
7f1e0fcc58 | ||
|
|
072a53eabc | ||
|
|
3115268fb8 | ||
|
|
0631bd65e1 | ||
|
|
6b7a4b3f9d | ||
|
|
0ba65cab1f | ||
|
|
d75419d858 | ||
|
|
771dfca1c8 | ||
|
|
73a5f62d90 | ||
|
|
3982670dff | ||
|
|
79d2ded836 | ||
|
|
55bc0cd40f | ||
|
|
9da09a279e | ||
|
|
889047f891 | ||
|
|
8f645fa425 | ||
|
|
e3e7f92b8d | ||
|
|
22f37995cf | ||
|
|
92119c01f6 | ||
|
|
95841c44dc | ||
|
|
e7b3040c0f | ||
|
|
78af68cac2 | ||
|
|
3e5eb989f9 | ||
|
|
975d6f8776 | ||
|
|
4e89a87ec1 | ||
|
|
eef644fb4c | ||
|
|
8131dd4ace | ||
|
|
c8059d6132 | ||
|
|
cc008a57e1 | ||
|
|
ce6910fd63 | ||
|
|
7892e637b2 | ||
|
|
6543a2c225 | ||
|
|
1e59d3d6ac | ||
|
|
11d0566433 | ||
|
|
b8d84d3af2 | ||
|
|
1831fea819 | ||
|
|
d15322a57c | ||
|
|
48981460ab | ||
|
|
eaca4a179f | ||
|
|
e249cf917b |
@@ -11,7 +11,7 @@ for:
|
||||
environment:
|
||||
APPVEYOR_SSH_KEY: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDJDW/+oYNGOiPvwuwAL9tc/LQgg58aosIVpMYfepQZ20V+VZnHpZh8IRDA8Jo5xht19p2PksA+hFgqA0kpKtrSkuiWdE8rATQItfk4gf7yB0yGasJGGQZYazy9k/9XtmYkq2HHOOeEqdxvrICddJQ88MLCLT9lJENSUP/YS/yGcjZFXVxE11pTeIcqlCRU+3eYa1v7BeNvXIKNhZoK5orXWrtuH3cy8jrSns/u70aYfJ6B2jA8CnWnDbuvpeQtEY61SQqlKUsSArNa8NAsXj41wr3Ar9gAG9330w7EMTqlutk8HZO35uHI0q5qinUhaQYufPPrVkb2L/N+ZCfu0fnh appveyor"
|
||||
APPIMAGE_TOOL: appimagetool-x86_64.AppImage
|
||||
PYTHON_APPIMAGE: python3.7.13-cp37-cp37m-manylinux2014_x86_64.AppImage
|
||||
PYTHON_APPIMAGE: python3.7.16-cp37-cp37m-manylinux2014_x86_64.AppImage
|
||||
DEPLOY_DIR: AppDir/opt/pyfa
|
||||
# APPVEYOR_SSH_BLOCK: true
|
||||
cache:
|
||||
@@ -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 ../../
|
||||
|
||||
@@ -211,4 +215,4 @@ for:
|
||||
force_update: false
|
||||
# deploy on tag push only
|
||||
on:
|
||||
APPVEYOR_REPO_TAG: true
|
||||
APPVEYOR_REPO_TAG: true
|
||||
|
||||
4
.gitignore
vendored
@@ -90,6 +90,7 @@ target/
|
||||
|
||||
# pyenv
|
||||
.python-version
|
||||
PyfaEnv/
|
||||
|
||||
# celery beat schedule file
|
||||
celerybeat-schedule
|
||||
@@ -123,3 +124,6 @@ gitversion
|
||||
|
||||
*.fsdbinary
|
||||
/locale/progress.json
|
||||
|
||||
# vscode settings
|
||||
.vscode
|
||||
@@ -1,6 +1,6 @@
|
||||
# pyfa
|
||||
|
||||
[](https://pyfainvite.azurewebsites.net/) [](https://travis-ci.org/pyfa-org/Pyfa)
|
||||
[]([https://travis-ci.org/pyfa-org/Pyfa](https://ci.appveyor.com/project/pyfa-org/pyfa))
|
||||
|
||||

|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ saveInRoot = False
|
||||
evemonMinVersion = "4081"
|
||||
|
||||
minItemSearchLength = 3
|
||||
minItemSearchLengthCjk = 1
|
||||
|
||||
pyfaPath = None
|
||||
savePath = None
|
||||
|
||||
136
db_update.py
@@ -117,8 +117,7 @@ def update_db():
|
||||
for k, v in compiled_data.items():
|
||||
row = {}
|
||||
row.update(v)
|
||||
if keyIdName not in row:
|
||||
row[keyIdName] = int(k)
|
||||
row[keyIdName] = int(k)
|
||||
data.append(row)
|
||||
return data
|
||||
|
||||
@@ -642,6 +641,139 @@ def update_db():
|
||||
effect.effectName = effectName
|
||||
item.effects[effectName] = effect
|
||||
|
||||
def hardcodeGeri():
|
||||
attrMap = {
|
||||
# Fitting
|
||||
'powerOutput': 50,
|
||||
'cpuOutput': 200,
|
||||
'capacitorCapacity': 325,
|
||||
'rechargeRate': 130000,
|
||||
# Slots
|
||||
'hiSlots': 5,
|
||||
'medSlots': 4,
|
||||
'lowSlots': 4,
|
||||
'launcherSlotsLeft': 3,
|
||||
'turretSlotsLeft': 2,
|
||||
# Rigs
|
||||
'rigSlots': 2,
|
||||
'rigSize': 1,
|
||||
'upgradeCapacity': 400,
|
||||
# Shield
|
||||
'shieldCapacity': 1000,
|
||||
'shieldEmDamageResonance': 1 - 0.75,
|
||||
'shieldThermalDamageResonance': 1 - 0.6,
|
||||
'shieldKineticDamageResonance': 1 - 0.4,
|
||||
'shieldExplosiveDamageResonance': 1 - 0.5,
|
||||
# Armor
|
||||
'armorHP': 1000,
|
||||
'armorEmDamageResonance': 1 - 0.9,
|
||||
'armorThermalDamageResonance': 1 - 0.675,
|
||||
'armorKineticDamageResonance': 1 - 0.25,
|
||||
'armorExplosiveDamageResonance': 1 - 0.1,
|
||||
# Structure
|
||||
'hp': 700,
|
||||
'emDamageResonance': 1 - 0.33,
|
||||
'thermalDamageResonance': 1 - 0.33,
|
||||
'kineticDamageResonance': 1 - 0.33,
|
||||
'explosiveDamageResonance': 1 - 0.33,
|
||||
'mass': 1309000,
|
||||
'volume': 27289,
|
||||
'capacity': 260,
|
||||
# Navigation
|
||||
'maxVelocity': 440,
|
||||
'agility': 2.5,
|
||||
'warpSpeedMultiplier': 5.5,
|
||||
# Drones
|
||||
'droneCapacity': 50,
|
||||
'droneBandwidth': 10,
|
||||
# Targeting
|
||||
'maxTargetRange': 42000,
|
||||
'maxLockedTargets': 6,
|
||||
'scanRadarStrength': 0,
|
||||
'scanLadarStrength': 12,
|
||||
'scanMagnetometricStrength': 0,
|
||||
'scanGravimetricStrength': 0,
|
||||
'signatureRadius': 33,
|
||||
'scanResolution': 770}
|
||||
effectMap = {
|
||||
100100: 'pyfaCustomGeriAfExploVel',
|
||||
100101: 'pyfaCustomGeriAfRof',
|
||||
100102: 'pyfaCustomGeriMfDmg',
|
||||
100103: 'pyfaCustomGeriMfRep',
|
||||
100104: 'pyfaCustomGeriRoleWebDroneStr',
|
||||
100105: 'pyfaCustomGeriRoleWebDroneHP',
|
||||
100106: 'pyfaCustomGeriRoleWebDroneSpeed',
|
||||
100107: 'pyfaCustomGeriRoleMWDSigBloom'}
|
||||
_hardcodeAttribs(74141, attrMap)
|
||||
_hardcodeEffects(74141, effectMap)
|
||||
|
||||
def hardcodeBestla():
|
||||
attrMap = {
|
||||
# Fitting
|
||||
'powerOutput': 1300,
|
||||
'cpuOutput': 500,
|
||||
'capacitorCapacity': 1500,
|
||||
'rechargeRate': 200000,
|
||||
'hiSlots': 6,
|
||||
'medSlots': 5,
|
||||
'lowSlots': 5,
|
||||
'launcherSlotsLeft': 4,
|
||||
'turretSlotsLeft': 2,
|
||||
# Rigs
|
||||
'rigSlots': 2,
|
||||
'rigSize': 2,
|
||||
'upgradeCapacity': 400,
|
||||
# Shield
|
||||
'shieldCapacity': 3000,
|
||||
'shieldEmDamageResonance': 1 - 0.75,
|
||||
'shieldThermalDamageResonance': 1 - 0.6,
|
||||
'shieldKineticDamageResonance': 1 - 0.4,
|
||||
'shieldExplosiveDamageResonance': 1 - 0.5,
|
||||
# Armor
|
||||
'armorHP': 3000,
|
||||
'armorEmDamageResonance': 1 - 0.9,
|
||||
'armorThermalDamageResonance': 1 - 0.675,
|
||||
'armorKineticDamageResonance': 1 - 0.25,
|
||||
'armorExplosiveDamageResonance': 1 - 0.1,
|
||||
# Structure
|
||||
'hp': 1600,
|
||||
'emDamageResonance': 1 - 0.33,
|
||||
'thermalDamageResonance': 1 - 0.33,
|
||||
'kineticDamageResonance': 1 - 0.33,
|
||||
'explosiveDamageResonance': 1 - 0.33,
|
||||
'mass': 11650000,
|
||||
'volume': 96000,
|
||||
'capacity': 660,
|
||||
# Navigation
|
||||
'maxVelocity': 300,
|
||||
'agility': 0.47,
|
||||
'warpSpeedMultiplier': 4.5,
|
||||
# Drones
|
||||
'droneCapacity': 125,
|
||||
'droneBandwidth': 20,
|
||||
# Targeting
|
||||
'maxTargetRange': 80000,
|
||||
'maxLockedTargets': 7,
|
||||
'scanRadarStrength': 0,
|
||||
'scanLadarStrength': 22,
|
||||
'scanMagnetometricStrength': 0,
|
||||
'scanGravimetricStrength': 0,
|
||||
'signatureRadius': 120,
|
||||
'scanResolution': 340}
|
||||
effectMap = {
|
||||
100200: 'pyfaCustomBestlaHacExploVel',
|
||||
100201: 'pyfaCustomBestlaHacRof',
|
||||
100202: 'pyfaCustomBestlaMcDmg',
|
||||
100203: 'pyfaCustomBestlaMcRep',
|
||||
100204: 'pyfaCustomBestlaRoleWebDroneStr',
|
||||
100205: 'pyfaCustomBestlaRoleWebDroneHP',
|
||||
100206: 'pyfaCustomBestlaRoleWebDroneSpeed'}
|
||||
_hardcodeAttribs(74316, attrMap)
|
||||
_hardcodeEffects(74316, effectMap)
|
||||
|
||||
# hardcodeGeri()
|
||||
# hardcodeBestla()
|
||||
|
||||
eos.db.gamedata_session.commit()
|
||||
eos.db.gamedata_engine.execute('VACUUM')
|
||||
|
||||
|
||||
0
dist_assets/linux/AppRun
Normal file → Executable file
2224
eos/effects.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
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -477,7 +477,7 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut, M
|
||||
# Some delay attributes have non-0 default value, so we have to pick according to effects
|
||||
if {'superWeaponAmarr', 'superWeaponCaldari', 'superWeaponGallente', 'superWeaponMinmatar', 'lightningWeapon'}.intersection(self.item.effects):
|
||||
dmgDelay = self.getModifiedItemAttr("damageDelayDuration", 0)
|
||||
elif {'doomsdayBeamDOT', 'doomsdaySlash', 'doomsdayConeDOT'}.intersection(self.item.effects):
|
||||
elif {'doomsdayBeamDOT', 'doomsdaySlash', 'doomsdayConeDOT', 'debuffLance'}.intersection(self.item.effects):
|
||||
dmgDelay = self.getModifiedItemAttr("doomsdayWarningDuration", 0)
|
||||
else:
|
||||
dmgDelay = 0
|
||||
|
||||
@@ -66,7 +66,7 @@ class FitShieldRegenGraph(FitGraph):
|
||||
('shieldAmount', '%'): lambda v, src, tgt: v / 100 * src.item.ship.getModifiedItemAttr('shieldCapacity'),
|
||||
('shieldAmountT0', '%'): lambda v, src, tgt: None if v is None else v / 100 * src.item.ship.getModifiedItemAttr('shieldCapacity'),
|
||||
# Needed only for "x mark" support, to convert EHP x into normalized value
|
||||
('shieldAmount', 'EHP'): lambda v, src, tgt: v / src.item.damagePattern.effectivify(src.item, 1, 'shield')}
|
||||
('shieldAmount', 'EHP'): lambda v, src, tgt: v / src.item.damagePattern.effectivify(src.item.ship, 1, 'shield')}
|
||||
_limiters = {
|
||||
'shieldAmount': lambda src, tgt: (0, src.item.ship.getModifiedItemAttr('shieldCapacity')),
|
||||
'shieldAmountT0': lambda src, tgt: (0, src.item.ship.getModifiedItemAttr('shieldCapacity'))}
|
||||
@@ -77,5 +77,5 @@ class FitShieldRegenGraph(FitGraph):
|
||||
('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')}
|
||||
('shieldAmount', 'EHP'): lambda v, src, tgt: src.item.damagePattern.effectivify(src.item.ship, v, 'shield'),
|
||||
('shieldRegen', 'EHP/s'): lambda v, src, tgt: src.item.damagePattern.effectivify(src.item.ship, v, 'shield')}
|
||||
|
||||
@@ -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']
|
||||
|
||||
@@ -66,6 +66,8 @@ class DroneView(Display):
|
||||
"Max Range",
|
||||
"Miscellanea",
|
||||
"attr:maxVelocity",
|
||||
"Drone HP",
|
||||
"Drone Regen",
|
||||
"Price",
|
||||
]
|
||||
|
||||
|
||||
@@ -151,6 +151,8 @@ class FighterDisplay(d.Display):
|
||||
# "Max Range",
|
||||
# "Miscellanea",
|
||||
"attr:maxVelocity",
|
||||
"Drone HP",
|
||||
"Drone Regen",
|
||||
"Fighter Abilities",
|
||||
"Price",
|
||||
]
|
||||
|
||||
@@ -44,7 +44,6 @@ class AddCommandFit(ContextMenuUnconditional):
|
||||
def display(self, callingWindow, srcContext):
|
||||
if self.mainFrame.getActiveFit() is None or len(self.__class__.commandFits) == 0 or srcContext != "commandView":
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def getText(self, callingWindow, itmContext):
|
||||
@@ -52,6 +51,8 @@ class AddCommandFit(ContextMenuUnconditional):
|
||||
|
||||
def addFit(self, menu, fit, includeShip=False):
|
||||
label = fit.name if not includeShip else "({}) {}".format(fit.ship.item.name, fit.name)
|
||||
if not label:
|
||||
label = ' '
|
||||
id = ContextMenuUnconditional.nextID()
|
||||
self.fitMenuItemIds[id] = fit
|
||||
menuItem = wx.MenuItem(menu, id, label)
|
||||
|
||||
@@ -123,9 +123,7 @@ class AddEnvironmentEffect(ContextMenuUnconditional):
|
||||
data.groups[_t('Abyssal Weather')] = self.getAbyssalWeather()
|
||||
data.groups[_t('Sansha Incursion')] = self.getEffectBeacons(
|
||||
_t('ContextMenu|ProjectedEffectManipulation|Sansha Incursion'))
|
||||
data.groups[_t('Triglavian Invasion')] = self.getEffectBeacons(
|
||||
_t('ContextMenu|ProjectedEffectManipulation|Triglavian Invasion'))
|
||||
data.groups[_t('Triglavian Invasion')].groups[_t('Destructible Beacons')] = self.getDestructibleBeacons()
|
||||
data.groups[_t('Triglavian Invasion')] = self.getInvasionBeacons()
|
||||
return data
|
||||
|
||||
def getEffectBeacons(self, *groups, extra_garbage=()):
|
||||
@@ -233,5 +231,12 @@ class AddEnvironmentEffect(ContextMenuUnconditional):
|
||||
data.sort()
|
||||
return data
|
||||
|
||||
def getInvasionBeacons(self):
|
||||
data = self.getDestructibleBeacons()
|
||||
# Turnur weather
|
||||
item = Market.getInstance().getItem(74002)
|
||||
data.items.append(Entry(item.ID, item.name, item.name))
|
||||
return data
|
||||
|
||||
|
||||
AddEnvironmentEffect.register()
|
||||
|
||||
@@ -36,6 +36,8 @@ class ItemCompare(wx.Panel):
|
||||
self.item = item
|
||||
self.items = sorted(items, key=defaultSort)
|
||||
self.attrs = {}
|
||||
self.HighlightOn = wx.Colour(255, 255, 0, wx.ALPHA_OPAQUE)
|
||||
self.highlightedNames = []
|
||||
|
||||
# get a dict of attrName: attrInfo of all unique attributes across all items
|
||||
for item in self.items:
|
||||
@@ -88,6 +90,21 @@ class ItemCompare(wx.Panel):
|
||||
self.toggleViewBtn.Bind(wx.EVT_TOGGLEBUTTON, self.ToggleViewMode)
|
||||
self.Bind(wx.EVT_LIST_COL_CLICK, self.SortCompareCols)
|
||||
|
||||
self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.HighlightRow)
|
||||
|
||||
def HighlightRow(self, event):
|
||||
itemIdx = event.GetIndex()
|
||||
name = self.paramList.GetItem(itemIdx).Text
|
||||
if name in self.highlightedNames:
|
||||
self.highlightedNames.remove(name)
|
||||
else:
|
||||
self.highlightedNames.append(name)
|
||||
self.Freeze()
|
||||
self.paramList.ClearAll()
|
||||
self.PopulateList()
|
||||
self.Thaw()
|
||||
event.Skip()
|
||||
|
||||
def SortCompareCols(self, event):
|
||||
self.Freeze()
|
||||
self.paramList.ClearAll()
|
||||
@@ -155,6 +172,8 @@ class ItemCompare(wx.Panel):
|
||||
self.paramList.InsertColumn(len(self.attrs) + 1, _t("Price"))
|
||||
self.paramList.SetColumnWidth(len(self.attrs) + 1, 60)
|
||||
|
||||
toHighlight = []
|
||||
|
||||
for item in self.items:
|
||||
i = self.paramList.InsertItem(self.paramList.GetItemCount(), item.name)
|
||||
for x, attr in enumerate(self.attrs.keys()):
|
||||
@@ -172,10 +191,19 @@ class ItemCompare(wx.Panel):
|
||||
|
||||
# Add prices
|
||||
self.paramList.SetItem(i, len(self.attrs) + 1, formatAmount(item.price.price, 3, 3, 9, currency=True) if item.price.price else "")
|
||||
if item.name in self.highlightedNames:
|
||||
toHighlight.append(i)
|
||||
|
||||
self.paramList.RefreshRows()
|
||||
self.Layout()
|
||||
|
||||
# Highlight after layout, otherwise colors are getting overwritten
|
||||
for itemIdx in toHighlight:
|
||||
listItem = self.paramList.GetItem(itemIdx)
|
||||
listItem.SetBackgroundColour(self.HighlightOn)
|
||||
listItem.SetFont(listItem.GetFont().MakeBold())
|
||||
self.paramList.SetItem(listItem)
|
||||
|
||||
@staticmethod
|
||||
def TranslateValueUnit(value, unitName, unitDisplayName):
|
||||
def itemIDCallback():
|
||||
|
||||
@@ -127,7 +127,9 @@ class TargetingMiscViewMinimal(StatsView):
|
||||
("specialSalvageHoldCapacity", _t("Salvage hold")),
|
||||
("specialCommandCenterHoldCapacity", _t("Command center hold")),
|
||||
("specialPlanetaryCommoditiesHoldCapacity", _t("Planetary goods hold")),
|
||||
("specialQuafeHoldCapacity", _t("Quafe hold"))))
|
||||
("specialQuafeHoldCapacity", _t("Quafe hold")),
|
||||
("specialMobileDepotHoldCapacity", _t("Mobile depot hold")),
|
||||
))
|
||||
|
||||
cargoValues = {
|
||||
"main": lambda: fit.ship.getModifiedItemAttr("capacity"),
|
||||
@@ -148,7 +150,8 @@ class TargetingMiscViewMinimal(StatsView):
|
||||
"specialSalvageHoldCapacity": lambda: fit.ship.getModifiedItemAttr("specialSalvageHoldCapacity"),
|
||||
"specialCommandCenterHoldCapacity": lambda: fit.ship.getModifiedItemAttr("specialCommandCenterHoldCapacity"),
|
||||
"specialPlanetaryCommoditiesHoldCapacity": lambda: fit.ship.getModifiedItemAttr("specialPlanetaryCommoditiesHoldCapacity"),
|
||||
"specialQuafeHoldCapacity": lambda: fit.ship.getModifiedItemAttr("specialQuafeHoldCapacity")
|
||||
"specialQuafeHoldCapacity": lambda: fit.ship.getModifiedItemAttr("specialQuafeHoldCapacity"),
|
||||
"specialMobileDepotHoldCapacity": lambda: fit.ship.getModifiedItemAttr("specialMobileDepotHoldCapacity"),
|
||||
}
|
||||
|
||||
stats = (("labelTargets", {"main": lambda: fit.maxTargets}, 3, 0, 0, ""),
|
||||
|
||||
87
gui/builtinViewColumns/droneEhp.py
Normal file
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
# =============================================================================
|
||||
|
||||
# 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()
|
||||
81
gui/builtinViewColumns/droneRegen.py
Normal file
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
# =============================================================================
|
||||
|
||||
# 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()
|
||||
@@ -182,6 +182,13 @@ class Miscellanea(ViewColumn):
|
||||
text = "{0} | {1}".format(formatAmount(strength, 3, 0, 3), formatAmount(coherence, 3, 0, 3))
|
||||
tooltip = "Virus strength and coherence"
|
||||
return text, tooltip
|
||||
elif itemGroup == "Damage Control":
|
||||
duration = stuff.getModifiedItemAttr("duration")
|
||||
if not duration:
|
||||
return "", None
|
||||
text = "{0}s".format(formatAmount(duration / 1000, 3, 0, 0))
|
||||
tooltip = "Assault ability duration"
|
||||
return text, tooltip
|
||||
elif itemGroup in ("Warp Scrambler", "Warp Core Stabilizer", "Structure Warp Scrambler"):
|
||||
scramStr = stuff.getModifiedItemAttr("warpScrambleStrength")
|
||||
if not scramStr:
|
||||
|
||||
@@ -22,6 +22,7 @@ import traceback
|
||||
|
||||
# noinspection PyPackageRequirements
|
||||
import wx
|
||||
import roman
|
||||
from logbook import Logger
|
||||
|
||||
import config
|
||||
@@ -105,6 +106,9 @@ class CharacterSelection(wx.Panel):
|
||||
exportItem = menu.Append(wx.ID_ANY, _t("Copy Missing Skills"))
|
||||
self.Bind(wx.EVT_MENU, self.exportSkills, exportItem)
|
||||
|
||||
exportItem = menu.Append(wx.ID_ANY, _t("Copy Missing Skills (EVEMon)"))
|
||||
self.Bind(wx.EVT_MENU, self.exportSkillsEveMon, exportItem)
|
||||
|
||||
self.PopupMenu(menu, pos)
|
||||
|
||||
event.Skip()
|
||||
@@ -264,6 +268,15 @@ class CharacterSelection(wx.Panel):
|
||||
|
||||
toClipboard(list)
|
||||
|
||||
def exportSkillsEveMon(self, evt):
|
||||
skillsMap = self._buildSkillsTooltipCondensed(self.reqs, skillsMap={})
|
||||
|
||||
list = ""
|
||||
for key in sorted(skillsMap):
|
||||
list += "%s %s\n" % (key, roman.toRoman(skillsMap[key][0]))
|
||||
|
||||
toClipboard(list)
|
||||
|
||||
def _buildSkillsTooltip(self, reqs, currItem="", tabulationLevel=0):
|
||||
tip = ""
|
||||
sCharacter = Character.getInstance()
|
||||
|
||||
@@ -78,6 +78,8 @@ from gui.builtinViewColumns import ( # noqa: E402, F401
|
||||
baseName,
|
||||
capacitorUse,
|
||||
dampScanRes,
|
||||
droneEhp,
|
||||
droneRegen,
|
||||
graphColor,
|
||||
graphLightness,
|
||||
graphLineStyle,
|
||||
|
||||
BIN
imgs/gui/shieldPassive_small.png
Normal file
|
After Width: | Height: | Size: 662 B |
BIN
imgs/icons/1168@1x.png
Normal file
|
After Width: | Height: | Size: 857 B |
BIN
imgs/icons/1168@2x.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
imgs/icons/21831@1x.png
Normal file
|
After Width: | Height: | Size: 812 B |
BIN
imgs/icons/21831@2x.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
imgs/icons/24296@1x.png
Normal file
|
After Width: | Height: | Size: 667 B |
BIN
imgs/icons/24296@2x.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
imgs/icons/24404@1x.png
Normal file
|
After Width: | Height: | Size: 676 B |
BIN
imgs/icons/24404@2x.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
imgs/icons/24411@1x.png
Normal file
|
After Width: | Height: | Size: 849 B |
BIN
imgs/icons/24411@2x.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
imgs/icons/24585@1x.png
Normal file
|
After Width: | Height: | Size: 878 B |
BIN
imgs/icons/24585@2x.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
imgs/icons/25328@1x.png
Normal file
|
After Width: | Height: | Size: 791 B |
BIN
imgs/icons/25328@2x.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
imgs/icons/25329@1x.png
Normal file
|
After Width: | Height: | Size: 769 B |
BIN
imgs/icons/25329@2x.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
imgs/icons/25330@1x.png
Normal file
|
After Width: | Height: | Size: 799 B |
BIN
imgs/icons/25330@2x.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
imgs/icons/25331@1x.png
Normal file
|
After Width: | Height: | Size: 802 B |
BIN
imgs/icons/25331@2x.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
imgs/icons/25355@1x.png
Normal file
|
After Width: | Height: | Size: 796 B |
BIN
imgs/icons/25355@2x.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
imgs/icons/25356@1x.png
Normal file
|
After Width: | Height: | Size: 603 B |
BIN
imgs/icons/25356@2x.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
imgs/icons/25467@1x.png
Normal file
|
After Width: | Height: | Size: 605 B |
BIN
imgs/icons/25467@2x.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
imgs/icons/25468@1x.png
Normal file
|
After Width: | Height: | Size: 625 B |
BIN
imgs/icons/25468@2x.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
imgs/icons/25621@1x.png
Normal file
|
After Width: | Height: | Size: 825 B |
BIN
imgs/icons/25621@2x.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
imgs/icons/25622@1x.png
Normal file
|
After Width: | Height: | Size: 834 B |
BIN
imgs/icons/25622@2x.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
imgs/icons/25624@1x.png
Normal file
|
After Width: | Height: | Size: 810 B |
BIN
imgs/icons/25624@2x.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
imgs/icons/25625@1x.png
Normal file
|
After Width: | Height: | Size: 833 B |
BIN
imgs/icons/25625@2x.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
imgs/icons/25629@1x.png
Normal file
|
After Width: | Height: | Size: 952 B |
BIN
imgs/icons/25629@2x.png
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
imgs/icons/25631@1x.png
Normal file
|
After Width: | Height: | Size: 771 B |
BIN
imgs/icons/25631@2x.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
imgs/icons/25632@1x.png
Normal file
|
After Width: | Height: | Size: 783 B |
BIN
imgs/icons/25632@2x.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
imgs/icons/25633@1x.png
Normal file
|
After Width: | Height: | Size: 768 B |
BIN
imgs/icons/25633@2x.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
imgs/icons/25634@1x.png
Normal file
|
After Width: | Height: | Size: 961 B |
BIN
imgs/icons/25634@2x.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 6.2 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 6.5 KiB After Width: | Height: | Size: 6.4 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 6.9 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 7.0 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 6.6 KiB |
BIN
imgs/renders/1793@1x.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
imgs/renders/1793@2x.png
Normal file
|
After Width: | Height: | Size: 6.6 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 7.1 KiB |
BIN
imgs/renders/1889@1x.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
imgs/renders/1889@2x.png
Normal file
|
After Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 5.9 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 6.0 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 7.2 KiB |
BIN
imgs/renders/20228@1x.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
imgs/renders/20228@2x.png
Normal file
|
After Width: | Height: | Size: 6.9 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 6.2 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |