Compare commits
54 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
52d6c452c7 | ||
|
|
fb3721ace5 | ||
|
|
b1f048ac93 | ||
|
|
73b3e347fb | ||
|
|
6090d748d2 | ||
|
|
5e37b5ef77 | ||
|
|
78bb5e7cc0 | ||
|
|
96c248f477 | ||
|
|
696b195bb5 | ||
|
|
b0fa8f1b8c | ||
|
|
6e173551ed | ||
|
|
2fccc7487b | ||
|
|
2f5b674b75 | ||
|
|
80ced86ace | ||
|
|
de93777f99 | ||
|
|
f23d1e4921 | ||
|
|
e8e22017cd | ||
|
|
e79f97964a | ||
|
|
138e7cd706 | ||
|
|
ce6fd4bd3a | ||
|
|
6e4ca641d7 | ||
|
|
46c6381cd9 | ||
|
|
126105cd0d | ||
|
|
fedaa70d9d | ||
|
|
d1707a0dca | ||
|
|
9065d348d3 | ||
|
|
602916c23f | ||
|
|
0d43a8a4c3 | ||
|
|
1e6431a8b3 | ||
|
|
b6067ff0a2 | ||
|
|
89e426815d | ||
|
|
cf0e88495d | ||
|
|
7c67f18be5 | ||
|
|
9ab7e0dbac | ||
|
|
7e92b58c62 | ||
|
|
9c519b878e | ||
|
|
bb07dd8553 | ||
|
|
60555e72d8 | ||
|
|
a457d1d629 | ||
|
|
0e62b29028 | ||
|
|
8a0cb156b2 | ||
|
|
654f8ed7f5 | ||
|
|
cfa927dcd0 | ||
|
|
4383481a5f | ||
|
|
22063842f9 | ||
|
|
0e5d29a8f9 | ||
|
|
5ee16476dc | ||
|
|
2abb73eab8 | ||
|
|
547d8be21e | ||
|
|
b6d8582867 | ||
|
|
370cb7eae6 | ||
|
|
d883935d8c | ||
|
|
235ca94dba | ||
|
|
2dabfe4c79 |
@@ -25,6 +25,7 @@ for:
|
|||||||
before_build:
|
before_build:
|
||||||
# Prepare pyfa data
|
# Prepare pyfa data
|
||||||
- sh: find locale/ -type f -name "*.po" -exec msgen "{}" -o "{}" \;
|
- sh: find locale/ -type f -name "*.po" -exec msgen "{}" -o "{}" \;
|
||||||
|
- sh: pyenv global system
|
||||||
- sh: python3 -B scripts/compile_lang.py
|
- sh: python3 -B scripts/compile_lang.py
|
||||||
- sh: python3 -B scripts/dump_crowdin_progress.py
|
- sh: python3 -B scripts/dump_crowdin_progress.py
|
||||||
- sh: python3 -B db_update.py
|
- sh: python3 -B db_update.py
|
||||||
|
|||||||
68
db_update.py
@@ -141,6 +141,7 @@ def update_db():
|
|||||||
(row['typeName_en-us'].startswith('Civilian') and "Shuttle" not in row['typeName_en-us'])
|
(row['typeName_en-us'].startswith('Civilian') and "Shuttle" not in row['typeName_en-us'])
|
||||||
or row['typeName_en-us'] == 'Capsule'
|
or row['typeName_en-us'] == 'Capsule'
|
||||||
or row['groupID'] == 4033 # destructible effect beacons
|
or row['groupID'] == 4033 # destructible effect beacons
|
||||||
|
or row['typeID'] == 82941 # Metenox service
|
||||||
or re.match(r'AIR .+Booster.*', row['typeName_en-us'])
|
or re.match(r'AIR .+Booster.*', row['typeName_en-us'])
|
||||||
):
|
):
|
||||||
row['published'] = True
|
row['published'] = True
|
||||||
@@ -601,7 +602,7 @@ def update_db():
|
|||||||
eos.gamedata.Item.name.like('%mutated%'),
|
eos.gamedata.Item.name.like('%mutated%'),
|
||||||
eos.gamedata.Item.name.like('%_PLACEHOLDER%'),
|
eos.gamedata.Item.name.like('%_PLACEHOLDER%'),
|
||||||
# Drifter weapons are published for some reason
|
# Drifter weapons are published for some reason
|
||||||
eos.gamedata.Item.name.in_(('Lux Kontos', 'Lux Xiphos'))
|
eos.gamedata.Item.name.in_(('Lux Kontos', 'Lux Xiphos', 'Lux Ballistra', 'Lux Kopis'))
|
||||||
)).all():
|
)).all():
|
||||||
if 'Asteroid Mining Crystal' in item.name:
|
if 'Asteroid Mining Crystal' in item.name:
|
||||||
continue
|
continue
|
||||||
@@ -642,15 +643,66 @@ def update_db():
|
|||||||
else:
|
else:
|
||||||
attr.value = value
|
attr.value = value
|
||||||
|
|
||||||
def _hardcodeEffects(typeID, effectMap):
|
def _hardcodeEffects(typeID, effectMap, clearEffects=True):
|
||||||
item = eos.db.gamedata_session.query(eos.gamedata.Item).filter(eos.gamedata.Item.ID == typeID).one()
|
item = eos.db.gamedata_session.query(eos.gamedata.Item).filter(eos.gamedata.Item.ID == typeID).one()
|
||||||
item.effects.clear()
|
if clearEffects:
|
||||||
|
item.effects.clear()
|
||||||
for effectID, effectName in effectMap.items():
|
for effectID, effectName in effectMap.items():
|
||||||
effect = eos.gamedata.Effect()
|
try:
|
||||||
effect.effectID = effectID
|
effect = eos.db.gamedata_session.query(eos.gamedata.Effect).filter(eos.gamedata.Effect.ID == effectID).one()
|
||||||
effect.effectName = effectName
|
except sqlalchemy.orm.exc.NoResultFound:
|
||||||
|
effect = eos.gamedata.Effect()
|
||||||
|
effect.effectID = effectID
|
||||||
|
effect.effectName = effectName
|
||||||
item.effects[effectName] = effect
|
item.effects[effectName] = effect
|
||||||
|
|
||||||
|
def hardcodeSuppressionTackleRange():
|
||||||
|
beaconTypeID = 79839
|
||||||
|
attrMap = {
|
||||||
|
'warfareBuff1ID': 2405,
|
||||||
|
'warfareBuff1Value': 10}
|
||||||
|
effectMap = {100000: 'pyfaCustomSuppressionTackleRange'}
|
||||||
|
_hardcodeAttribs(beaconTypeID, attrMap)
|
||||||
|
_hardcodeEffects(beaconTypeID, effectMap)
|
||||||
|
eos.db.gamedata_session.flush()
|
||||||
|
|
||||||
|
def hardcodeSovUpgradeBuffs():
|
||||||
|
typeBuffMap = {
|
||||||
|
# Gamma
|
||||||
|
87815: {
|
||||||
|
'warfareBuff1ID': 2433,
|
||||||
|
'warfareBuff1Value': 5,
|
||||||
|
'warfareBuff2ID': 2434,
|
||||||
|
'warfareBuff2Value': 10,
|
||||||
|
'warfareBuff3ID': 2441,
|
||||||
|
'warfareBuff3Value': 5},
|
||||||
|
# Plasma
|
||||||
|
87949: {
|
||||||
|
'warfareBuff1ID': 2442,
|
||||||
|
'warfareBuff1Value': 5,
|
||||||
|
'warfareBuff2ID': 2435,
|
||||||
|
'warfareBuff2Value': 5,
|
||||||
|
'warfareBuff3ID': 2436,
|
||||||
|
'warfareBuff3Value': 10},
|
||||||
|
# Electric
|
||||||
|
87950: {
|
||||||
|
'warfareBuff1ID': 2437,
|
||||||
|
'warfareBuff1Value': -25,
|
||||||
|
'warfareBuff2ID': 2438,
|
||||||
|
'warfareBuff2Value': 25},
|
||||||
|
# Exotic
|
||||||
|
87951: {
|
||||||
|
'warfareBuff1ID': 2440,
|
||||||
|
'warfareBuff1Value': 2,
|
||||||
|
'warfareBuff2ID': 2439,
|
||||||
|
'warfareBuff2Value': 25}}
|
||||||
|
effectMap = {100001: 'pyfaCustomSovUpgradeBuffEffect'}
|
||||||
|
for typeID, attrMap in typeBuffMap.items():
|
||||||
|
_hardcodeAttribs(typeID, attrMap)
|
||||||
|
_hardcodeEffects(typeID, effectMap, clearEffects=False)
|
||||||
|
eos.db.gamedata_session.flush()
|
||||||
|
|
||||||
|
|
||||||
def hardcodeShapash():
|
def hardcodeShapash():
|
||||||
shapashTypeID = 1000000
|
shapashTypeID = 1000000
|
||||||
_copyItem(srcName='Utu', tgtTypeID=shapashTypeID, tgtName='Shapash')
|
_copyItem(srcName='Utu', tgtTypeID=shapashTypeID, tgtName='Shapash')
|
||||||
@@ -794,8 +846,8 @@ def update_db():
|
|||||||
_hardcodeAttribs(cybeleTypeID, attrMap)
|
_hardcodeAttribs(cybeleTypeID, attrMap)
|
||||||
_hardcodeEffects(cybeleTypeID, effectMap)
|
_hardcodeEffects(cybeleTypeID, effectMap)
|
||||||
|
|
||||||
# hardcodeShapash()
|
hardcodeSuppressionTackleRange()
|
||||||
# hardcodeCybele()
|
hardcodeSovUpgradeBuffs()
|
||||||
|
|
||||||
eos.db.gamedata_session.commit()
|
eos.db.gamedata_session.commit()
|
||||||
eos.db.gamedata_engine.execute('VACUUM')
|
eos.db.gamedata_engine.execute('VACUUM')
|
||||||
|
|||||||
749
eos/effects.py
@@ -890,6 +890,42 @@ class Fit:
|
|||||||
lambda mod: mod.item.group.name == "Stasis Web",
|
lambda mod: mod.item.group.name == "Stasis Web",
|
||||||
"maxRange", value, stackingPenalties=True)
|
"maxRange", value, stackingPenalties=True)
|
||||||
|
|
||||||
|
# Sov upgrades buffs
|
||||||
|
if warfareBuffID == 2433: # Sov System Modifier Shield HP Bonus
|
||||||
|
self.ship.boostItemAttr("shieldCapacity", value)
|
||||||
|
if warfareBuffID == 2434: # Sov System Modifier Capacitor Capacity Bonus
|
||||||
|
self.ship.boostItemAttr("capacitorCapacity", value)
|
||||||
|
if warfareBuffID == 2435: # Sov System Modifier Armor HP Bonus
|
||||||
|
self.ship.boostItemAttr("armorHP", value)
|
||||||
|
if warfareBuffID == 2436: # Sov System Modifier Overheating Bonus - Includes Ewar
|
||||||
|
for attr in (
|
||||||
|
'overloadDurationBonus', 'overloadRofBonus', 'overloadSelfDurationBonus',
|
||||||
|
'overloadHardeningBonus', 'overloadDamageModifier', 'overloadRangeBonus',
|
||||||
|
'overloadSpeedFactorBonus', 'overloadECMStrengthBonus', 'overloadECCMStrenghtBonus',
|
||||||
|
'overloadArmorDamageAmount', 'overloadShieldBonus', 'overloadTrackingModuleStrengthBonus',
|
||||||
|
'overloadSensorModuleStrengthBonus', 'overloadPainterStrengthBonus',
|
||||||
|
):
|
||||||
|
self.modules.filteredItemBoost(lambda mod: attr in mod.itemModifiedAttributes, attr, value)
|
||||||
|
if warfareBuffID == 2437: # Sov System Modifier Capacitor Recharge Bonus
|
||||||
|
self.ship.boostItemAttr("rechargeRate", value)
|
||||||
|
if warfareBuffID == 2438: # Sov System Modifier Targeting and DScan Range Bonus
|
||||||
|
self.ship.boostItemAttr("maxTargetRange", value)
|
||||||
|
self.ship.boostItemAttr("maxDirectionalScanRange", value)
|
||||||
|
if warfareBuffID == 2439: # Sov System Modifier Scan Resolution Bonus
|
||||||
|
self.ship.boostItemAttr("scanResolution", value)
|
||||||
|
if warfareBuffID == 2440: # Sov System Modifier Warp Speed Addition
|
||||||
|
self.ship.increaseItemAttr('warpSpeedMultiplier', value)
|
||||||
|
if warfareBuffID == 2441: # Sov System Modifier Shield Booster Bonus
|
||||||
|
self.modules.filteredItemBoost(
|
||||||
|
lambda mod: (mod.item.requiresSkill("Shield Operation")
|
||||||
|
or mod.item.requiresSkill("Capital Shield Operation")),
|
||||||
|
"shieldBonus", value, stackingPenalties=True)
|
||||||
|
if warfareBuffID == 2442: # Sov System Modifier Armor Repairer Bonus
|
||||||
|
self.modules.filteredItemBoost(
|
||||||
|
lambda mod: (mod.item.requiresSkill("Repair Systems")
|
||||||
|
or mod.item.requiresSkill("Capital Repair Systems")),
|
||||||
|
"armorDamageAmount", value, stackingPenalties=True)
|
||||||
|
|
||||||
del self.commandBonuses[warfareBuffID]
|
del self.commandBonuses[warfareBuffID]
|
||||||
|
|
||||||
def __resetDependentCalcs(self):
|
def __resetDependentCalcs(self):
|
||||||
@@ -1820,7 +1856,7 @@ class Fit:
|
|||||||
# That's right, for considerations of RR diminishing returns cycle time is rounded this way
|
# That's right, for considerations of RR diminishing returns cycle time is rounded this way
|
||||||
totalRaw += amount / int(cycleTime)
|
totalRaw += amount / int(cycleTime)
|
||||||
RR_ADDITION = 7000
|
RR_ADDITION = 7000
|
||||||
RR_MULTIPLIER = 10
|
RR_MULTIPLIER = 20
|
||||||
appliedRr = 0
|
appliedRr = 0
|
||||||
for amount, cycleTime in rrList:
|
for amount, cycleTime in rrList:
|
||||||
rrps = amount / int(cycleTime)
|
rrps = amount / int(cycleTime)
|
||||||
|
|||||||
@@ -66,8 +66,8 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut, M
|
|||||||
"""An instance of this class represents a module together with its charge and modified attributes"""
|
"""An instance of this class represents a module together with its charge and modified attributes"""
|
||||||
MINING_ATTRIBUTES = ("miningAmount",)
|
MINING_ATTRIBUTES = ("miningAmount",)
|
||||||
SYSTEM_GROUPS = (
|
SYSTEM_GROUPS = (
|
||||||
"Effect Beacon", "MassiveEnvironments", "Abyssal Hazards",
|
"Effect Beacon", "MassiveEnvironments", "Abyssal Hazards", "Non-Interactable Object",
|
||||||
"Non-Interactable Object", "Destructible Effect Beacon")
|
"Destructible Effect Beacon", "Sovereignty Hub System Effect Generator Upgrades")
|
||||||
|
|
||||||
def __init__(self, item, baseItem=None, mutaplasmid=None):
|
def __init__(self, item, baseItem=None, mutaplasmid=None):
|
||||||
"""Initialize a module from the program"""
|
"""Initialize a module from the program"""
|
||||||
|
|||||||
@@ -58,7 +58,8 @@ def getApplicationPerKey(src, tgt, atkSpeed, atkAngle, distance, tgtSpeed, tgtAn
|
|||||||
tgtSigRadius=tgtSigRadius)
|
tgtSigRadius=tgtSigRadius)
|
||||||
else:
|
else:
|
||||||
applicationMap[mod] = 0
|
applicationMap[mod] = 0
|
||||||
elif mod.hardpoint == FittingHardpoint.MISSILE:
|
# Missile launcher or civilian missile launcher
|
||||||
|
elif mod.hardpoint == FittingHardpoint.MISSILE or mod.item.ID == 32461:
|
||||||
# FoF missiles can shoot beyond lock range
|
# FoF missiles can shoot beyond lock range
|
||||||
if inLockRange or (mod.charge is not None and 'fofMissileLaunching' in mod.charge.effects):
|
if inLockRange or (mod.charge is not None and 'fofMissileLaunching' in mod.charge.effects):
|
||||||
applicationMap[mod] = getLauncherMult(
|
applicationMap[mod] = getLauncherMult(
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ from gui.builtinContextMenus import skillAffectors
|
|||||||
from gui.builtinContextMenus import itemFill
|
from gui.builtinContextMenus import itemFill
|
||||||
from gui.builtinContextMenus import droneAddStack
|
from gui.builtinContextMenus import droneAddStack
|
||||||
from gui.builtinContextMenus import cargoAdd
|
from gui.builtinContextMenus import cargoAdd
|
||||||
|
from gui.builtinContextMenus import cargoFill
|
||||||
from gui.builtinContextMenus import cargoAddAmmo
|
from gui.builtinContextMenus import cargoAddAmmo
|
||||||
from gui.builtinContextMenus import itemProject
|
from gui.builtinContextMenus import itemProject
|
||||||
from gui.builtinContextMenus import ammoToDmgPattern
|
from gui.builtinContextMenus import ammoToDmgPattern
|
||||||
|
|||||||
68
gui/builtinContextMenus/cargoFill.py
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
import wx
|
||||||
|
|
||||||
|
import gui.fitCommands as cmd
|
||||||
|
import gui.mainFrame
|
||||||
|
from gui.contextMenu import ContextMenuSingle
|
||||||
|
from service.fit import Fit
|
||||||
|
from eos.saveddata.cargo import Cargo
|
||||||
|
|
||||||
|
_t = wx.GetTranslation
|
||||||
|
|
||||||
|
|
||||||
|
class FillCargoWithItem(ContextMenuSingle):
|
||||||
|
def __init__(self):
|
||||||
|
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||||
|
|
||||||
|
def display(self, callingWindow, srcContext, mainItem):
|
||||||
|
if srcContext not in ("marketItemGroup", "marketItemMisc", "cargoItem"):
|
||||||
|
return False
|
||||||
|
|
||||||
|
if mainItem is None:
|
||||||
|
return False
|
||||||
|
|
||||||
|
if self.mainFrame.getActiveFit() is None:
|
||||||
|
return False
|
||||||
|
|
||||||
|
if srcContext in ("marketItemGroup", "marketItemMisc"):
|
||||||
|
if not (mainItem.isCharge or mainItem.isCommodity):
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def getText(self, callingWindow, itmContext, mainItem):
|
||||||
|
return _t("Fill Cargo With {0}").format(itmContext)
|
||||||
|
|
||||||
|
def activate(self, callingWindow, fullContext, mainItem, i):
|
||||||
|
fitID = self.mainFrame.getActiveFit()
|
||||||
|
fit = Fit.getInstance().getFit(fitID)
|
||||||
|
|
||||||
|
if isinstance(mainItem, Cargo):
|
||||||
|
itemVolume = mainItem.item.attributes['volume'].value
|
||||||
|
itemID = mainItem.itemID
|
||||||
|
else:
|
||||||
|
itemVolume = mainItem.attributes['volume'].value
|
||||||
|
itemID = int(mainItem.ID)
|
||||||
|
|
||||||
|
if itemVolume is None or itemVolume <= 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Calculate how many items can fit in the cargo
|
||||||
|
cargoCapacity = fit.ship.getModifiedItemAttr("capacity")
|
||||||
|
currentCargoVolume = fit.cargoBayUsed
|
||||||
|
availableVolume = cargoCapacity - currentCargoVolume
|
||||||
|
|
||||||
|
if availableVolume <= 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Calculate maximum amount that can fit
|
||||||
|
maxAmount = int(availableVolume / itemVolume)
|
||||||
|
if maxAmount <= 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Add the items to cargo
|
||||||
|
command = cmd.GuiAddCargoCommand(fitID=fitID, itemID=itemID, amount=maxAmount)
|
||||||
|
if self.mainFrame.command.Submit(command):
|
||||||
|
self.mainFrame.additionsPane.select("Cargo", focus=False)
|
||||||
|
|
||||||
|
|
||||||
|
FillCargoWithItem.register()
|
||||||
@@ -123,9 +123,12 @@ class AddEnvironmentEffect(ContextMenuUnconditional):
|
|||||||
data.groups[_t('Abyssal Weather')] = self.getAbyssalWeather()
|
data.groups[_t('Abyssal Weather')] = self.getAbyssalWeather()
|
||||||
data.groups[_t('Sansha Incursion')] = self.getEffectBeacons(
|
data.groups[_t('Sansha Incursion')] = self.getEffectBeacons(
|
||||||
_t('ContextMenu|ProjectedEffectManipulation|Sansha Incursion'))
|
_t('ContextMenu|ProjectedEffectManipulation|Sansha Incursion'))
|
||||||
|
data.groups[_t('Drifter Incursion')] = self.getDrifterIncursion()
|
||||||
data.groups[_t('Triglavian Invasion')] = self.getInvasionBeacons()
|
data.groups[_t('Triglavian Invasion')] = self.getInvasionBeacons()
|
||||||
# data.groups[_t('Pirate Insurgency')] = self.getEffectBeacons(
|
data.groups[_t('Pirate Insurgency')] = self.getEffectBeacons(
|
||||||
# _t('ContextMenu|ProjectedEffectManipulation|Insurgency'))
|
_t('ContextMenu|ProjectedEffectManipulation|Insurgency'),
|
||||||
|
extra_garbage=(_t('ContextMenu|ProjectedEffectManipulation|Beacon'),))
|
||||||
|
data.groups[_t('IHub Upgrades')] = self.getIHubEffects()
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def getEffectBeacons(self, *groups, extra_garbage=()):
|
def getEffectBeacons(self, *groups, extra_garbage=()):
|
||||||
@@ -176,7 +179,6 @@ class AddEnvironmentEffect(ContextMenuUnconditional):
|
|||||||
container.append(Entry(beacon.ID, beaconname, shortname))
|
container.append(Entry(beacon.ID, beaconname, shortname))
|
||||||
# Break loop on 1st result
|
# Break loop on 1st result
|
||||||
break
|
break
|
||||||
data.sort()
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def getAbyssalWeather(self):
|
def getAbyssalWeather(self):
|
||||||
@@ -218,34 +220,42 @@ class AddEnvironmentEffect(ContextMenuUnconditional):
|
|||||||
subsubdata.items.append(Entry(beacon.ID, beacon.customName, beacon.customName))
|
subsubdata.items.append(Entry(beacon.ID, beacon.customName, beacon.customName))
|
||||||
subdata.sort()
|
subdata.sort()
|
||||||
|
|
||||||
# PVP weather
|
|
||||||
data.items.append(Entry(49766, _t('PvP Weather'), _t('PvP Weather')))
|
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def getDestructibleBeacons(self):
|
def getDrifterIncursion(self):
|
||||||
data = Group()
|
data = self.getEffectBeacons(_t('ContextMenu|ProjectedEffectManipulation|Drifter Incursion'))
|
||||||
sMkt = Market.getInstance()
|
# Drifter Crisis
|
||||||
for item in sMkt.getItemsByGroup(sMkt.getGroup('Destructible Effect Beacon')):
|
item = Market.getInstance().getItem(87294)
|
||||||
if not item.isType('projected'):
|
data.items.append(Entry(item.ID, item.name, item.name))
|
||||||
continue
|
|
||||||
data.items.append(Entry(item.ID, item.name, item.name))
|
|
||||||
data.sort()
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def getInvasionBeacons(self):
|
def getInvasionBeacons(self):
|
||||||
data = self.getDestructibleBeacons()
|
data = Group()
|
||||||
|
# Trig Minor Victory
|
||||||
|
item = Market.getInstance().getItem(87177)
|
||||||
|
data.items.append(Entry(item.ID, item.name, item.name))
|
||||||
|
# Trig Final Liminality
|
||||||
|
item = Market.getInstance().getItem(87164)
|
||||||
|
data.items.append(Entry(item.ID, item.name, item.name))
|
||||||
# Turnur weather
|
# Turnur weather
|
||||||
item = Market.getInstance().getItem(74002)
|
item = Market.getInstance().getItem(74002)
|
||||||
data.items.append(Entry(item.ID, item.name, item.name))
|
data.items.append(Entry(item.ID, item.name, item.name))
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def getInsurgencyBeacons(self):
|
def getIHubEffects(self):
|
||||||
data = self.getDestructibleBeacons()
|
data = Group()
|
||||||
# Suppression Interdiction Range Beacon
|
# Electric
|
||||||
item = Market.getInstance().getItem(79839)
|
item = Market.getInstance().getItem(87950)
|
||||||
data.items.append(Entry(item.ID, item.name, item.name))
|
data.items.append(Entry(item.ID, item.name, _t('Electric')))
|
||||||
|
# Plasma
|
||||||
|
item = Market.getInstance().getItem(87949)
|
||||||
|
data.items.append(Entry(item.ID, item.name, _t('Plasma')))
|
||||||
|
# Exotic
|
||||||
|
item = Market.getInstance().getItem(87951)
|
||||||
|
data.items.append(Entry(item.ID, item.name, _t('Exotic')))
|
||||||
|
# Gamma
|
||||||
|
item = Market.getInstance().getItem(87815)
|
||||||
|
data.items.append(Entry(item.ID, item.name, _t('Gamma')))
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
AddEnvironmentEffect.register()
|
AddEnvironmentEffect.register()
|
||||||
|
|||||||
@@ -68,22 +68,27 @@ class PFContextMenuPref(PreferenceView):
|
|||||||
rbSizerRow2.Add(self.rbBox5, 1, wx.ALL, 5)
|
rbSizerRow2.Add(self.rbBox5, 1, wx.ALL, 5)
|
||||||
self.rbBox5.Bind(wx.EVT_RADIOBOX, self.OnSetting5Change)
|
self.rbBox5.Bind(wx.EVT_RADIOBOX, self.OnSetting5Change)
|
||||||
|
|
||||||
|
self.rbBox6 = wx.RadioBox(panel, -1, _t("Spoolup"), wx.DefaultPosition, wx.DefaultSize, [_t('Disabled'), _t('Enabled')], 1, wx.RA_SPECIFY_COLS)
|
||||||
|
self.rbBox6.SetSelection(self.settings.get('spoolup'))
|
||||||
|
rbSizerRow2.Add(self.rbBox6, 1, wx.ALL, 5)
|
||||||
|
self.rbBox6.Bind(wx.EVT_RADIOBOX, self.OnSetting6Change)
|
||||||
|
|
||||||
mainSizer.Add(rbSizerRow2, 1, wx.ALL | wx.EXPAND, 0)
|
mainSizer.Add(rbSizerRow2, 1, wx.ALL | wx.EXPAND, 0)
|
||||||
|
|
||||||
# Row 3
|
# Row 3
|
||||||
rbSizerRow3 = wx.BoxSizer(wx.HORIZONTAL)
|
rbSizerRow3 = wx.BoxSizer(wx.HORIZONTAL)
|
||||||
|
|
||||||
self.rbBox6 = wx.RadioBox(panel, -1, _t("Spoolup"), wx.DefaultPosition, wx.DefaultSize, [_t('Disabled'), _t('Enabled')], 1, wx.RA_SPECIFY_COLS)
|
|
||||||
self.rbBox6.SetSelection(self.settings.get('spoolup'))
|
|
||||||
rbSizerRow3.Add(self.rbBox6, 1, wx.ALL, 5)
|
|
||||||
self.rbBox6.Bind(wx.EVT_RADIOBOX, self.OnSetting6Change)
|
|
||||||
|
|
||||||
self.rbBox7 = wx.RadioBox(panel, -1, _t("Additions Panel Copy/Paste"), wx.DefaultPosition, wx.DefaultSize, [_t('Disabled'), _t('Enabled')], 1,
|
self.rbBox7 = wx.RadioBox(panel, -1, _t("Additions Panel Copy/Paste"), wx.DefaultPosition, wx.DefaultSize, [_t('Disabled'), _t('Enabled')], 1,
|
||||||
wx.RA_SPECIFY_COLS)
|
wx.RA_SPECIFY_COLS)
|
||||||
self.rbBox7.SetSelection(self.settings.get('additionsCopyPaste'))
|
self.rbBox7.SetSelection(self.settings.get('additionsCopyPaste'))
|
||||||
rbSizerRow3.Add(self.rbBox7, 1, wx.ALL, 5)
|
rbSizerRow3.Add(self.rbBox7, 1, wx.ALL, 5)
|
||||||
self.rbBox7.Bind(wx.EVT_RADIOBOX, self.OnSetting7Change)
|
self.rbBox7.Bind(wx.EVT_RADIOBOX, self.OnSetting7Change)
|
||||||
|
|
||||||
|
self.rbBox8 = wx.RadioBox(panel, -1, _t("Fill cargo with"), wx.DefaultPosition, wx.DefaultSize, [_t('Disabled'), _t('Enabled')], 1, wx.RA_SPECIFY_COLS)
|
||||||
|
self.rbBox8.SetSelection(self.settings.get('cargoFill'))
|
||||||
|
rbSizerRow3.Add(self.rbBox8, 1, wx.ALL, 5)
|
||||||
|
self.rbBox8.Bind(wx.EVT_RADIOBOX, self.OnSetting8Change)
|
||||||
|
|
||||||
mainSizer.Add(rbSizerRow3, 1, wx.ALL | wx.EXPAND, 0)
|
mainSizer.Add(rbSizerRow3, 1, wx.ALL | wx.EXPAND, 0)
|
||||||
|
|
||||||
panel.SetSizer(mainSizer)
|
panel.SetSizer(mainSizer)
|
||||||
@@ -110,6 +115,9 @@ class PFContextMenuPref(PreferenceView):
|
|||||||
def OnSetting7Change(self, event):
|
def OnSetting7Change(self, event):
|
||||||
self.settings.set('additionsCopyPaste', event.GetInt())
|
self.settings.set('additionsCopyPaste', event.GetInt())
|
||||||
|
|
||||||
|
def OnSetting8Change(self, event):
|
||||||
|
self.settings.set('cargoFill', event.GetInt())
|
||||||
|
|
||||||
def getImage(self):
|
def getImage(self):
|
||||||
return BitmapLoader.getBitmap("settings_menu", "gui")
|
return BitmapLoader.getBitmap("settings_menu", "gui")
|
||||||
|
|
||||||
|
|||||||
@@ -106,6 +106,14 @@ class PFStatViewPref(PreferenceView):
|
|||||||
rbSizerRow3.Add(self.rbOutgoing, 1, wx.TOP | wx.RIGHT, 5)
|
rbSizerRow3.Add(self.rbOutgoing, 1, wx.TOP | wx.RIGHT, 5)
|
||||||
self.rbOutgoing.Bind(wx.EVT_RADIOBOX, self.OnOutgoingChange)
|
self.rbOutgoing.Bind(wx.EVT_RADIOBOX, self.OnOutgoingChange)
|
||||||
|
|
||||||
|
self.rbBombing = wx.RadioBox(panel, -1, _t("Bombing"), wx.DefaultPosition, wx.DefaultSize, [_t('None'), _t('Minimal'), _t('Full')], 1,
|
||||||
|
wx.RA_SPECIFY_COLS)
|
||||||
|
# Disable minimal as we don't have a view for this yet
|
||||||
|
self.rbBombing.EnableItem(1, False)
|
||||||
|
self.rbBombing.SetSelection(self.settings.get('bombing'))
|
||||||
|
rbSizerRow3.Add(self.rbBombing, 1, wx.TOP | wx.RIGHT, 5)
|
||||||
|
self.rbBombing.Bind(wx.EVT_RADIOBOX, self.OnBombingChange)
|
||||||
|
|
||||||
mainSizer.Add(rbSizerRow3, 1, wx.ALL | wx.EXPAND, 0)
|
mainSizer.Add(rbSizerRow3, 1, wx.ALL | wx.EXPAND, 0)
|
||||||
|
|
||||||
panel.SetSizer(mainSizer)
|
panel.SetSizer(mainSizer)
|
||||||
@@ -144,5 +152,7 @@ class PFStatViewPref(PreferenceView):
|
|||||||
def getImage(self):
|
def getImage(self):
|
||||||
return BitmapLoader.getBitmap("settings_stats", "gui")
|
return BitmapLoader.getBitmap("settings_stats", "gui")
|
||||||
|
|
||||||
|
def OnBombingChange(self, event):
|
||||||
|
self.settings.set('bombing', event.GetInt())
|
||||||
|
|
||||||
PFStatViewPref.register()
|
PFStatViewPref.register()
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ __all__ = [
|
|||||||
"outgoingViewFull",
|
"outgoingViewFull",
|
||||||
"outgoingViewMinimal",
|
"outgoingViewMinimal",
|
||||||
"targetingMiscViewMinimal",
|
"targetingMiscViewMinimal",
|
||||||
|
"bombingViewFull",
|
||||||
"priceViewFull",
|
"priceViewFull",
|
||||||
"priceViewMinimal",
|
"priceViewMinimal",
|
||||||
]
|
]
|
||||||
|
|||||||
165
gui/builtinStatsViews/bombingViewFull.py
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
# =============================================================================
|
||||||
|
# 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 math
|
||||||
|
|
||||||
|
import gui.mainFrame
|
||||||
|
from gui.bitmap_loader import BitmapLoader
|
||||||
|
from gui.statsView import StatsView
|
||||||
|
from eos.const import FittingModuleState
|
||||||
|
from service.market import Market
|
||||||
|
|
||||||
|
_t = wx.GetTranslation
|
||||||
|
|
||||||
|
|
||||||
|
class BombingViewFull(StatsView):
|
||||||
|
name = "bombingViewFull"
|
||||||
|
|
||||||
|
def __init__(self, parent):
|
||||||
|
StatsView.__init__(self)
|
||||||
|
self.parent = parent
|
||||||
|
self._cachedValues = []
|
||||||
|
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||||
|
|
||||||
|
def getHeaderText(self, fit):
|
||||||
|
return _t("Bombing")
|
||||||
|
|
||||||
|
def getTextExtentW(self, text):
|
||||||
|
width, height = self.parent.GetTextExtent(text)
|
||||||
|
return width
|
||||||
|
|
||||||
|
def populatePanel(self, contentPanel, headerPanel):
|
||||||
|
contentSizer = contentPanel.GetSizer()
|
||||||
|
self.panel = contentPanel
|
||||||
|
|
||||||
|
self.headerPanel = headerPanel
|
||||||
|
|
||||||
|
# Display table
|
||||||
|
sizerBombing = wx.FlexGridSizer(7, 5, 0, 0)
|
||||||
|
for i in range(4):
|
||||||
|
sizerBombing.AddGrowableCol(i + 1)
|
||||||
|
contentSizer.Add(sizerBombing, 0, wx.EXPAND, 0)
|
||||||
|
|
||||||
|
# first row is for icons
|
||||||
|
bitmap = BitmapLoader.getStaticBitmap("skill_big", contentPanel, "gui")
|
||||||
|
tooltip = wx.ToolTip(_t("Covert Ops level"))
|
||||||
|
bitmap.SetToolTip(tooltip)
|
||||||
|
sizerBombing.Add(bitmap, 0, wx.ALIGN_CENTER)
|
||||||
|
toolTipText = {
|
||||||
|
"em": _t("Electron Bomb"),
|
||||||
|
"thermal": _t("Scorch Bomb"),
|
||||||
|
"kinetic": _t("Concussion Bomb"),
|
||||||
|
"explosive": _t("Shrapnel Bomb")
|
||||||
|
}
|
||||||
|
for damageType in ("em", "thermal", "kinetic", "explosive"):
|
||||||
|
bitmap = BitmapLoader.getStaticBitmap("%s_big" % damageType, contentPanel, "gui")
|
||||||
|
tooltip = wx.ToolTip(toolTipText[damageType])
|
||||||
|
bitmap.SetToolTip(tooltip)
|
||||||
|
sizerBombing.Add(bitmap, 0, wx.ALIGN_CENTER)
|
||||||
|
|
||||||
|
# the other rows are for each possible level of Covert Ops skill
|
||||||
|
for covertLevel in ("0", "1", "2", "3", "4", "5"):
|
||||||
|
label = wx.StaticText(contentPanel, wx.ID_ANY, "%s" % covertLevel)
|
||||||
|
tooltip = wx.ToolTip(_t("Covert Ops level"))
|
||||||
|
label.SetToolTip(tooltip)
|
||||||
|
sizerBombing.Add(label, 0, wx.ALIGN_CENTER)
|
||||||
|
|
||||||
|
for damageType in ("em", "thermal", "kinetic", "explosive"):
|
||||||
|
label = wx.StaticText(contentPanel, wx.ID_ANY, "0.0")
|
||||||
|
setattr(self, "labelDamagetypeCovertlevel%s%s" % (damageType.capitalize(), covertLevel), label)
|
||||||
|
sizerBombing.Add(label, 0, wx.ALIGN_CENTER)
|
||||||
|
|
||||||
|
def refreshPanel(self, fit):
|
||||||
|
# If we did anything interesting, we'd update our labels to reflect the new fit's stats here
|
||||||
|
if fit is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
mkt = Market.getInstance()
|
||||||
|
emBomb = mkt.getItem(27920)
|
||||||
|
thermalBomb = mkt.getItem(27916)
|
||||||
|
kineticBomb = mkt.getItem(27912)
|
||||||
|
explosiveBomb = mkt.getItem(27918)
|
||||||
|
environementBombDamageModifier = 1.0
|
||||||
|
|
||||||
|
# list all environmental effects affecting bomb damage
|
||||||
|
relevantEffects = [
|
||||||
|
'Class 6 Red Giant Effects',
|
||||||
|
'Class 5 Red Giant Effects',
|
||||||
|
'Class 4 Red Giant Effects',
|
||||||
|
'Class 3 Red Giant Effects',
|
||||||
|
'Class 2 Red Giant Effects',
|
||||||
|
'Class 1 Red Giant Effects',
|
||||||
|
]
|
||||||
|
for effect in fit.projectedModules:
|
||||||
|
if effect.state == FittingModuleState.ONLINE and effect.fullName in relevantEffects:
|
||||||
|
# note: despite the name, smartbombDamageMultiplier applies to the damage of launched bombs
|
||||||
|
environementBombDamageModifier = environementBombDamageModifier *\
|
||||||
|
effect.item.attributes['smartbombDamageMultiplier'].value
|
||||||
|
|
||||||
|
# signature radius of the current fit to calculate the application of bombs
|
||||||
|
shipSigRadius = fit.ship.getModifiedItemAttr('signatureRadius')
|
||||||
|
|
||||||
|
# get the raw values for all hp layers
|
||||||
|
hullHP = fit.ship.getModifiedItemAttr('hp')
|
||||||
|
armorHP = fit.ship.getModifiedItemAttr('armorHP')
|
||||||
|
shieldHP = fit.ship.getModifiedItemAttr('shieldCapacity')
|
||||||
|
|
||||||
|
# we calculate the total ehp for pure damage of all types based on raw hp and resonance (resonance= 1-resistance)
|
||||||
|
emEhp = hullHP / fit.ship.getModifiedItemAttr('emDamageResonance') +\
|
||||||
|
armorHP / fit.ship.getModifiedItemAttr('armorEmDamageResonance') +\
|
||||||
|
shieldHP / fit.ship.getModifiedItemAttr('shieldEmDamageResonance')
|
||||||
|
thermalEhp = hullHP / fit.ship.getModifiedItemAttr('thermalDamageResonance') +\
|
||||||
|
armorHP / fit.ship.getModifiedItemAttr('armorThermalDamageResonance') +\
|
||||||
|
shieldHP / fit.ship.getModifiedItemAttr('shieldThermalDamageResonance')
|
||||||
|
kineticEhp = hullHP / fit.ship.getModifiedItemAttr('kineticDamageResonance') +\
|
||||||
|
armorHP / fit.ship.getModifiedItemAttr('armorKineticDamageResonance') +\
|
||||||
|
shieldHP / fit.ship.getModifiedItemAttr('shieldKineticDamageResonance')
|
||||||
|
explosiveEhp = hullHP / fit.ship.getModifiedItemAttr('explosiveDamageResonance') +\
|
||||||
|
armorHP / fit.ship.getModifiedItemAttr('armorExplosiveDamageResonance') +\
|
||||||
|
shieldHP / fit.ship.getModifiedItemAttr('shieldExplosiveDamageResonance')
|
||||||
|
|
||||||
|
# updates the labels for each combination of covert op level and damage type
|
||||||
|
for covertLevel in ("0", "1", "2", "3", "4", "5"):
|
||||||
|
covertOpsBombDamageModifier = 1 + 0.05 * int(covertLevel)
|
||||||
|
for damageType, ehp, bomber, bomb in (("em", emEhp, "Purifier", emBomb),
|
||||||
|
("thermal", thermalEhp, "Nemesis", thermalBomb),
|
||||||
|
("kinetic", kineticEhp, "Manticore", kineticBomb),
|
||||||
|
("explosive", explosiveEhp, "Hound", explosiveBomb)):
|
||||||
|
baseBombDamage = (bomb.attributes['emDamage'].value + bomb.attributes['thermalDamage'].value +
|
||||||
|
bomb.attributes['kineticDamage'].value + bomb.attributes['explosiveDamage'].value)
|
||||||
|
appliedBombDamage = baseBombDamage * covertOpsBombDamageModifier * environementBombDamageModifier * \
|
||||||
|
(min(bomb.attributes['signatureRadius'].value, shipSigRadius) /
|
||||||
|
bomb.attributes['signatureRadius'].value)
|
||||||
|
label = getattr(self, "labelDamagetypeCovertlevel%s%s" % (damageType.capitalize(), covertLevel))
|
||||||
|
label.SetLabel("{:.1f}".format(math.ceil((ehp / appliedBombDamage) * 10) / 10))
|
||||||
|
if covertLevel != "0":
|
||||||
|
label.SetToolTip("Number of %s to kill a %s using a %s "
|
||||||
|
"with Covert Ops level %s" % (bomb.customName, fit.name, bomber, covertLevel))
|
||||||
|
else:
|
||||||
|
label.SetToolTip("Number of %s to kill a %s with Covert Ops level %s" %
|
||||||
|
(bomb.customName, fit.name, covertLevel))
|
||||||
|
|
||||||
|
|
||||||
|
self.panel.Layout()
|
||||||
|
self.headerPanel.Layout()
|
||||||
|
|
||||||
|
|
||||||
|
BombingViewFull.register()
|
||||||
@@ -481,6 +481,35 @@ class SkillTreeView(wx.Panel):
|
|||||||
|
|
||||||
toClipboard(list)
|
toClipboard(list)
|
||||||
|
|
||||||
|
def exportSkillsSuperCondensed(self, evt):
|
||||||
|
char = self.charEditor.entityEditor.getActiveEntity()
|
||||||
|
|
||||||
|
skills = {}
|
||||||
|
explicit_levels = {}
|
||||||
|
implicit_levels = {}
|
||||||
|
for s in char.__class__.getSkillNameMap().keys():
|
||||||
|
skill = char.getSkill(s)
|
||||||
|
if skill.level < 1:
|
||||||
|
continue
|
||||||
|
skills[skill.item.ID] = skill
|
||||||
|
explicit_levels[skill.item.ID] = skill.level
|
||||||
|
|
||||||
|
for skill in skills.values():
|
||||||
|
for req_skill, level in skill.item.requiredSkills.items():
|
||||||
|
if req_skill.ID not in implicit_levels or implicit_levels[req_skill.ID] < level:
|
||||||
|
implicit_levels[req_skill.ID] = level
|
||||||
|
|
||||||
|
condensed = {}
|
||||||
|
for typeID, level in explicit_levels.items():
|
||||||
|
if typeID not in implicit_levels or implicit_levels[typeID] < level:
|
||||||
|
condensed[skills[typeID].item.name] = level
|
||||||
|
|
||||||
|
lines = []
|
||||||
|
for skill in sorted(condensed):
|
||||||
|
lines.append(f'{skill}\t{condensed[skill]}')
|
||||||
|
|
||||||
|
toClipboard('\n'.join(lines))
|
||||||
|
|
||||||
def onSecStatus(self, event):
|
def onSecStatus(self, event):
|
||||||
sChar = Character.getInstance()
|
sChar = Character.getInstance()
|
||||||
char = self.charEditor.entityEditor.getActiveEntity()
|
char = self.charEditor.entityEditor.getActiveEntity()
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ class StatsPane(wx.Panel):
|
|||||||
"outgoing",
|
"outgoing",
|
||||||
"capacitor",
|
"capacitor",
|
||||||
"targetingMisc",
|
"targetingMisc",
|
||||||
|
"bombing",
|
||||||
"price",
|
"price",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ from gui.builtinStatsViews import ( # noqa: E402, F401
|
|||||||
capacitorViewFull,
|
capacitorViewFull,
|
||||||
rechargeViewFull,
|
rechargeViewFull,
|
||||||
targetingMiscViewMinimal,
|
targetingMiscViewMinimal,
|
||||||
|
bombingViewFull,
|
||||||
priceViewFull,
|
priceViewFull,
|
||||||
priceViewMinimal,
|
priceViewMinimal,
|
||||||
outgoingViewFull,
|
outgoingViewFull,
|
||||||
|
|||||||
BIN
imgs/icons/10877@1x.png
Normal file
|
After Width: | Height: | Size: 721 B |
BIN
imgs/icons/10877@2x.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
imgs/icons/1156@1x.png
Normal file
|
After Width: | Height: | Size: 762 B |
BIN
imgs/icons/1156@2x.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 433 B After Width: | Height: | Size: 539 B |
|
Before Width: | Height: | Size: 944 B After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 717 B |
|
Before Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 804 B After Width: | Height: | Size: 787 B |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 788 B After Width: | Height: | Size: 799 B |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 818 B After Width: | Height: | Size: 796 B |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 808 B After Width: | Height: | Size: 785 B |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 807 B After Width: | Height: | Size: 756 B |
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 816 B After Width: | Height: | Size: 806 B |
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 809 B After Width: | Height: | Size: 816 B |
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 823 B After Width: | Height: | Size: 805 B |
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 820 B After Width: | Height: | Size: 756 B |
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 831 B After Width: | Height: | Size: 792 B |
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 821 B After Width: | Height: | Size: 803 B |
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 839 B After Width: | Height: | Size: 798 B |
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 819 B After Width: | Height: | Size: 747 B |
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 817 B After Width: | Height: | Size: 790 B |
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 820 B After Width: | Height: | Size: 801 B |
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 823 B After Width: | Height: | Size: 789 B |
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 780 B After Width: | Height: | Size: 769 B |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 829 B After Width: | Height: | Size: 805 B |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 821 B After Width: | Height: | Size: 796 B |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 824 B |
|
Before Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 784 B After Width: | Height: | Size: 809 B |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 808 B After Width: | Height: | Size: 847 B |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 829 B After Width: | Height: | Size: 856 B |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 833 B |
|
Before Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 783 B After Width: | Height: | Size: 802 B |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 814 B After Width: | Height: | Size: 841 B |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 825 B After Width: | Height: | Size: 840 B |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 821 B |
|
Before Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 782 B After Width: | Height: | Size: 821 B |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 816 B After Width: | Height: | Size: 850 B |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 823 B After Width: | Height: | Size: 839 B |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 814 B |
|
Before Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 787 B After Width: | Height: | Size: 794 B |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 836 B After Width: | Height: | Size: 847 B |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 846 B After Width: | Height: | Size: 853 B |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 848 B After Width: | Height: | Size: 852 B |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 816 B After Width: | Height: | Size: 807 B |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 778 B After Width: | Height: | Size: 797 B |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |