Merge branch 'master' of github.com-shyadow:pyfa-org/Pyfa into master
154
db_update.py
@@ -27,7 +27,8 @@ import re
|
||||
import sqlite3
|
||||
import sys
|
||||
|
||||
from sqlalchemy import or_
|
||||
import sqlalchemy.orm
|
||||
from sqlalchemy import or_, and_
|
||||
|
||||
|
||||
# todo: need to set the EOS language to en, becasuse this assumes it's being run within an English context
|
||||
@@ -146,6 +147,7 @@ def update_db():
|
||||
# Nearly useless and clutter search results too much
|
||||
elif (
|
||||
row['typeName_en-us'].startswith('Limited Synth ') or
|
||||
row['typeName_en-us'].startswith('Expired ') or
|
||||
row['typeName_en-us'].endswith(' Filament') and (
|
||||
"'Needlejack'" not in row['typeName_en-us'] and
|
||||
"'Devana'" not in row['typeName_en-us'] and
|
||||
@@ -595,8 +597,14 @@ def update_db():
|
||||
attr.value = 4.0
|
||||
for item in eos.db.gamedata_session.query(eos.gamedata.Item).filter(or_(
|
||||
eos.gamedata.Item.name.like('%abyssal%'),
|
||||
eos.gamedata.Item.name.like('%mutated%')
|
||||
eos.gamedata.Item.name.like('%mutated%'),
|
||||
# Drifter weapons are published for some reason
|
||||
eos.gamedata.Item.name.in_(('Lux Kontos', 'Lux Xiphos'))
|
||||
)).all():
|
||||
if 'Asteroid Mining Crystal' in item.name:
|
||||
continue
|
||||
if 'Mutated Drone Specialization' in item.name:
|
||||
continue
|
||||
item.published = False
|
||||
|
||||
for x in [
|
||||
@@ -606,6 +614,148 @@ def update_db():
|
||||
print ('Removing Category: {}'.format(cat.name))
|
||||
eos.db.gamedata_session.delete(cat)
|
||||
|
||||
def _hardcodeAttribs(typeID, attrMap):
|
||||
for attrName, value in attrMap.items():
|
||||
try:
|
||||
attr = eos.db.gamedata_session.query(eos.gamedata.Attribute).filter(and_(
|
||||
eos.gamedata.Attribute.name == attrName, eos.gamedata.Attribute.typeID == typeID)).one()
|
||||
except sqlalchemy.orm.exc.NoResultFound:
|
||||
attrInfo = eos.db.gamedata_session.query(eos.gamedata.AttributeInfo).filter(eos.gamedata.AttributeInfo.name == attrName).one()
|
||||
attr = eos.gamedata.Attribute()
|
||||
attr.ID = attrInfo.ID
|
||||
attr.typeID = typeID
|
||||
attr.value = value
|
||||
eos.db.gamedata_session.add(attr)
|
||||
else:
|
||||
attr.value = value
|
||||
|
||||
def _hardcodeEffects(typeID, effectMap):
|
||||
item = eos.db.gamedata_session.query(eos.gamedata.Item).filter(eos.gamedata.Item.ID == typeID).one()
|
||||
item.effects.clear()
|
||||
for effectID, effectName in effectMap.items():
|
||||
effect = eos.gamedata.Effect()
|
||||
effect.effectID = effectID
|
||||
effect.effectName = effectName
|
||||
item.effects[effectName] = effect
|
||||
|
||||
def hardcodeRaiju():
|
||||
attrMap = {
|
||||
'hp': 600,
|
||||
'capacity': 220,
|
||||
'mass': 987000,
|
||||
'volume': 27289,
|
||||
'agility': 3.1,
|
||||
'emDamageResonance': 1 - 0.33,
|
||||
'thermalDamageResonance': 1 - 0.33,
|
||||
'kineticDamageResonance': 1 - 0.33,
|
||||
'explosiveDamageResonance': 1 - 0.33,
|
||||
'armorHP': 700,
|
||||
'armorEmDamageResonance': 1 - 0.5,
|
||||
'armorThermalDamageResonance': 1 - 0.8625,
|
||||
'armorKineticDamageResonance': 1 - 0.625,
|
||||
'armorExplosiveDamageResonance': 1 - 0.1,
|
||||
'shieldCapacity': 850,
|
||||
'shieldRechargeRate': 625000,
|
||||
'shieldEmDamageResonance': 1 - 0.15,
|
||||
'shieldThermalDamageResonance': 1 - 0.8,
|
||||
'shieldKineticDamageResonance': 1 - 0.7,
|
||||
'shieldExplosiveDamageResonance': 1 - 0.5,
|
||||
'energyWarfareResistance': 1,
|
||||
'weaponDisruptionResistance': 1,
|
||||
'capacitorCapacity': 400,
|
||||
'rechargeRate': 195000,
|
||||
'maxTargetRange': 70000,
|
||||
'maxLockedTargets': 7,
|
||||
'signatureRadius': 32,
|
||||
'scanResolution': 650,
|
||||
'scanRadarStrength': 0,
|
||||
'scanLadarStrength': 0,
|
||||
'scanMagnetometricStrength': 0,
|
||||
'scanGravimetricStrength': 13,
|
||||
'maxVelocity': 440,
|
||||
'warpSpeedMultiplier': 5.5,
|
||||
'cpuOutput': 247,
|
||||
'powerOutput': 38,
|
||||
'upgradeCapacity': 400,
|
||||
'launcherSlotsLeft': 3,
|
||||
'hiSlots': 3,
|
||||
'medSlots': 6,
|
||||
'lowSlots': 3,
|
||||
'rigSlots': 3,
|
||||
'rigSize': 1}
|
||||
effectMap = {
|
||||
100100: 'pyfaCustomRaijuPointRange',
|
||||
100101: 'pyfaCustomRaijuPointCap',
|
||||
100102: 'pyfaCustomRaijuDampStr',
|
||||
100103: 'pyfaCustomRaijuDampCap',
|
||||
100104: 'pyfaCustomRaijuMissileDmg',
|
||||
100105: 'pyfaCustomRaijuMissileFlightTime',
|
||||
100106: 'pyfaCustomRaijuMissileFlightVelocity'}
|
||||
_hardcodeAttribs(60765, attrMap)
|
||||
_hardcodeEffects(60765, effectMap)
|
||||
|
||||
def hardcodeLaelaps():
|
||||
attrMap = {
|
||||
'hp': 2300,
|
||||
'capacity': 420,
|
||||
'droneCapacity': 25,
|
||||
'droneBandwidth': 25,
|
||||
'mass': 10298000,
|
||||
'volume': 101000,
|
||||
'agility': 0.48,
|
||||
'emDamageResonance': 1 - 0.33,
|
||||
'thermalDamageResonance': 1 - 0.33,
|
||||
'kineticDamageResonance': 1 - 0.33,
|
||||
'explosiveDamageResonance': 1 - 0.33,
|
||||
'armorHP': 2730,
|
||||
'armorEmDamageResonance': 1 - 0.5,
|
||||
'armorThermalDamageResonance': 1 - 0.8625,
|
||||
'armorKineticDamageResonance': 1 - 0.625,
|
||||
'armorExplosiveDamageResonance': 1 - 0.1,
|
||||
'shieldCapacity': 3540,
|
||||
'shieldRechargeRate': 1250000,
|
||||
'shieldEmDamageResonance': 1 - 0.15,
|
||||
'shieldThermalDamageResonance': 1 - 0.8,
|
||||
'shieldKineticDamageResonance': 1 - 0.7,
|
||||
'shieldExplosiveDamageResonance': 1 - 0.5,
|
||||
'energyWarfareResistance': 1,
|
||||
'weaponDisruptionResistance': 1,
|
||||
'capacitorCapacity': 1550,
|
||||
'rechargeRate': 315000,
|
||||
'maxTargetRange': 80000,
|
||||
'maxLockedTargets': 7,
|
||||
'signatureRadius': 135,
|
||||
'scanResolution': 300,
|
||||
'scanRadarStrength': 0,
|
||||
'scanLadarStrength': 0,
|
||||
'scanMagnetometricStrength': 0,
|
||||
'scanGravimetricStrength': 21,
|
||||
'maxVelocity': 230,
|
||||
'warpSpeedMultiplier': 4.5,
|
||||
'cpuOutput': 560,
|
||||
'powerOutput': 900,
|
||||
'upgradeCapacity': 400,
|
||||
'launcherSlotsLeft': 5,
|
||||
'hiSlots': 7,
|
||||
'medSlots': 5,
|
||||
'lowSlots': 4,
|
||||
'rigSlots': 3,
|
||||
'rigSize': 2}
|
||||
effectMap = {
|
||||
100200: 'pyfaCustomLaelapsWdfgRange',
|
||||
100201: 'pyfaCustomLaelapsMissileReload',
|
||||
100202: 'pyfaCustomLaelapsMissileDamage',
|
||||
100203: 'pyfaCustomLaelapsMissileRof',
|
||||
100204: 'pyfaCustomLaelapsShieldResists',
|
||||
100205: 'pyfaCustomLaelapsMissileFlightTime',
|
||||
100206: 'pyfaCustomLaelapsWdfgSigPenalty',
|
||||
100207: 'pyfaCustomLaelapsMissileFlightVelocity'}
|
||||
_hardcodeAttribs(60764, attrMap)
|
||||
_hardcodeEffects(60764, effectMap)
|
||||
|
||||
hardcodeRaiju()
|
||||
hardcodeLaelaps()
|
||||
|
||||
eos.db.gamedata_session.commit()
|
||||
eos.db.gamedata_engine.execute('VACUUM')
|
||||
|
||||
|
||||
68
eos/db/migrations/upgrade46.py
Normal file
@@ -0,0 +1,68 @@
|
||||
"""
|
||||
Migration 46
|
||||
|
||||
- Mining crystal changes
|
||||
"""
|
||||
|
||||
CONVERSIONS = {
|
||||
60276: ( # Simple Asteroid Mining Crystal Type A I
|
||||
18066, # Veldspar Mining Crystal I
|
||||
18062, # Scordite Mining Crystal I
|
||||
18060, # Pyroxeres Mining Crystal I
|
||||
18058, # Plagioclase Mining Crystal I
|
||||
),
|
||||
60281: ( # Simple Asteroid Mining Crystal Type A II
|
||||
18618, # Veldspar Mining Crystal II
|
||||
18616, # Scordite Mining Crystal II
|
||||
18614, # Pyroxeres Mining Crystal II
|
||||
18612, # Plagioclase Mining Crystal II
|
||||
),
|
||||
60285: ( # Coherent Asteroid Mining Crystal Type A I
|
||||
18056, # Omber Mining Crystal I
|
||||
18052, # Kernite Mining Crystal I
|
||||
18050, # Jaspet Mining Crystal I
|
||||
18048, # Hemorphite Mining Crystal I
|
||||
18046, # Hedbergite Mining Crystal I
|
||||
),
|
||||
60288: ( # Coherent Asteroid Mining Crystal Type A II
|
||||
18610, # Omber Mining Crystal II
|
||||
18604, # Jaspet Mining Crystal II
|
||||
18606, # Kernite Mining Crystal II
|
||||
18600, # Hedbergite Mining Crystal II
|
||||
18602, # Hemorphite Mining Crystal II
|
||||
),
|
||||
60291: ( # Variegated Asteroid Mining Crystal Type A I
|
||||
18044, # Gneiss Mining Crystal I
|
||||
18042, # Dark Ochre Mining Crystal I
|
||||
18040, # Crokite Mining Crystal I
|
||||
),
|
||||
60294: ( # Variegated Asteroid Mining Crystal Type A II
|
||||
18598, # Gneiss Mining Crystal II
|
||||
18596, # Dark Ochre Mining Crystal II
|
||||
18594, # Crokite Mining Crystal II
|
||||
),
|
||||
60297: ( # Complex Asteroid Mining Crystal Type A I
|
||||
18038, # Bistot Mining Crystal I
|
||||
18036, # Arkonor Mining Crystal I
|
||||
18064, # Spodumain Mining Crystal I
|
||||
),
|
||||
60300: ( # Complex Asteroid Mining Crystal Type A II
|
||||
18592, # Bistot Mining Crystal II
|
||||
18590, # Arkonor Mining Crystal II
|
||||
18624, # Spodumain Mining Crystal II
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
def upgrade(saveddata_engine):
|
||||
# Convert modules
|
||||
for replacement_item, list in CONVERSIONS.items():
|
||||
for retired_item in list:
|
||||
saveddata_engine.execute('UPDATE "modules" SET "itemID" = ? WHERE "itemID" = ?',
|
||||
(replacement_item, retired_item))
|
||||
saveddata_engine.execute('UPDATE "modules" SET "baseItemID" = ? WHERE "baseItemID" = ?',
|
||||
(replacement_item, retired_item))
|
||||
saveddata_engine.execute('UPDATE "modules" SET "chargeID" = ? WHERE "chargeID" = ?',
|
||||
(replacement_item, retired_item))
|
||||
saveddata_engine.execute('UPDATE "cargo" SET "itemID" = ? WHERE "itemID" = ?',
|
||||
(replacement_item, retired_item))
|
||||
1680
eos/effects.py
@@ -71,30 +71,30 @@ class ItemAttrShortcut:
|
||||
|
||||
def getModifiedItemAttr(self, key, default=0):
|
||||
return_value = self.itemModifiedAttributes.get(key)
|
||||
return return_value or default
|
||||
return return_value if return_value is not None else default
|
||||
|
||||
def getModifiedItemAttrExtended(self, key, extraMultipliers=None, ignoreAfflictors=(), default=0):
|
||||
return_value = self.itemModifiedAttributes.getExtended(key, extraMultipliers=extraMultipliers, ignoreAfflictors=ignoreAfflictors)
|
||||
return return_value or default
|
||||
return return_value if return_value is not None else default
|
||||
|
||||
def getItemBaseAttrValue(self, key, default=0):
|
||||
return_value = self.itemModifiedAttributes.getOriginal(key)
|
||||
return return_value or default
|
||||
return return_value if return_value is not None else default
|
||||
|
||||
|
||||
class ChargeAttrShortcut:
|
||||
|
||||
def getModifiedChargeAttr(self, key, default=0):
|
||||
return_value = self.chargeModifiedAttributes.get(key)
|
||||
return return_value or default
|
||||
return return_value if return_value is not None else default
|
||||
|
||||
def getModifiedChargeAttrExtended(self, key, extraMultipliers=None, ignoreAfflictors=(), default=0):
|
||||
return_value = self.chargeModifiedAttributes.getExtended(key, extraMultipliers=extraMultipliers, ignoreAfflictors=ignoreAfflictors)
|
||||
return return_value or default
|
||||
return return_value if return_value is not None else default
|
||||
|
||||
def getChargeBaseAttrValue(self, key, default=0):
|
||||
return_value = self.chargeModifiedAttributes.getOriginal(key)
|
||||
return return_value or default
|
||||
return return_value if return_value is not None else default
|
||||
|
||||
|
||||
class ModifiedAttributeDict(MutableMapping):
|
||||
|
||||
@@ -80,7 +80,8 @@ class Drone(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut, Mu
|
||||
self.__charge = None
|
||||
self.__baseVolley = None
|
||||
self.__baseRRAmount = None
|
||||
self.__miningyield = None
|
||||
self.__miningYield = None
|
||||
self.__miningWaste = None
|
||||
self.__itemModifiedAttributes = ModifiedAttributeDict()
|
||||
self.__itemModifiedAttributes.original = self._item.attributes
|
||||
self.__itemModifiedAttributes.overrides = self._item.overrides
|
||||
@@ -89,9 +90,8 @@ class Drone(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut, Mu
|
||||
self._mutaLoadMutators(mutatorClass=MutatorDrone)
|
||||
self.__itemModifiedAttributes.mutators = self.mutators
|
||||
|
||||
# pheonix todo: check the attribute itself, not the modified. this will always return 0 now.
|
||||
chargeID = self.getModifiedItemAttr("entityMissileTypeID", None)
|
||||
if chargeID is not None:
|
||||
if chargeID:
|
||||
charge = eos.db.getItem(int(chargeID))
|
||||
self.__charge = charge
|
||||
self.__chargeModifiedAttributes.original = charge.attributes
|
||||
@@ -129,8 +129,8 @@ class Drone(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut, Mu
|
||||
cycleTime = self.getModifiedItemAttr("missileLaunchDuration", 0)
|
||||
else:
|
||||
for attr in ("speed", "duration", "durationHighisGood"):
|
||||
cycleTime = self.getModifiedItemAttr(attr, None)
|
||||
if cycleTime is not None:
|
||||
cycleTime = self.getModifiedItemAttr(attr)
|
||||
if cycleTime:
|
||||
break
|
||||
if cycleTime is None:
|
||||
return 0
|
||||
@@ -237,35 +237,49 @@ class Drone(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut, Mu
|
||||
|
||||
def getCycleParameters(self, reloadOverride=None):
|
||||
cycleTime = self.cycleTime
|
||||
if cycleTime == 0:
|
||||
if not cycleTime:
|
||||
return None
|
||||
return CycleInfo(self.cycleTime, 0, math.inf, False)
|
||||
|
||||
@property
|
||||
def miningStats(self):
|
||||
if self.__miningyield is None:
|
||||
if self.mines is True and self.amountActive > 0:
|
||||
getter = self.getModifiedItemAttr
|
||||
cycleParams = self.getCycleParameters()
|
||||
if cycleParams is None:
|
||||
self.__miningyield = 0
|
||||
else:
|
||||
cycleTime = cycleParams.averageTime
|
||||
volley = sum([getter(d) for d in self.MINING_ATTRIBUTES]) * self.amountActive
|
||||
self.__miningyield = volley / (cycleTime / 1000.0)
|
||||
else:
|
||||
self.__miningyield = 0
|
||||
def getMiningYPS(self, ignoreState=False):
|
||||
if not ignoreState and self.amountActive <= 0:
|
||||
return 0
|
||||
if self.__miningYield is None:
|
||||
self.__miningYield, self.__miningWaste = self.__calculateMining()
|
||||
return self.__miningYield
|
||||
|
||||
return self.__miningyield
|
||||
def getMiningWPS(self, ignoreState=False):
|
||||
if not ignoreState and self.amountActive <= 0:
|
||||
return 0
|
||||
if self.__miningWaste is None:
|
||||
self.__miningYield, self.__miningWaste = self.__calculateMining()
|
||||
return self.__miningWaste
|
||||
|
||||
def __calculateMining(self):
|
||||
if self.mines is True:
|
||||
getter = self.getModifiedItemAttr
|
||||
cycleParams = self.getCycleParameters()
|
||||
if cycleParams is None:
|
||||
yps = 0
|
||||
else:
|
||||
cycleTime = cycleParams.averageTime
|
||||
yield_ = sum([getter(d) for d in self.MINING_ATTRIBUTES]) * self.amount
|
||||
yps = yield_ / (cycleTime / 1000.0)
|
||||
wasteChance = self.getModifiedItemAttr("miningWasteProbability")
|
||||
wasteMult = self.getModifiedItemAttr("miningWastedVolumeMultiplier")
|
||||
wps = yps * max(0, min(1, wasteChance / 100)) * wasteMult
|
||||
return yps, wps
|
||||
else:
|
||||
return 0, 0
|
||||
|
||||
@property
|
||||
def maxRange(self):
|
||||
attrs = ("shieldTransferRange", "powerTransferRange",
|
||||
"energyDestabilizationRange", "empFieldRange",
|
||||
"ecmBurstRange", "maxRange")
|
||||
"ecmBurstRange", "maxRange", "ECMRangeOptimal")
|
||||
for attr in attrs:
|
||||
maxRange = self.getModifiedItemAttr(attr, None)
|
||||
if maxRange is not None:
|
||||
maxRange = self.getModifiedItemAttr(attr)
|
||||
if maxRange:
|
||||
return maxRange
|
||||
if self.charge is not None:
|
||||
delay = self.getModifiedChargeAttr("explosionDelay")
|
||||
@@ -280,8 +294,8 @@ class Drone(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut, Mu
|
||||
def falloff(self):
|
||||
attrs = ("falloff", "falloffEffectiveness")
|
||||
for attr in attrs:
|
||||
falloff = self.getModifiedItemAttr(attr, None)
|
||||
if falloff is not None:
|
||||
falloff = self.getModifiedItemAttr(attr)
|
||||
if falloff:
|
||||
return falloff
|
||||
|
||||
@validates("ID", "itemID", "chargeID", "amount", "amountActive")
|
||||
@@ -302,7 +316,8 @@ class Drone(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut, Mu
|
||||
def clear(self):
|
||||
self.__baseVolley = None
|
||||
self.__baseRRAmount = None
|
||||
self.__miningyield = None
|
||||
self.__miningYield = None
|
||||
self.__miningWaste = None
|
||||
self.itemModifiedAttributes.clear()
|
||||
self.chargeModifiedAttributes.clear()
|
||||
|
||||
@@ -375,8 +390,8 @@ class Drone(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut, Mu
|
||||
def fits(self, fit):
|
||||
fitDroneGroupLimits = set()
|
||||
for i in range(1, 3):
|
||||
groneGrp = fit.ship.getModifiedItemAttr("allowedDroneGroup%d" % i, None)
|
||||
if groneGrp is not None:
|
||||
groneGrp = fit.ship.getModifiedItemAttr("allowedDroneGroup%d" % i)
|
||||
if groneGrp:
|
||||
fitDroneGroupLimits.add(int(groneGrp))
|
||||
if len(fitDroneGroupLimits) == 0:
|
||||
return True
|
||||
|
||||
@@ -21,7 +21,7 @@ import datetime
|
||||
import time
|
||||
from copy import deepcopy
|
||||
from itertools import chain
|
||||
from math import floor, log, sqrt
|
||||
from math import ceil, log, sqrt
|
||||
|
||||
from logbook import Logger
|
||||
from sqlalchemy.orm import reconstructor, validates
|
||||
@@ -139,9 +139,11 @@ class Fit:
|
||||
self.__weaponVolleyMap = {}
|
||||
self.__remoteRepMap = {}
|
||||
self.__minerYield = None
|
||||
self.__droneYield = None
|
||||
self.__minerWaste = None
|
||||
self.__droneWaste = None
|
||||
self.__droneDps = None
|
||||
self.__droneVolley = None
|
||||
self.__droneYield = None
|
||||
self.__sustainableTank = None
|
||||
self.__effectiveSustainableTank = None
|
||||
self.__effectiveTank = None
|
||||
@@ -365,26 +367,44 @@ class Fit:
|
||||
@property
|
||||
def minerYield(self):
|
||||
if self.__minerYield is None:
|
||||
self.calculateMiningStats()
|
||||
self.calculatemining()
|
||||
|
||||
return self.__minerYield
|
||||
|
||||
@property
|
||||
def minerWaste(self):
|
||||
if self.__minerWaste is None:
|
||||
self.calculatemining()
|
||||
|
||||
return self.__minerWaste
|
||||
|
||||
@property
|
||||
def droneYield(self):
|
||||
if self.__droneYield is None:
|
||||
self.calculateMiningStats()
|
||||
self.calculatemining()
|
||||
|
||||
return self.__droneYield
|
||||
|
||||
@property
|
||||
def droneWaste(self):
|
||||
if self.__droneWaste is None:
|
||||
self.calculatemining()
|
||||
|
||||
return self.__droneWaste
|
||||
|
||||
@property
|
||||
def totalYield(self):
|
||||
return self.droneYield + self.minerYield
|
||||
|
||||
@property
|
||||
def totalWaste(self):
|
||||
return self.droneWaste + self.minerWaste
|
||||
|
||||
@property
|
||||
def maxTargets(self):
|
||||
maxTargets = min(self.extraAttributes["maxTargetsLockedFromSkills"],
|
||||
self.ship.getModifiedItemAttr("maxLockedTargets"))
|
||||
return floor(floatUnerr(maxTargets))
|
||||
return ceil(floatUnerr(maxTargets))
|
||||
|
||||
@property
|
||||
def maxTargetRange(self):
|
||||
@@ -491,11 +511,13 @@ class Fit:
|
||||
self.__weaponVolleyMap = {}
|
||||
self.__remoteRepMap = {}
|
||||
self.__minerYield = None
|
||||
self.__droneYield = None
|
||||
self.__minerWaste = None
|
||||
self.__droneWaste = None
|
||||
self.__effectiveSustainableTank = None
|
||||
self.__sustainableTank = None
|
||||
self.__droneDps = None
|
||||
self.__droneVolley = None
|
||||
self.__droneYield = None
|
||||
self.__ehp = None
|
||||
self.__calculated = False
|
||||
self.__capStable = None
|
||||
@@ -1627,18 +1649,23 @@ class Fit:
|
||||
else:
|
||||
return self.ship.getModifiedItemAttr("scanSpeed") / 1000.0
|
||||
|
||||
def calculateMiningStats(self):
|
||||
def calculatemining(self):
|
||||
minerYield = 0
|
||||
minerWaste = 0
|
||||
droneYield = 0
|
||||
droneWaste = 0
|
||||
|
||||
for mod in self.modules:
|
||||
minerYield += mod.miningStats
|
||||
|
||||
minerYield += mod.getMiningYPS()
|
||||
minerWaste += mod.getMiningWPS()
|
||||
for drone in self.drones:
|
||||
droneYield += drone.miningStats
|
||||
droneYield += drone.getMiningYPS()
|
||||
droneWaste += drone.getMiningWPS()
|
||||
|
||||
self.__minerYield = minerYield
|
||||
self.__minerWaste = minerWaste
|
||||
self.__droneYield = droneYield
|
||||
self.__droneWaste = droneWaste
|
||||
|
||||
def calculateWeaponDmgStats(self, spoolOptions):
|
||||
weaponVolley = DmgTypes(0, 0, 0, 0)
|
||||
|
||||
@@ -124,7 +124,8 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut, M
|
||||
|
||||
self.__baseVolley = None
|
||||
self.__baseRRAmount = None
|
||||
self.__miningyield = None
|
||||
self.__miningYield = None
|
||||
self.__miningWaste = None
|
||||
self.__reloadTime = None
|
||||
self.__reloadForce = None
|
||||
self.__chargeCycles = None
|
||||
@@ -306,10 +307,10 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut, M
|
||||
"shipScanRange", "surveyScanRange")
|
||||
maxRange = None
|
||||
for attr in attrs:
|
||||
maxRange = self.getModifiedItemAttr(attr, None)
|
||||
if maxRange is not None:
|
||||
maxRange = self.getModifiedItemAttr(attr)
|
||||
if maxRange:
|
||||
break
|
||||
if maxRange is not None:
|
||||
if maxRange:
|
||||
if 'burst projector' in self.item.name.lower():
|
||||
maxRange -= self.owner.ship.getModifiedItemAttr("radius")
|
||||
return maxRange
|
||||
@@ -371,8 +372,8 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut, M
|
||||
def falloff(self):
|
||||
attrs = ("falloffEffectiveness", "falloff", "shipScanFalloff")
|
||||
for attr in attrs:
|
||||
falloff = self.getModifiedItemAttr(attr, None)
|
||||
if falloff is not None:
|
||||
falloff = self.getModifiedItemAttr(attr)
|
||||
if falloff:
|
||||
return falloff
|
||||
|
||||
@property
|
||||
@@ -409,28 +410,39 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut, M
|
||||
|
||||
self.__itemModifiedAttributes.clear()
|
||||
|
||||
@property
|
||||
def miningStats(self):
|
||||
if self.__miningyield is None:
|
||||
if self.isEmpty:
|
||||
self.__miningyield = 0
|
||||
else:
|
||||
if self.state >= FittingModuleState.ACTIVE:
|
||||
volley = self.getModifiedItemAttr("specialtyMiningAmount") or self.getModifiedItemAttr(
|
||||
"miningAmount") or 0
|
||||
if volley:
|
||||
cycleParams = self.getCycleParameters()
|
||||
if cycleParams is None:
|
||||
self.__miningyield = 0
|
||||
else:
|
||||
cycleTime = cycleParams.averageTime
|
||||
self.__miningyield = volley / (cycleTime / 1000.0)
|
||||
else:
|
||||
self.__miningyield = 0
|
||||
else:
|
||||
self.__miningyield = 0
|
||||
def getMiningYPS(self, ignoreState=False):
|
||||
if self.isEmpty:
|
||||
return 0
|
||||
if not ignoreState and self.state < FittingModuleState.ACTIVE:
|
||||
return 0
|
||||
if self.__miningYield is None:
|
||||
self.__miningYield, self.__miningWaste = self.__calculateMining()
|
||||
return self.__miningYield
|
||||
|
||||
return self.__miningyield
|
||||
def getMiningWPS(self, ignoreState=False):
|
||||
if self.isEmpty:
|
||||
return 0
|
||||
if not ignoreState and self.state < FittingModuleState.ACTIVE:
|
||||
return 0
|
||||
if self.__miningWaste is None:
|
||||
self.__miningYield, self.__miningWaste = self.__calculateMining()
|
||||
return self.__miningWaste
|
||||
|
||||
def __calculateMining(self):
|
||||
yield_ = self.getModifiedItemAttr("miningAmount")
|
||||
if yield_:
|
||||
cycleParams = self.getCycleParameters()
|
||||
if cycleParams is None:
|
||||
yps = 0
|
||||
else:
|
||||
cycleTime = cycleParams.averageTime
|
||||
yps = yield_ / (cycleTime / 1000.0)
|
||||
else:
|
||||
yps = 0
|
||||
wasteChance = self.getModifiedItemAttr("miningWasteProbability")
|
||||
wasteMult = self.getModifiedItemAttr("miningWastedVolumeMultiplier")
|
||||
wps = yps * max(0, min(1, wasteChance / 100)) * wasteMult
|
||||
return yps, wps
|
||||
|
||||
def isDealingDamage(self, ignoreState=False):
|
||||
volleyParams = self.getVolleyParameters(ignoreState=ignoreState)
|
||||
@@ -642,6 +654,8 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut, M
|
||||
"""
|
||||
|
||||
slot = self.slot
|
||||
if slot is None:
|
||||
return False
|
||||
if fit.getSlotsFree(slot) <= (0 if self.owner != fit else -1):
|
||||
return False
|
||||
|
||||
@@ -680,8 +694,8 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut, M
|
||||
return False
|
||||
|
||||
# Check max group fitted
|
||||
max = self.getModifiedItemAttr("maxGroupFitted", None)
|
||||
if max is not None:
|
||||
max = self.getModifiedItemAttr("maxGroupFitted")
|
||||
if max:
|
||||
current = 0 # if self.owner != fit else -1 # Disabled, see #1278
|
||||
for mod in fit.modules:
|
||||
if (mod.item and mod.item.groupID == self.item.groupID and
|
||||
@@ -734,7 +748,7 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut, M
|
||||
# Check if the local module is over it's max limit; if it's not, we're fine
|
||||
maxGroupOnline = self.getModifiedItemAttr("maxGroupOnline", None)
|
||||
maxGroupActive = self.getModifiedItemAttr("maxGroupActive", None)
|
||||
if maxGroupOnline is None and maxGroupActive is None and projectedOnto is None:
|
||||
if not maxGroupOnline and not maxGroupActive and projectedOnto is None:
|
||||
return True
|
||||
|
||||
# Following is applicable only to local modules, we do not want to limit projected
|
||||
@@ -750,11 +764,11 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut, M
|
||||
currOnline += 1
|
||||
if mod.state >= FittingModuleState.ACTIVE:
|
||||
currActive += 1
|
||||
if maxGroupOnline is not None and currOnline > maxGroupOnline:
|
||||
if maxGroupOnline and currOnline > maxGroupOnline:
|
||||
if maxState is None or maxState > FittingModuleState.OFFLINE:
|
||||
maxState = FittingModuleState.OFFLINE
|
||||
break
|
||||
if maxGroupActive is not None and currActive > maxGroupActive:
|
||||
if maxGroupActive and currActive > maxGroupActive:
|
||||
if maxState is None or maxState > FittingModuleState.ONLINE:
|
||||
maxState = FittingModuleState.ONLINE
|
||||
return True if maxState is None else maxState
|
||||
@@ -792,7 +806,7 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut, M
|
||||
chargeGroup = charge.groupID
|
||||
for i in range(5):
|
||||
itemChargeGroup = self.getModifiedItemAttr('chargeGroup' + str(i), None)
|
||||
if itemChargeGroup is None:
|
||||
if not itemChargeGroup:
|
||||
continue
|
||||
if itemChargeGroup == chargeGroup:
|
||||
return True
|
||||
@@ -803,7 +817,7 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut, M
|
||||
validCharges = set()
|
||||
for i in range(5):
|
||||
itemChargeGroup = self.getModifiedItemAttr('chargeGroup' + str(i), None)
|
||||
if itemChargeGroup is not None:
|
||||
if itemChargeGroup:
|
||||
g = eos.db.getGroup(int(itemChargeGroup), eager="items.attributes")
|
||||
if g is None:
|
||||
continue
|
||||
@@ -865,7 +879,8 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut, M
|
||||
def clear(self):
|
||||
self.__baseVolley = None
|
||||
self.__baseRRAmount = None
|
||||
self.__miningyield = None
|
||||
self.__miningYield = None
|
||||
self.__miningWaste = None
|
||||
self.__reloadTime = None
|
||||
self.__reloadForce = None
|
||||
self.__chargeCycles = None
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# noinspection PyPackageRequirements
|
||||
from collections import OrderedDict
|
||||
|
||||
# noinspection PyPackageRequirements
|
||||
import wx
|
||||
|
||||
import gui.fitCommands as cmd
|
||||
@@ -25,8 +26,20 @@ class ChangeModuleAmmo(ContextMenuCombined):
|
||||
'thermal': _t('Thermal'),
|
||||
'explosive': _t('Explosive'),
|
||||
'kinetic': _t('Kinetic'),
|
||||
'mixed': _t('Mixed')
|
||||
}
|
||||
'mixed': _t('Mixed')}
|
||||
self.oreChargeCatTrans = OrderedDict([
|
||||
('a1', _t('Asteroid Simple')),
|
||||
('a2', _t('Asteroid Coherent')),
|
||||
('a3', _t('Asteroid Variegated')),
|
||||
('a4', _t('Asteroid Complex')),
|
||||
('a5', _t('Asteroid Abyssal')),
|
||||
('a6', _t('Asteroid Mercoxit')),
|
||||
('r4', _t('Moon Ubiquitous')),
|
||||
('r8', _t('Moon Common')),
|
||||
('r16', _t('Moon Uncommon')),
|
||||
('r32', _t('Moon Rare')),
|
||||
('r64', _t('Moon Exceptional')),
|
||||
('misc', _t('Misc'))])
|
||||
|
||||
def display(self, callingWindow, srcContext, mainItem, selection):
|
||||
if srcContext not in ('fittingModule', 'projectedModule'):
|
||||
@@ -115,6 +128,24 @@ class ChangeModuleAmmo(ContextMenuCombined):
|
||||
self._addSeparator(subMenu, _t('More Damage'))
|
||||
for menuItem in menuItems:
|
||||
menu.Append(menuItem)
|
||||
elif modType == 'miner':
|
||||
menuItems = []
|
||||
for catHandle, catLabel in self.oreChargeCatTrans.items():
|
||||
charges = chargeDict.get(catHandle)
|
||||
if not charges:
|
||||
continue
|
||||
if len(charges) == 1:
|
||||
menuItems.append(self._addCharge(rootMenu if msw else menu, charges[0]))
|
||||
else:
|
||||
menuItem = wx.MenuItem(menu, wx.ID_ANY, catLabel)
|
||||
menuItems.append(menuItem)
|
||||
subMenu = wx.Menu()
|
||||
subMenu.Bind(wx.EVT_MENU, self.handleAmmoSwitch)
|
||||
menuItem.SetSubMenu(subMenu)
|
||||
for charge in charges:
|
||||
subMenu.Append(self._addCharge(rootMenu if msw else subMenu, charge))
|
||||
for menuItem in menuItems:
|
||||
menu.Append(menuItem)
|
||||
elif modType == 'general':
|
||||
for charge in chargeDict['general']:
|
||||
menu.Append(self._addCharge(rootMenu if msw else menu, charge))
|
||||
|
||||
@@ -59,7 +59,8 @@ AttrGroupDict = {
|
||||
"agility",
|
||||
"droneCapacity",
|
||||
"droneBandwidth",
|
||||
"specialOreHoldCapacity",
|
||||
"generalMiningHoldCapacity",
|
||||
"specialIceHoldCapacity",
|
||||
"specialGasHoldCapacity",
|
||||
"specialMineralHoldCapacity",
|
||||
"specialSalvageHoldCapacity",
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
import csv
|
||||
import config
|
||||
from enum import IntEnum
|
||||
|
||||
# noinspection PyPackageRequirements
|
||||
import wx
|
||||
import wx.lib.agw.hypertreelist
|
||||
|
||||
import config
|
||||
import gui
|
||||
from gui import globalEvents as GE
|
||||
from gui.bitmap_loader import BitmapLoader
|
||||
from gui.utils.numberFormatter import formatAmount, roundDec
|
||||
from enum import IntEnum
|
||||
from gui.builtinItemStatsViews.attributeGrouping import *
|
||||
from gui.utils.numberFormatter import formatAmount, roundDec
|
||||
from service.const import GuiAttrGroup
|
||||
|
||||
|
||||
_t = wx.GetTranslation
|
||||
|
||||
|
||||
@@ -25,6 +28,8 @@ class ItemParams(wx.Panel):
|
||||
wx.Panel.__init__(self, parent, size=(1000, 1000))
|
||||
self.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNFACE))
|
||||
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
|
||||
mainSizer = wx.BoxSizer(wx.VERTICAL)
|
||||
|
||||
self.paramList = wx.lib.agw.hypertreelist.HyperTreeList(self, wx.ID_ANY,
|
||||
@@ -37,6 +42,8 @@ class ItemParams(wx.Panel):
|
||||
self.toggleView = AttributeView.NORMAL
|
||||
self.stuff = stuff
|
||||
self.item = item
|
||||
self.isStuffItem = stuff is not None and item is not None and getattr(stuff, 'item', None) == item
|
||||
self.isStuffCharge = stuff is not None and item is not None and getattr(stuff, 'charge', None) == item
|
||||
self.attrInfo = {}
|
||||
self.attrValues = {}
|
||||
self._fetchValues()
|
||||
@@ -71,6 +78,10 @@ class ItemParams(wx.Panel):
|
||||
|
||||
self.toggleViewBtn.Bind(wx.EVT_TOGGLEBUTTON, self.ToggleViewMode)
|
||||
self.exportStatsBtn.Bind(wx.EVT_TOGGLEBUTTON, self.ExportItemStats)
|
||||
self.mainFrame.Bind(GE.ITEM_CHANGED_INPLACE, self.OnUpdateStuff)
|
||||
|
||||
def OnWindowClose(self):
|
||||
self.mainFrame.Unbind(GE.ITEM_CHANGED_INPLACE)
|
||||
|
||||
def _fetchValues(self):
|
||||
if self.stuff is None:
|
||||
@@ -78,12 +89,12 @@ class ItemParams(wx.Panel):
|
||||
self.attrValues.clear()
|
||||
self.attrInfo.update(self.item.attributes)
|
||||
self.attrValues.update(self.item.attributes)
|
||||
elif self.stuff.item == self.item:
|
||||
elif self.isStuffItem:
|
||||
self.attrInfo.clear()
|
||||
self.attrValues.clear()
|
||||
self.attrInfo.update(self.stuff.item.attributes)
|
||||
self.attrValues.update(self.stuff.itemModifiedAttributes)
|
||||
elif self.stuff.charge == self.item:
|
||||
elif self.isStuffCharge:
|
||||
self.attrInfo.clear()
|
||||
self.attrValues.clear()
|
||||
self.attrInfo.update(self.stuff.charge.attributes)
|
||||
@@ -171,6 +182,10 @@ class ItemParams(wx.Panel):
|
||||
]
|
||||
)
|
||||
|
||||
def OnUpdateStuff(self, event):
|
||||
if self.stuff is event.old:
|
||||
self.stuff = event.new
|
||||
|
||||
def SetupImageList(self):
|
||||
self.imageList.RemoveAll()
|
||||
|
||||
@@ -282,9 +297,9 @@ class ItemParams(wx.Panel):
|
||||
valDefault = getattr(info, "value", None) # Get default value from attribute
|
||||
if self.stuff is not None:
|
||||
# if it's a stuff, overwrite default (with fallback to current value)
|
||||
if self.stuff.item == self.item:
|
||||
if self.isStuffItem:
|
||||
valDefault = self.stuff.getItemBaseAttrValue(attr, valDefault)
|
||||
elif self.stuff.charge == self.item:
|
||||
elif self.isStuffCharge:
|
||||
valDefault = self.stuff.getChargeBaseAttrValue(attr, valDefault)
|
||||
|
||||
valueDefault = valDefault if valDefault is not None else att
|
||||
@@ -357,3 +372,4 @@ class ItemParams(wx.Panel):
|
||||
fvalue = value
|
||||
unitSuffix = f' {unit}' if unit is not None else ''
|
||||
return f'{fvalue}{unitSuffix}'
|
||||
|
||||
|
||||
@@ -130,21 +130,33 @@ class MiningYieldViewFull(StatsView):
|
||||
def refreshPanel(self, fit):
|
||||
# If we did anything intresting, we'd update our labels to reflect the new fit's stats here
|
||||
|
||||
stats = (("labelFullminingyieldMiner", lambda: fit.minerYield, 3, 0, 0, "%s m\u00B3/s", None),
|
||||
("labelFullminingyieldDrone", lambda: fit.droneYield, 3, 0, 0, "%s m\u00B3/s", None),
|
||||
("labelFullminingyieldTotal", lambda: fit.totalYield, 3, 0, 0, "%s m\u00B3/s", None))
|
||||
stats = (("labelFullminingyieldMiner", lambda: fit.minerYield, lambda: fit.minerWaste, 3, 0, 0, "{}{} m\u00B3/s", None),
|
||||
("labelFullminingyieldDrone", lambda: fit.droneYield, lambda: fit.droneWaste, 3, 0, 0, "{}{} m\u00B3/s", None),
|
||||
("labelFullminingyieldTotal", lambda: fit.totalYield, lambda: fit.totalWaste, 3, 0, 0, "{}{} m\u00B3/s", None))
|
||||
|
||||
counter = 0
|
||||
for labelName, value, prec, lowest, highest, valueFormat, altFormat in stats:
|
||||
label = getattr(self, labelName)
|
||||
def processValue(value):
|
||||
value = value() if fit is not None else 0
|
||||
value = value if value is not None else 0
|
||||
if self._cachedValues[counter] != value:
|
||||
valueStr = formatAmount(value, prec, lowest, highest)
|
||||
label.SetLabel(valueFormat % valueStr)
|
||||
tipStr = "Mining Yield per second ({0} per hour)".format(formatAmount(value * 3600, 3, 0, 3))
|
||||
label.SetToolTip(wx.ToolTip(tipStr))
|
||||
self._cachedValues[counter] = value
|
||||
return value
|
||||
|
||||
counter = 0
|
||||
for labelName, yieldValue, wasteValue, prec, lowest, highest, valueFormat, altFormat in stats:
|
||||
label = getattr(self, labelName)
|
||||
yieldValue = processValue(yieldValue)
|
||||
wasteValue = processValue(wasteValue)
|
||||
if self._cachedValues[counter] != (yieldValue, wasteValue):
|
||||
yps = formatAmount(yieldValue, prec, lowest, highest)
|
||||
yph = formatAmount(yieldValue * 3600, prec, lowest, highest)
|
||||
wps = formatAmount(wasteValue, prec, lowest, highest)
|
||||
wph = formatAmount(wasteValue * 3600, prec, lowest, highest)
|
||||
wasteSuffix = '\u02b7' if wasteValue > 0 else ''
|
||||
label.SetLabel(valueFormat.format(yps, wasteSuffix))
|
||||
tipLines = []
|
||||
tipLines.append("{} m\u00B3 mining yield per second ({} m\u00B3 per hour)".format(yps, yph))
|
||||
if wasteValue > 0:
|
||||
tipLines.append("{} m\u00B3 mining waste per second ({} m\u00B3 per hour)".format(wps, wph))
|
||||
label.SetToolTip(wx.ToolTip('\n'.join(tipLines)))
|
||||
self._cachedValues[counter] = (yieldValue, wasteValue)
|
||||
counter += 1
|
||||
self.panel.Layout()
|
||||
self.headerPanel.Layout()
|
||||
|
||||
@@ -119,10 +119,11 @@ class TargetingMiscViewMinimal(StatsView):
|
||||
("specialMediumShipHoldCapacity", _t("Medium ship hold")),
|
||||
("specialLargeShipHoldCapacity", _t("Large ship hold")),
|
||||
("specialIndustrialShipHoldCapacity", _t("Industrial ship hold")),
|
||||
("specialOreHoldCapacity", _t("Ore hold")),
|
||||
("generalMiningHoldCapacity", _t("Mining hold")),
|
||||
("specialIceHoldCapacity", _t("Ice hold")),
|
||||
("specialGasHoldCapacity", _t("Gas hold")),
|
||||
("specialMineralHoldCapacity", _t("Mineral hold")),
|
||||
("specialMaterialBayCapacity", _t("Material bay")),
|
||||
("specialGasHoldCapacity", _t("Gas hold")),
|
||||
("specialSalvageHoldCapacity", _t("Salvage hold")),
|
||||
("specialCommandCenterHoldCapacity", _t("Command center hold")),
|
||||
("specialPlanetaryCommoditiesHoldCapacity", _t("Planetary goods hold")),
|
||||
@@ -139,10 +140,11 @@ class TargetingMiscViewMinimal(StatsView):
|
||||
"specialMediumShipHoldCapacity": lambda: fit.ship.getModifiedItemAttr("specialMediumShipHoldCapacity"),
|
||||
"specialLargeShipHoldCapacity": lambda: fit.ship.getModifiedItemAttr("specialLargeShipHoldCapacity"),
|
||||
"specialIndustrialShipHoldCapacity": lambda: fit.ship.getModifiedItemAttr("specialIndustrialShipHoldCapacity"),
|
||||
"specialOreHoldCapacity": lambda: fit.ship.getModifiedItemAttr("specialOreHoldCapacity"),
|
||||
"generalMiningHoldCapacity": lambda: fit.ship.getModifiedItemAttr("generalMiningHoldCapacity"),
|
||||
"specialIceHoldCapacity": lambda: fit.ship.getModifiedItemAttr("specialIceHoldCapacity"),
|
||||
"specialGasHoldCapacity": lambda: fit.ship.getModifiedItemAttr("specialGasHoldCapacity"),
|
||||
"specialMineralHoldCapacity": lambda: fit.ship.getModifiedItemAttr("specialMineralHoldCapacity"),
|
||||
"specialMaterialBayCapacity": lambda: fit.ship.getModifiedItemAttr("specialMaterialBayCapacity"),
|
||||
"specialGasHoldCapacity": lambda: fit.ship.getModifiedItemAttr("specialGasHoldCapacity"),
|
||||
"specialSalvageHoldCapacity": lambda: fit.ship.getModifiedItemAttr("specialSalvageHoldCapacity"),
|
||||
"specialCommandCenterHoldCapacity": lambda: fit.ship.getModifiedItemAttr("specialCommandCenterHoldCapacity"),
|
||||
"specialPlanetaryCommoditiesHoldCapacity": lambda: fit.ship.getModifiedItemAttr("specialPlanetaryCommoditiesHoldCapacity"),
|
||||
|
||||
@@ -80,7 +80,7 @@ class AttributeDisplay(ViewColumn):
|
||||
else:
|
||||
attr = mod.getAttribute(self.info.name)
|
||||
|
||||
if attr is None:
|
||||
if not attr:
|
||||
return ""
|
||||
|
||||
if self.info.name == "volume":
|
||||
|
||||
@@ -537,14 +537,24 @@ class Miscellanea(ViewColumn):
|
||||
text = "{0}m".format(formatAmount(optimalSig, 3, 0, 3))
|
||||
tooltip = "Optimal signature radius"
|
||||
return text, tooltip
|
||||
elif itemGroup in ("Frequency Mining Laser", "Strip Miner", "Mining Laser", "Gas Cloud Harvester", "Mining Drone"):
|
||||
miningAmount = stuff.getModifiedItemAttr("specialtyMiningAmount") or stuff.getModifiedItemAttr("miningAmount")
|
||||
cycleTime = getattr(stuff, 'cycleTime', stuff.getModifiedItemAttr("duration"))
|
||||
if not miningAmount or not cycleTime:
|
||||
elif itemGroup in ("Frequency Mining Laser", "Strip Miner", "Mining Laser", "Gas Cloud Scoops", "Mining Drone", "Gas Cloud Harvesters"):
|
||||
yps = stuff.getMiningYPS(ignoreState=True)
|
||||
if not yps:
|
||||
return "", None
|
||||
minePerSec = (float(miningAmount) * 1000 / cycleTime)
|
||||
text = "{0} m3/s".format(formatAmount(minePerSec, 3, 0, 3))
|
||||
tooltip = "Mining Yield per second ({0} per hour)".format(formatAmount(minePerSec * 3600, 3, 0, 3))
|
||||
yph = yps * 3600
|
||||
wps = stuff.getMiningWPS(ignoreState=True)
|
||||
wph = wps * 3600
|
||||
textParts = []
|
||||
textParts.append(formatAmount(yps, 3, 0, 3))
|
||||
tipLines = []
|
||||
tipLines.append("{} m\u00B3 mining yield per second ({} m\u00B3 per hour)".format(
|
||||
formatAmount(yps, 3, 0, 3), formatAmount(yph, 3, 0, 3)))
|
||||
if wps > 0:
|
||||
textParts.append(formatAmount(wps, 3, 0, 3))
|
||||
tipLines.append("{} m\u00B3 mining waste per second ({} m\u00B3 per hour)".format(
|
||||
formatAmount(wps, 3, 0, 3), formatAmount(wph, 3, 0, 3)))
|
||||
text = '{} m\u00B3/s'.format('+'.join(textParts))
|
||||
tooltip = '\n'.join(tipLines)
|
||||
return text, tooltip
|
||||
elif itemGroup == "Logistic Drone":
|
||||
rpsData = stuff.getRemoteReps(ignoreState=True)
|
||||
@@ -679,7 +689,7 @@ class Miscellanea(ViewColumn):
|
||||
formatAmount(itemArmorResistanceShiftHardenerKin, 3, 0, 3),
|
||||
formatAmount(itemArmorResistanceShiftHardenerExp, 3, 0, 3),
|
||||
)
|
||||
tooltip = "Resistances Shifted to Damage Profile:\n{0}% EM | {1}% Therm | {2}% Kin | {3}% Exp".format(
|
||||
tooltip = "Resistances shifted to damage profile:\n{0}% EM | {1}% Therm | {2}% Kin | {3}% Exp".format(
|
||||
formatAmount(itemArmorResistanceShiftHardenerEM, 3, 0, 3),
|
||||
formatAmount(itemArmorResistanceShiftHardenerTherm, 3, 0, 3),
|
||||
formatAmount(itemArmorResistanceShiftHardenerKin, 3, 0, 3),
|
||||
@@ -693,96 +703,80 @@ class Miscellanea(ViewColumn):
|
||||
text = "{}s".format(formatAmount(duration / 1000, 3, 0, 0))
|
||||
tooltip = "Scan duration"
|
||||
return text, tooltip
|
||||
|
||||
elif itemGroup == "Command Burst":
|
||||
|
||||
# Text and tooltip are empty if there is no charge.
|
||||
text = ""
|
||||
tooltip = ""
|
||||
|
||||
|
||||
buff_value = stuff.getModifiedItemAttr('warfareBuff1Value')
|
||||
buff_id = stuff.getModifiedChargeAttr('warfareBuff1ID')
|
||||
if buff_id == 10: # Shield Burst: Shield Harmonizing: Shield Resistance
|
||||
# minus buff value because ingame shows positive value
|
||||
text = f"{-buff_value:.1f}%"
|
||||
tooltip = "Shield Resistance Bonus"
|
||||
|
||||
elif buff_id == 11: # Shield Burst: Active Shielding: Repair Duration/Capacitor
|
||||
text = f"{buff_value:+.1f}%"
|
||||
tooltip = "Shield Repair Modules: Duration & Capacictor-use bonus"
|
||||
|
||||
elif buff_id == 12: # Shield Burst: Shield Extension: Shield HP
|
||||
text = f"{buff_value:.1f}%"
|
||||
tooltip = "Shield HP Bonus"
|
||||
|
||||
elif buff_id == 13: # Armor Burst: Armor Energizing: Armor Resistance
|
||||
# minus buff value because ingame shows positive value
|
||||
text = f"{-buff_value:.1f}%"
|
||||
tooltip = "Armor Resistance Bonus"
|
||||
|
||||
elif buff_id == 14: # Armor Burst: Rapid Repair: Repair Duration/Capacitor
|
||||
text = f"{buff_value:+.1f}%"
|
||||
tooltip = "Armor Repair Modules: Duration & Capacitor-use bonus"
|
||||
|
||||
elif buff_id == 15: # Armor Burst: Armor Reinforcement: Armor HP
|
||||
text = f"{buff_value:.1f}%"
|
||||
tooltip = "Armor HP Bonus"
|
||||
|
||||
elif buff_id == 16: # Information Burst: Sensor Optimization: Scan Resolution
|
||||
text = f"{buff_value:.1f}%"
|
||||
tooltip = "Scan Resolution bonus"
|
||||
|
||||
elif buff_id == 26: # Information Burst: Sensor Optimization: Targeting Range
|
||||
text += f" | {buff_value:.1f}%"
|
||||
tooltip += " | Targeting Range bonus"
|
||||
|
||||
elif buff_id == 17: # Information Burst: Electronic Superiority: EWAR Range and Strength
|
||||
text = f"{buff_value:.1f}%"
|
||||
tooltip = "Electronic Warfare modules: Range and Strength bonus"
|
||||
|
||||
elif buff_id == 18: # Information Burst: Electronic Hardening: Sensor Strength
|
||||
text = f"{buff_value:.1f}%"
|
||||
tooltip = "Sensor Strength bonus"
|
||||
|
||||
buff2_value = stuff.getModifiedItemAttr('warfareBuff2Value')
|
||||
|
||||
# Information Burst: Electronic Hardening: RSD/RWD Resistance
|
||||
text += f" | {buff2_value:+.1f}%"
|
||||
tooltip += " | Remote Sensor Dampener / Remote Weapon Disruption Resistance bonus"
|
||||
|
||||
elif buff_id == 20: # Skirmish Burst: Evasive Maneuvers: Signature Radius
|
||||
text = f"{buff_value:+.1f}%"
|
||||
tooltip = "Signature Radius bonus"
|
||||
|
||||
buff2_value = stuff.getModifiedItemAttr('warfareBuff2Value')
|
||||
# Skirmish Burst: Evasive Maneuvers: Agility
|
||||
# minus the buff value because we want Agility as shown ingame, not inertia modifier
|
||||
text += f" | {-buff2_value:.1f}%"
|
||||
tooltip += " | Agility bonus"
|
||||
|
||||
elif buff_id == 21: # Skirmish Burst: Interdiction Maneuvers: Tackle Range
|
||||
text = f"{buff_value:.1f}%"
|
||||
tooltip = "Propulsion disruption module range bonus"
|
||||
|
||||
elif buff_id == 22: # Skirmish Burst: Rapid Deployment: AB/MWD Speed Increase
|
||||
text = f"{buff_value:.1f}%"
|
||||
tooltip = "AB/MWD module speed increase"
|
||||
|
||||
elif buff_id == 23: # Mining Burst: Mining Laser Field Enhancement: Mining/Survey Range
|
||||
text = f"{buff_value:.1f}%"
|
||||
tooltip = "Mining/Survey module range bonus"
|
||||
|
||||
elif buff_id == 24: # Mining Burst: Mining Laser Optimization: Mining Capacitor/Duration
|
||||
text = f"{buff_value:+.1f}%"
|
||||
tooltip = "Mining Modules: Duration & Capacitor-use bonus"
|
||||
|
||||
elif buff_id == 25: # Mining Burst: Mining Equipment Preservation: Crystal Volatility
|
||||
text = f"{buff_value:+.1f}%"
|
||||
tooltip = "Mining crystal volatility bonus"
|
||||
|
||||
textSections = []
|
||||
tooltipSections = []
|
||||
buffMap = {}
|
||||
for seq in (1, 2, 3, 4):
|
||||
buffId = stuff.getModifiedChargeAttr(f'warfareBuff{seq}ID')
|
||||
if not buffId:
|
||||
continue
|
||||
buffValue = stuff.getModifiedItemAttr(f'warfareBuff{seq}Value')
|
||||
buffMap[buffId] = buffValue
|
||||
if buffId == 10: # Shield Burst: Shield Harmonizing: Shield Resistance
|
||||
# minus buff value because ingame shows positive value
|
||||
textSections.append(f"{formatAmount(-buffValue, 3, 0, 3, forceSign=True)}%")
|
||||
tooltipSections.append("shield resistance")
|
||||
elif buffId == 11: # Shield Burst: Active Shielding: Repair Duration/Capacitor
|
||||
textSections.append(f"{formatAmount(buffValue, 3, 0, 3, forceSign=True)}%")
|
||||
tooltipSections.append("shield RR duration & capacictor use")
|
||||
elif buffId == 12: # Shield Burst: Shield Extension: Shield HP
|
||||
textSections.append(f"{formatAmount(buffValue, 3, 0, 3, forceSign=True)}%")
|
||||
tooltipSections.append("shield HP")
|
||||
elif buffId == 13: # Armor Burst: Armor Energizing: Armor Resistance
|
||||
# minus buff value because ingame shows positive value
|
||||
textSections.append(f"{formatAmount(-buffValue, 3, 0, 3, forceSign=True)}%")
|
||||
tooltipSections.append("armor resistance")
|
||||
elif buffId == 14: # Armor Burst: Rapid Repair: Repair Duration/Capacitor
|
||||
textSections.append(f"{formatAmount(buffValue, 3, 0, 3, forceSign=True)}%")
|
||||
tooltipSections.append("armor RR duration & capacitor use")
|
||||
elif buffId == 15: # Armor Burst: Armor Reinforcement: Armor HP
|
||||
textSections.append(f"{formatAmount(buffValue, 3, 0, 3, forceSign=True)}%")
|
||||
tooltipSections.append("armor HP")
|
||||
elif buffId == 16: # Information Burst: Sensor Optimization: Scan Resolution
|
||||
textSections.append(f"{formatAmount(buffValue, 3, 0, 3, forceSign=True)}%")
|
||||
tooltipSections.append("scan resolution")
|
||||
elif buffId == 26: # Information Burst: Sensor Optimization: Targeting Range
|
||||
textSections.append(f"{formatAmount(buffValue, 3, 0, 3, forceSign=True)}%")
|
||||
tooltipSections.append("targeting range")
|
||||
elif buffId == 17: # Information Burst: Electronic Superiority: EWAR Range and Strength
|
||||
textSections.append(f"{formatAmount(buffValue, 3, 0, 3, forceSign=True)}%")
|
||||
tooltipSections.append("electronic warfare modules range & strength")
|
||||
elif buffId == 18: # Information Burst: Electronic Hardening: Sensor Strength
|
||||
textSections.append(f"{formatAmount(buffValue, 3, 0, 3, forceSign=True)}%")
|
||||
tooltipSections.append("sensor strength")
|
||||
elif buffId == 19: # Information Burst: Electronic Hardening: RSD/RWD Resistance
|
||||
textSections.append(f"{formatAmount(-buffValue, 3, 0, 3, forceSign=True)}%")
|
||||
tooltipSections.append("sensor dampener & weapon disruption resistance")
|
||||
elif buffId == 20: # Skirmish Burst: Evasive Maneuvers: Signature Radius
|
||||
textSections.append(f"{formatAmount(buffValue, 3, 0, 3, forceSign=True)}%")
|
||||
tooltipSections.append("signature radius")
|
||||
elif buffId == 60: # Skirmish Burst: Evasive Maneuvers: Agility
|
||||
# minus the buff value because we want Agility as shown ingame, not inertia modifier
|
||||
textSections.append(f"{formatAmount(-buffValue, 3, 0, 3, forceSign=True)}%")
|
||||
tooltipSections.append("agility")
|
||||
elif buffId == 21: # Skirmish Burst: Interdiction Maneuvers: Tackle Range
|
||||
textSections.append(f"{formatAmount(buffValue, 3, 0, 3, forceSign=True)}%")
|
||||
tooltipSections.append("warp disruption & stasis web range")
|
||||
elif buffId == 22: # Skirmish Burst: Rapid Deployment: AB/MWD Speed Increase
|
||||
textSections.append(f"{formatAmount(buffValue, 3, 0, 3, forceSign=True)}%")
|
||||
tooltipSections.append("AB/MWD speed increase")
|
||||
elif buffId == 23: # Mining Burst: Mining Laser Field Enhancement: Mining/Survey Range
|
||||
textSections.append(f"{formatAmount(buffValue, 3, 0, 3, forceSign=True)}%")
|
||||
tooltipSections.append("mining/survey module range")
|
||||
elif buffId == 24: # Mining Burst: Mining Laser Optimization: Mining Capacitor/Duration
|
||||
textSections.append(f"{formatAmount(buffValue, 3, 0, 3, forceSign=True)}%")
|
||||
tooltipSections.append("mining module duration & capacitor use")
|
||||
elif buffId == 25: # Mining Burst: Mining Equipment Preservation: Crystal Volatility
|
||||
textSections.append(f"{formatAmount(buffValue, 3, 0, 3, forceSign=True)}%")
|
||||
tooltipSections.append("mining crystal volatility")
|
||||
if not textSections:
|
||||
return '', None
|
||||
text = ' | '.join(textSections)
|
||||
tooltip = '{} bonus'.format(' | '.join(tooltipSections))
|
||||
if tooltip:
|
||||
tooltip = tooltip[0].capitalize() + tooltip[1:]
|
||||
return text, tooltip
|
||||
|
||||
elif stuff.charge is not None:
|
||||
chargeGroup = stuff.charge.group.name
|
||||
if chargeGroup.endswith("Rocket") or chargeGroup.endswith("Missile") or chargeGroup.endswith("Torpedo"):
|
||||
@@ -794,7 +788,7 @@ class Miscellanea(ViewColumn):
|
||||
formatAmount(aoeVelocity, 3, 0, 3), "m/s")
|
||||
tooltip = "Explosion radius and explosion velocity"
|
||||
return text, tooltip
|
||||
elif chargeGroup in ("Bomb", "Structure Guided Bomb"):
|
||||
elif chargeGroup in ("Bomb", "Guided Bomb"):
|
||||
cloudSize = stuff.getModifiedChargeAttr("aoeCloudSize")
|
||||
if not cloudSize:
|
||||
return "", None
|
||||
|
||||
@@ -71,7 +71,7 @@ class CalcReplaceLocalModuleCommand(wx.Command):
|
||||
# Remove if there was no module
|
||||
if self.oldModInfo is None:
|
||||
from .localRemove import CalcRemoveLocalModulesCommand
|
||||
cmd = CalcRemoveLocalModulesCommand(fitID=self.fitID, positions=[self.position], recalc=False)
|
||||
cmd = CalcRemoveLocalModulesCommand(fitID=self.fitID, positions=[self.position], recalc=self.recalc)
|
||||
if not cmd.Do():
|
||||
return False
|
||||
restoreCheckedStates(fit, self.savedStateCheckChanges)
|
||||
|
||||
@@ -16,6 +16,7 @@ class GuiChangeBoosterMetaCommand(wx.Command):
|
||||
self.fitID = fitID
|
||||
self.position = position
|
||||
self.newItemID = newItemID
|
||||
self.newPosition = None
|
||||
|
||||
def Do(self):
|
||||
sFit = Fit.getInstance()
|
||||
@@ -31,15 +32,24 @@ class GuiChangeBoosterMetaCommand(wx.Command):
|
||||
sFit.recalc(self.fitID)
|
||||
sFit.fill(self.fitID)
|
||||
eos.db.commit()
|
||||
wx.PostEvent(gui.mainFrame.MainFrame.getInstance(), GE.FitChanged(fitIDs=(self.fitID,)))
|
||||
self.newPosition = cmd.newPosition
|
||||
newBooster = fit.boosters[self.newPosition]
|
||||
mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
wx.PostEvent(mainFrame, GE.FitChanged(fitIDs=(self.fitID,)))
|
||||
wx.PostEvent(mainFrame, GE.ItemChangedInplace(old=booster, new=newBooster))
|
||||
return success
|
||||
|
||||
def Undo(self):
|
||||
sFit = Fit.getInstance()
|
||||
fit = sFit.getFit(self.fitID)
|
||||
oldBooster = fit.boosters[self.newPosition]
|
||||
success = self.internalHistory.undoAll()
|
||||
eos.db.flush()
|
||||
sFit = Fit.getInstance()
|
||||
sFit.recalc(self.fitID)
|
||||
sFit.fill(self.fitID)
|
||||
eos.db.commit()
|
||||
wx.PostEvent(gui.mainFrame.MainFrame.getInstance(), GE.FitChanged(fitIDs=(self.fitID,)))
|
||||
newBooster = fit.boosters[self.position]
|
||||
mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
wx.PostEvent(mainFrame, GE.FitChanged(fitIDs=(self.fitID,)))
|
||||
wx.PostEvent(mainFrame, GE.ItemChangedInplace(old=oldBooster, new=newBooster))
|
||||
return success
|
||||
|
||||
@@ -16,6 +16,7 @@ class GuiChangeImplantMetaCommand(wx.Command):
|
||||
self.fitID = fitID
|
||||
self.position = position
|
||||
self.newItemID = newItemID
|
||||
self.newPosition = None
|
||||
|
||||
def Do(self):
|
||||
sFit = Fit.getInstance()
|
||||
@@ -31,15 +32,25 @@ class GuiChangeImplantMetaCommand(wx.Command):
|
||||
sFit.recalc(self.fitID)
|
||||
sFit.fill(self.fitID)
|
||||
eos.db.commit()
|
||||
wx.PostEvent(gui.mainFrame.MainFrame.getInstance(), GE.FitChanged(fitIDs=(self.fitID,)))
|
||||
self.newPosition = cmd.newPosition
|
||||
newImplant = fit.implants[self.newPosition]
|
||||
mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
wx.PostEvent(mainFrame, GE.FitChanged(fitIDs=(self.fitID,)))
|
||||
wx.PostEvent(mainFrame, GE.ItemChangedInplace(old=implant, new=newImplant))
|
||||
return success
|
||||
|
||||
def Undo(self):
|
||||
sFit = Fit.getInstance()
|
||||
fit = sFit.getFit(self.fitID)
|
||||
oldImplant = fit.implants[self.newPosition]
|
||||
success = self.internalHistory.undoAll()
|
||||
eos.db.flush()
|
||||
sFit = Fit.getInstance()
|
||||
sFit.recalc(self.fitID)
|
||||
sFit.fill(self.fitID)
|
||||
eos.db.commit()
|
||||
wx.PostEvent(gui.mainFrame.MainFrame.getInstance(), GE.FitChanged(fitIDs=(self.fitID,)))
|
||||
newImplant = fit.implants[self.position]
|
||||
mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
wx.PostEvent(mainFrame, GE.FitChanged(fitIDs=(self.fitID,)))
|
||||
wx.PostEvent(mainFrame, GE.ItemChangedInplace(old=oldImplant, new=newImplant))
|
||||
return success
|
||||
|
||||
@@ -22,6 +22,7 @@ class GuiChangeLocalModuleMetasCommand(wx.Command):
|
||||
def Do(self):
|
||||
sFit = Fit.getInstance()
|
||||
fit = sFit.getFit(self.fitID)
|
||||
oldModMap = self._getPositionMap(fit)
|
||||
results = []
|
||||
self.replacedItemIDs = set()
|
||||
lastSuccessfulCmd = None
|
||||
@@ -49,6 +50,7 @@ class GuiChangeLocalModuleMetasCommand(wx.Command):
|
||||
sFit.recalc(self.fitID)
|
||||
self.savedRemovedDummies = sFit.fill(self.fitID)
|
||||
eos.db.commit()
|
||||
newModMap = self._getPositionMap(fit)
|
||||
events = []
|
||||
if success and self.replacedItemIDs:
|
||||
events.append(GE.FitChanged(fitIDs=(self.fitID,), action='moddel', typeID=self.replacedItemIDs))
|
||||
@@ -56,6 +58,12 @@ class GuiChangeLocalModuleMetasCommand(wx.Command):
|
||||
events.append(GE.FitChanged(fitIDs=(self.fitID,), action='modadd', typeID=self.newItemID))
|
||||
if not events:
|
||||
events.append(GE.FitChanged(fitIDs=(self.fitID,)))
|
||||
if success:
|
||||
for position in self.positions:
|
||||
oldMod = oldModMap.get(position)
|
||||
newMod = newModMap.get(position)
|
||||
if oldMod is not newMod:
|
||||
events.append(GE.ItemChangedInplace(old=oldMod, new=newMod))
|
||||
for event in events:
|
||||
wx.PostEvent(gui.mainFrame.MainFrame.getInstance(), event)
|
||||
return success
|
||||
@@ -63,12 +71,16 @@ class GuiChangeLocalModuleMetasCommand(wx.Command):
|
||||
def Undo(self):
|
||||
sFit = Fit.getInstance()
|
||||
fit = sFit.getFit(self.fitID)
|
||||
oldModMap = self._getPositionMap(fit)
|
||||
for position in self.positions:
|
||||
oldModMap[position] = fit.modules[position]
|
||||
restoreRemovedDummies(fit, self.savedRemovedDummies)
|
||||
success = self.internalHistory.undoAll()
|
||||
eos.db.flush()
|
||||
sFit.recalc(self.fitID)
|
||||
sFit.fill(self.fitID)
|
||||
eos.db.commit()
|
||||
newModMap = self._getPositionMap(fit)
|
||||
events = []
|
||||
if success:
|
||||
events.append(GE.FitChanged(fitIDs=(self.fitID,), action='moddel', typeID=self.newItemID))
|
||||
@@ -76,6 +88,18 @@ class GuiChangeLocalModuleMetasCommand(wx.Command):
|
||||
events.append(GE.FitChanged(fitIDs=(self.fitID,), action='modadd', typeID=self.replacedItemIDs))
|
||||
if not events:
|
||||
events.append(GE.FitChanged(fitIDs=(self.fitID,)))
|
||||
if success:
|
||||
for position in self.positions:
|
||||
oldMod = oldModMap.get(position)
|
||||
newMod = newModMap.get(position)
|
||||
if oldMod is not newMod:
|
||||
events.append(GE.ItemChangedInplace(fitID=self.fitID, old=oldMod, new=newMod))
|
||||
for event in events:
|
||||
wx.PostEvent(gui.mainFrame.MainFrame.getInstance(), event)
|
||||
return success
|
||||
|
||||
def _getPositionMap(self, fit):
|
||||
positionMap = {}
|
||||
for position in self.positions:
|
||||
positionMap[position] = fit.modules[position]
|
||||
return positionMap
|
||||
|
||||
@@ -57,41 +57,42 @@ class GuiLocalModuleToCargoCommand(wx.Command):
|
||||
commands.append(cmdReplace)
|
||||
# Submit batch now because we need to have updated info on fit to keep going
|
||||
success = self.internalHistory.submitBatch(*commands)
|
||||
newMod = fit.modules[self.srcModPosition]
|
||||
# Process charge changes if module is moved to proper slot
|
||||
if newMod.slot == srcModSlot:
|
||||
# If we had to unload charge, add it to cargo
|
||||
if cmdReplace.unloadedCharge and srcModChargeItemID is not None:
|
||||
cmdAddCargoCharge = CalcAddCargoCommand(
|
||||
fitID=self.fitID,
|
||||
cargoInfo=CargoInfo(itemID=srcModChargeItemID, amount=srcModChargeAmount))
|
||||
success = self.internalHistory.submit(cmdAddCargoCharge)
|
||||
# If we did not unload charge and there still was a charge, see if amount differs and process it
|
||||
elif not cmdReplace.unloadedCharge and srcModChargeItemID is not None:
|
||||
# How many extra charges do we need to take from cargo
|
||||
extraChargeAmount = newMod.numCharges - srcModChargeAmount
|
||||
if extraChargeAmount > 0:
|
||||
cmdRemoveCargoExtraCharge = CalcRemoveCargoCommand(
|
||||
if success:
|
||||
newMod = fit.modules[self.srcModPosition]
|
||||
# Process charge changes if module is moved to proper slot
|
||||
if newMod.slot == srcModSlot:
|
||||
# If we had to unload charge, add it to cargo
|
||||
if cmdReplace.unloadedCharge and srcModChargeItemID is not None:
|
||||
cmdAddCargoCharge = CalcAddCargoCommand(
|
||||
fitID=self.fitID,
|
||||
cargoInfo=CargoInfo(itemID=srcModChargeItemID, amount=extraChargeAmount))
|
||||
# Do not check if operation was successful or not, we're okay if we have no such
|
||||
# charges in cargo
|
||||
self.internalHistory.submit(cmdRemoveCargoExtraCharge)
|
||||
elif extraChargeAmount < 0:
|
||||
cmdAddCargoExtraCharge = CalcAddCargoCommand(
|
||||
fitID=self.fitID,
|
||||
cargoInfo=CargoInfo(itemID=srcModChargeItemID, amount=abs(extraChargeAmount)))
|
||||
success = self.internalHistory.submit(cmdAddCargoExtraCharge)
|
||||
if success:
|
||||
# Store info to properly send events later
|
||||
self.removedModItemID = srcModItemID
|
||||
self.addedModItemID = self.dstCargoItemID
|
||||
# If drag happened to module which cannot be fit into current slot - consider it as failure
|
||||
else:
|
||||
success = False
|
||||
# And in case of any failures, cancel everything to try to do move instead
|
||||
if not success:
|
||||
self.internalHistory.undoAll()
|
||||
cargoInfo=CargoInfo(itemID=srcModChargeItemID, amount=srcModChargeAmount))
|
||||
success = self.internalHistory.submit(cmdAddCargoCharge)
|
||||
# If we did not unload charge and there still was a charge, see if amount differs and process it
|
||||
elif not cmdReplace.unloadedCharge and srcModChargeItemID is not None:
|
||||
# How many extra charges do we need to take from cargo
|
||||
extraChargeAmount = newMod.numCharges - srcModChargeAmount
|
||||
if extraChargeAmount > 0:
|
||||
cmdRemoveCargoExtraCharge = CalcRemoveCargoCommand(
|
||||
fitID=self.fitID,
|
||||
cargoInfo=CargoInfo(itemID=srcModChargeItemID, amount=extraChargeAmount))
|
||||
# Do not check if operation was successful or not, we're okay if we have no such
|
||||
# charges in cargo
|
||||
self.internalHistory.submit(cmdRemoveCargoExtraCharge)
|
||||
elif extraChargeAmount < 0:
|
||||
cmdAddCargoExtraCharge = CalcAddCargoCommand(
|
||||
fitID=self.fitID,
|
||||
cargoInfo=CargoInfo(itemID=srcModChargeItemID, amount=abs(extraChargeAmount)))
|
||||
success = self.internalHistory.submit(cmdAddCargoExtraCharge)
|
||||
if success:
|
||||
# Store info to properly send events later
|
||||
self.removedModItemID = srcModItemID
|
||||
self.addedModItemID = self.dstCargoItemID
|
||||
# If drag happened to module which cannot be fit into current slot - consider it as failure
|
||||
else:
|
||||
success = False
|
||||
# And in case of any failures, cancel everything to try to do move instead
|
||||
if not success:
|
||||
self.internalHistory.undoAll()
|
||||
# Just dump module and its charges into cargo when copying or moving to cargo
|
||||
if not success:
|
||||
commands = []
|
||||
|
||||
@@ -11,6 +11,9 @@ GraphOptionChanged, GRAPH_OPTION_CHANGED = wx.lib.newevent.NewEvent()
|
||||
TargetProfileRenamed, TARGET_PROFILE_RENAMED = wx.lib.newevent.NewEvent()
|
||||
TargetProfileChanged, TARGET_PROFILE_CHANGED = wx.lib.newevent.NewEvent()
|
||||
TargetProfileRemoved, TARGET_PROFILE_REMOVED = wx.lib.newevent.NewEvent()
|
||||
# For events when item is actually replaced under the hood,
|
||||
# but from user's perspective it's supposed to change/mutate
|
||||
ItemChangedInplace, ITEM_CHANGED_INPLACE = wx.lib.newevent.NewEvent()
|
||||
|
||||
EffectiveHpToggled, EFFECTIVE_HP_TOGGLED = wx.lib.newevent.NewEvent()
|
||||
|
||||
|
||||
@@ -216,3 +216,4 @@ class ItemStatsContainer(wx.Panel):
|
||||
mutaPanel = getattr(self, 'mutator', None)
|
||||
if mutaPanel is not None:
|
||||
mutaPanel.OnWindowClose()
|
||||
self.params.OnWindowClose()
|
||||
|
||||
BIN
imgs/icons/10065@1x.png
Normal file
|
After Width: | Height: | Size: 658 B |
BIN
imgs/icons/10065@2x.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
imgs/icons/24968@1x.png
Normal file
|
After Width: | Height: | Size: 794 B |
BIN
imgs/icons/24968@2x.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
imgs/icons/24969@1x.png
Normal file
|
After Width: | Height: | Size: 801 B |
BIN
imgs/icons/24969@2x.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
imgs/icons/24970@1x.png
Normal file
|
After Width: | Height: | Size: 789 B |
BIN
imgs/icons/24970@2x.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
imgs/icons/24971@1x.png
Normal file
|
After Width: | Height: | Size: 792 B |
BIN
imgs/icons/24971@2x.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
imgs/icons/24972@1x.png
Normal file
|
After Width: | Height: | Size: 778 B |
BIN
imgs/icons/24972@2x.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
imgs/icons/24973@1x.png
Normal file
|
After Width: | Height: | Size: 798 B |
BIN
imgs/icons/24973@2x.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
imgs/icons/24974@1x.png
Normal file
|
After Width: | Height: | Size: 903 B |
BIN
imgs/icons/24974@2x.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
imgs/icons/24975@1x.png
Normal file
|
After Width: | Height: | Size: 909 B |
BIN
imgs/icons/24975@2x.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
imgs/icons/24976@1x.png
Normal file
|
After Width: | Height: | Size: 919 B |
BIN
imgs/icons/24976@2x.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
imgs/icons/24977@1x.png
Normal file
|
After Width: | Height: | Size: 909 B |
BIN
imgs/icons/24977@2x.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
imgs/icons/24978@1x.png
Normal file
|
After Width: | Height: | Size: 900 B |
BIN
imgs/icons/24978@2x.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
imgs/icons/24979@1x.png
Normal file
|
After Width: | Height: | Size: 905 B |
BIN
imgs/icons/24979@2x.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
imgs/icons/24980@1x.png
Normal file
|
After Width: | Height: | Size: 885 B |
BIN
imgs/icons/24980@2x.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
imgs/icons/24981@1x.png
Normal file
|
After Width: | Height: | Size: 883 B |
BIN
imgs/icons/24981@2x.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
imgs/icons/24982@1x.png
Normal file
|
After Width: | Height: | Size: 865 B |
BIN
imgs/icons/24982@2x.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
imgs/icons/24983@1x.png
Normal file
|
After Width: | Height: | Size: 877 B |
BIN
imgs/icons/24983@2x.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
imgs/icons/24984@1x.png
Normal file
|
After Width: | Height: | Size: 844 B |
BIN
imgs/icons/24984@2x.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
imgs/icons/24985@1x.png
Normal file
|
After Width: | Height: | Size: 873 B |
BIN
imgs/icons/24985@2x.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
imgs/icons/24986@1x.png
Normal file
|
After Width: | Height: | Size: 933 B |
BIN
imgs/icons/24986@2x.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
imgs/icons/24987@1x.png
Normal file
|
After Width: | Height: | Size: 941 B |
BIN
imgs/icons/24987@2x.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
imgs/icons/24988@1x.png
Normal file
|
After Width: | Height: | Size: 921 B |
BIN
imgs/icons/24988@2x.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
imgs/icons/24989@1x.png
Normal file
|
After Width: | Height: | Size: 945 B |
BIN
imgs/icons/24989@2x.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
imgs/icons/24990@1x.png
Normal file
|
After Width: | Height: | Size: 917 B |
BIN
imgs/icons/24990@2x.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
imgs/icons/24991@1x.png
Normal file
|
After Width: | Height: | Size: 938 B |
BIN
imgs/icons/24991@2x.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
imgs/icons/24992@1x.png
Normal file
|
After Width: | Height: | Size: 809 B |
BIN
imgs/icons/24992@2x.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
imgs/icons/24993@1x.png
Normal file
|
After Width: | Height: | Size: 828 B |
BIN
imgs/icons/24993@2x.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
imgs/icons/24994@1x.png
Normal file
|
After Width: | Height: | Size: 814 B |
BIN
imgs/icons/24994@2x.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
imgs/icons/24995@1x.png
Normal file
|
After Width: | Height: | Size: 826 B |
BIN
imgs/icons/24995@2x.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
imgs/icons/24996@1x.png
Normal file
|
After Width: | Height: | Size: 798 B |
BIN
imgs/icons/24996@2x.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
imgs/icons/24997@1x.png
Normal file
|
After Width: | Height: | Size: 816 B |
BIN
imgs/icons/24997@2x.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
imgs/icons/24998@1x.png
Normal file
|
After Width: | Height: | Size: 880 B |
BIN
imgs/icons/24998@2x.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
imgs/icons/24999@1x.png
Normal file
|
After Width: | Height: | Size: 887 B |
BIN
imgs/icons/24999@2x.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
imgs/icons/25000@1x.png
Normal file
|
After Width: | Height: | Size: 880 B |
BIN
imgs/icons/25000@2x.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
imgs/icons/25001@1x.png
Normal file
|
After Width: | Height: | Size: 902 B |
BIN
imgs/icons/25001@2x.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
imgs/icons/25002@1x.png
Normal file
|
After Width: | Height: | Size: 875 B |
BIN
imgs/icons/25002@2x.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
imgs/icons/25003@1x.png
Normal file
|
After Width: | Height: | Size: 903 B |
BIN
imgs/icons/25003@2x.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
imgs/icons/25021@1x.png
Normal file
|
After Width: | Height: | Size: 775 B |
BIN
imgs/icons/25021@2x.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
imgs/icons/25022@1x.png
Normal file
|
After Width: | Height: | Size: 831 B |
BIN
imgs/icons/25022@2x.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
imgs/icons/25023@1x.png
Normal file
|
After Width: | Height: | Size: 808 B |