Merge branch 'singularity'
30
eos/db/migrations/upgrade39.py
Normal file
@@ -0,0 +1,30 @@
|
||||
"""
|
||||
Migration 39
|
||||
|
||||
- Shield amplifier tiericide
|
||||
"""
|
||||
|
||||
CONVERSIONS = {
|
||||
1798: ( # 'Basic' EM Shield Amplifier
|
||||
9562, # Supplemental EM Ward Amplifier
|
||||
),
|
||||
1804: ( # 'Basic' Explosive Shield Amplifier
|
||||
9574, # Supplemental Explosive Deflection Amplifier
|
||||
),
|
||||
1802: ( # 'Basic' Kinetic Shield Amplifier
|
||||
9570, # Supplemental Kinetic Deflection Amplifier
|
||||
),
|
||||
1800: ( # 'Basic' Thermal Shield Amplifier
|
||||
9566, # Supplemental Thermal Dissipation Amplifier
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
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 "cargo" SET "itemID" = ? WHERE "itemID" = ?',
|
||||
(replacement_item, retired_item))
|
||||
367
eos/effects.py
@@ -26,6 +26,8 @@ from eos.utils.spoolSupport import SpoolType, SpoolOptions, calculateSpoolup, re
|
||||
|
||||
class BaseEffect:
|
||||
|
||||
dealsDamage = False
|
||||
|
||||
@staticmethod
|
||||
def handler(fit, module, context, projectionRange, **kwargs):
|
||||
pass
|
||||
@@ -62,6 +64,7 @@ class Effect10(BaseEffect):
|
||||
Modules from group: Energy Weapon (212 of 214)
|
||||
"""
|
||||
|
||||
dealsDamage = True
|
||||
type = 'active'
|
||||
|
||||
@staticmethod
|
||||
@@ -96,7 +99,7 @@ class Effect21(BaseEffect):
|
||||
|
||||
Used by:
|
||||
Modules from group: Shield Extender (36 of 36)
|
||||
Modules from group: Shield Resistance Amplifier (88 of 88)
|
||||
Modules from group: Shield Resistance Amplifier (84 of 84)
|
||||
"""
|
||||
|
||||
type = 'passive'
|
||||
@@ -169,6 +172,7 @@ class Effect34(BaseEffect):
|
||||
Modules from group: Projectile Weapon (165 of 165)
|
||||
"""
|
||||
|
||||
dealsDamage = True
|
||||
type = 'active'
|
||||
|
||||
@staticmethod
|
||||
@@ -189,6 +193,7 @@ class Effect38(BaseEffect):
|
||||
Modules from group: Smart Bomb (118 of 118)
|
||||
"""
|
||||
|
||||
dealsDamage = True
|
||||
type = 'active'
|
||||
|
||||
|
||||
@@ -555,6 +560,7 @@ class Effect101(BaseEffect):
|
||||
Structure Modules named like: Standup Launcher (7 of 7)
|
||||
"""
|
||||
|
||||
dealsDamage = True
|
||||
type = 'active', 'projected'
|
||||
|
||||
@staticmethod
|
||||
@@ -1633,7 +1639,7 @@ class Effect581(BaseEffect):
|
||||
@staticmethod
|
||||
def handler(fit, container, context, projectionRange, **kwargs):
|
||||
level = container.level if 'skill' in context else 1
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill('Gunnery'),
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill('Gunnery') or mod.item.requiresSkill('Vorton Projector Operation'),
|
||||
'cpu', container.getModifiedItemAttr('cpuNeedBonus') * level, **kwargs)
|
||||
|
||||
|
||||
@@ -1742,7 +1748,7 @@ class Effect596(BaseEffect):
|
||||
ammoInfluenceRange
|
||||
|
||||
Used by:
|
||||
Items from category: Charge (590 of 955)
|
||||
Items from category: Charge (608 of 973)
|
||||
"""
|
||||
|
||||
type = 'passive'
|
||||
@@ -2328,7 +2334,7 @@ class Effect804(BaseEffect):
|
||||
ammoInfluenceCapNeed
|
||||
|
||||
Used by:
|
||||
Items from category: Charge (496 of 955)
|
||||
Items from category: Charge (514 of 973)
|
||||
"""
|
||||
|
||||
type = 'passive'
|
||||
@@ -4898,7 +4904,9 @@ class Effect1638(BaseEffect):
|
||||
@staticmethod
|
||||
def handler(fit, skill, context, projectionRange, **kwargs):
|
||||
fit.modules.filteredItemBoost(
|
||||
lambda mod: mod.item.requiresSkill('Gunnery') or mod.item.requiresSkill('Missile Launcher Operation'),
|
||||
lambda mod: (mod.item.requiresSkill('Gunnery') or
|
||||
mod.item.requiresSkill('Missile Launcher Operation') or
|
||||
mod.item.requiresSkill('Vorton Projector Operation')),
|
||||
'power', skill.getModifiedItemAttr('powerNeedBonus') * skill.level, **kwargs)
|
||||
|
||||
|
||||
@@ -6054,7 +6062,7 @@ class Effect2052(BaseEffect):
|
||||
modifyShieldResonancePostPercent
|
||||
|
||||
Used by:
|
||||
Modules from group: Shield Resistance Amplifier (88 of 88)
|
||||
Modules from group: Shield Resistance Amplifier (84 of 84)
|
||||
"""
|
||||
|
||||
type = 'passive'
|
||||
@@ -7822,7 +7830,10 @@ class Effect2735(BaseEffect):
|
||||
boosterArmorHpPenalty
|
||||
|
||||
Used by:
|
||||
Implants named like: Booster (12 of 38)
|
||||
Implants named like: Crash Booster (3 of 4)
|
||||
Implants named like: Exile Booster (3 of 4)
|
||||
Implants named like: Frentix Booster (3 of 4)
|
||||
Implants named like: X Instinct Booster (3 of 4)
|
||||
"""
|
||||
|
||||
attr = 'boosterArmorHPPenalty'
|
||||
@@ -8441,6 +8452,7 @@ class Effect2847(BaseEffect):
|
||||
|
||||
Used by:
|
||||
Implants named like: Drop Booster (4 of 4)
|
||||
Implants named like: EDENCOM Vorton Booster (6 of 9)
|
||||
Implants named like: Eifyr and Co. 'Gunslinger' Motion Prediction MR (6 of 6)
|
||||
Implant: Antipharmakon Iokira
|
||||
Implant: Ogdin's Eye Coordination Enhancer
|
||||
@@ -9176,7 +9188,7 @@ class Effect3001(BaseEffect):
|
||||
|
||||
Used by:
|
||||
Modules from group: Missile Launcher Torpedo (22 of 22)
|
||||
Items from market group: Ship Equipment > Turrets & Launchers (429 of 889)
|
||||
Items from market group: Ship Equipment > Turrets & Launchers (444 of 907)
|
||||
Module: Interdiction Sphere Launcher I
|
||||
"""
|
||||
|
||||
@@ -15118,6 +15130,7 @@ class Effect4489(BaseEffect):
|
||||
Module: 'Judgment' Electromagnetic Doomsday
|
||||
"""
|
||||
|
||||
dealsDamage = True
|
||||
type = 'active'
|
||||
|
||||
@staticmethod
|
||||
@@ -15134,6 +15147,7 @@ class Effect4490(BaseEffect):
|
||||
Module: 'Oblivion' Kinetic Doomsday
|
||||
"""
|
||||
|
||||
dealsDamage = True
|
||||
type = 'active'
|
||||
|
||||
@staticmethod
|
||||
@@ -15150,6 +15164,7 @@ class Effect4491(BaseEffect):
|
||||
Module: 'Aurora Ominae' Thermal Doomsday
|
||||
"""
|
||||
|
||||
dealsDamage = True
|
||||
type = 'active'
|
||||
|
||||
@staticmethod
|
||||
@@ -15166,6 +15181,7 @@ class Effect4492(BaseEffect):
|
||||
Module: 'Gjallarhorn' Explosive Doomsday
|
||||
"""
|
||||
|
||||
dealsDamage = True
|
||||
type = 'active'
|
||||
|
||||
@staticmethod
|
||||
@@ -27358,6 +27374,7 @@ class Effect6431(BaseEffect):
|
||||
Fighters from group: Light Fighter (32 of 32)
|
||||
"""
|
||||
|
||||
dealsDamage = True
|
||||
displayName = 'Missile Attack'
|
||||
hasCharges = True
|
||||
prefix = 'fighterAbilityMissiles'
|
||||
@@ -27638,6 +27655,7 @@ class Effect6465(BaseEffect):
|
||||
Fighters from group: Heavy Fighter (34 of 34)
|
||||
"""
|
||||
|
||||
dealsDamage = True
|
||||
displayName = 'Turret Attack'
|
||||
prefix = 'fighterAbilityAttackMissile'
|
||||
type = 'active'
|
||||
@@ -27680,6 +27698,7 @@ class Effect6472(BaseEffect):
|
||||
Modules named like: Lance (4 of 4)
|
||||
"""
|
||||
|
||||
dealsDamage = True
|
||||
type = 'active'
|
||||
|
||||
@staticmethod
|
||||
@@ -27696,6 +27715,7 @@ class Effect6473(BaseEffect):
|
||||
Module: Bosonic Field Generator
|
||||
"""
|
||||
|
||||
dealsDamage = True
|
||||
type = 'active'
|
||||
|
||||
@staticmethod
|
||||
@@ -27906,6 +27926,7 @@ class Effect6485(BaseEffect):
|
||||
Fighters from group: Heavy Fighter (16 of 34)
|
||||
"""
|
||||
|
||||
dealsDamage = True
|
||||
displayName = 'Bomb'
|
||||
hasCharges = True
|
||||
prefix = 'fighterAbilityLaunchBomb'
|
||||
@@ -31290,7 +31311,6 @@ class Effect6713(BaseEffect):
|
||||
shipBonusSupercarrierM1BurstProjectorWebBonus
|
||||
|
||||
Used by:
|
||||
Ship: Hel
|
||||
Ship: Vendetta
|
||||
"""
|
||||
|
||||
@@ -33959,6 +33979,7 @@ class Effect6995(BaseEffect):
|
||||
Modules from group: Precursor Weapon (19 of 19)
|
||||
"""
|
||||
|
||||
dealsDamage = True
|
||||
type = 'active'
|
||||
|
||||
@staticmethod
|
||||
@@ -36370,3 +36391,331 @@ class Effect8029(BaseEffect):
|
||||
fit.modules.filteredItemForce(
|
||||
lambda mod: mod.item.group.name == 'Capacitor Booster',
|
||||
attr, ship.getModifiedItemAttr('shipBonusRole7'), **kwargs)
|
||||
|
||||
|
||||
class Effect8034(BaseEffect):
|
||||
"""
|
||||
smallUpwellWeaponDmgBonusRequiredSkill
|
||||
|
||||
Used by:
|
||||
Skill: Small Vorton Projector
|
||||
"""
|
||||
|
||||
type = 'passive'
|
||||
|
||||
@staticmethod
|
||||
def handler(fit, skill, context, projectionRange, **kwargs):
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill('Small Vorton Projector'),
|
||||
'damageMultiplier', skill.getModifiedItemAttr('damageMultiplierBonus') * skill.level, **kwargs)
|
||||
|
||||
|
||||
class Effect8035(BaseEffect):
|
||||
"""
|
||||
mediumUpwellWeaponDmgBonusRequiredSkill
|
||||
|
||||
Used by:
|
||||
Skill: Medium Vorton Projector
|
||||
"""
|
||||
|
||||
type = 'passive'
|
||||
|
||||
@staticmethod
|
||||
def handler(fit, skill, context, projectionRange, **kwargs):
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill('Medium Vorton Projector'),
|
||||
'damageMultiplier', skill.getModifiedItemAttr('damageMultiplierBonus') * skill.level, **kwargs)
|
||||
|
||||
|
||||
class Effect8036(BaseEffect):
|
||||
"""
|
||||
largeUpwellWeaponDmgBonusRequiredSkill
|
||||
|
||||
Used by:
|
||||
Skill: Large Vorton Projector
|
||||
"""
|
||||
|
||||
type = 'passive'
|
||||
|
||||
@staticmethod
|
||||
def handler(fit, skill, context, projectionRange, **kwargs):
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill('Large Vorton Projector'),
|
||||
'damageMultiplier', skill.getModifiedItemAttr('damageMultiplierBonus') * skill.level, **kwargs)
|
||||
|
||||
|
||||
class Effect8037(BaseEffect):
|
||||
"""
|
||||
ChainLightning
|
||||
|
||||
Used by:
|
||||
Modules from group: Vorton Projector (15 of 15)
|
||||
"""
|
||||
|
||||
type = 'active'
|
||||
|
||||
|
||||
class Effect8039(BaseEffect):
|
||||
"""
|
||||
upwellSkillaoeVelocityaoeCloudSizeBonus
|
||||
|
||||
Used by:
|
||||
Skill: Vorton Arc Guidance
|
||||
"""
|
||||
|
||||
type = 'passive'
|
||||
|
||||
@staticmethod
|
||||
def handler(fit, skill, context, projectionRange, **kwargs):
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill('Vorton Projector Operation'),
|
||||
'aoeVelocity', skill.getModifiedItemAttr('aoeVelocityBonus') * skill.level, **kwargs)
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill('Vorton Projector Operation'),
|
||||
'aoeCloudSize', skill.getModifiedItemAttr('aoeCloudSizeBonus') * skill.level, **kwargs)
|
||||
|
||||
|
||||
class Effect8041(BaseEffect):
|
||||
"""
|
||||
upwellSkillDamageMuliplierBonus
|
||||
|
||||
Used by:
|
||||
Skill: Vorton Power Amplification
|
||||
"""
|
||||
|
||||
type = 'passive'
|
||||
|
||||
@staticmethod
|
||||
def handler(fit, skill, context, projectionRange, **kwargs):
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.group.name == 'Vorton Projector',
|
||||
'damageMultiplier', skill.getModifiedItemAttr('damageMultiplierBonus') * skill.level, **kwargs)
|
||||
|
||||
|
||||
class Effect8042(BaseEffect):
|
||||
"""
|
||||
upwellSkillSpeedBonus
|
||||
|
||||
Used by:
|
||||
Skill: Vorton Projector Operation
|
||||
"""
|
||||
|
||||
type = 'passive'
|
||||
|
||||
@staticmethod
|
||||
def handler(fit, skill, context, projectionRange, **kwargs):
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill('Vorton Projector Operation'),
|
||||
'speed', skill.getModifiedItemAttr('turretSpeeBonus') * skill.level, **kwargs)
|
||||
|
||||
|
||||
class Effect8044(BaseEffect):
|
||||
"""
|
||||
smallVortonProjectorSkillDmgBonus
|
||||
|
||||
Used by:
|
||||
Skill: Small Vorton Specialization
|
||||
"""
|
||||
|
||||
type = 'passive'
|
||||
|
||||
@staticmethod
|
||||
def handler(fit, skill, context, projectionRange, **kwargs):
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill('Small Vorton Specialization'),
|
||||
'damageMultiplier', skill.getModifiedItemAttr('damageMultiplierBonus') * skill.level, **kwargs)
|
||||
|
||||
|
||||
class Effect8045(BaseEffect):
|
||||
"""
|
||||
mediumVortonProjectorSkillDmgBonus
|
||||
|
||||
Used by:
|
||||
Skill: Medium Vorton Specialization
|
||||
"""
|
||||
|
||||
type = 'passive'
|
||||
|
||||
@staticmethod
|
||||
def handler(fit, skill, context, projectionRange, **kwargs):
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill('Medium Vorton Specialization'),
|
||||
'damageMultiplier', skill.getModifiedItemAttr('damageMultiplierBonus') * skill.level, **kwargs)
|
||||
|
||||
|
||||
class Effect8046(BaseEffect):
|
||||
"""
|
||||
largeVortonProjectorSkillDmgBonus
|
||||
|
||||
Used by:
|
||||
Skill: Large Vorton Specialization
|
||||
"""
|
||||
|
||||
type = 'passive'
|
||||
|
||||
@staticmethod
|
||||
def handler(fit, skill, context, projectionRange, **kwargs):
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill('Large Vorton Specialization'),
|
||||
'damageMultiplier', skill.getModifiedItemAttr('damageMultiplierBonus') * skill.level, **kwargs)
|
||||
|
||||
|
||||
class Effect8047(BaseEffect):
|
||||
"""
|
||||
shipBonusUF1shieldResistance
|
||||
|
||||
Used by:
|
||||
Ship: Skybreaker
|
||||
"""
|
||||
|
||||
type = 'passive'
|
||||
|
||||
@staticmethod
|
||||
def handler(fit, ship, context, projectionRange, **kwargs):
|
||||
for type in ('kinetic', 'thermal', 'explosive', 'em'):
|
||||
fit.ship.boostItemAttr('shield%sDamageResonance' % type.capitalize(),
|
||||
ship.getModifiedItemAttr('shipBonusUF1'),
|
||||
skill='EDENCOM Frigate', **kwargs)
|
||||
|
||||
|
||||
class Effect8048(BaseEffect):
|
||||
"""
|
||||
shipBonusUF2damage
|
||||
|
||||
Used by:
|
||||
Ship: Skybreaker
|
||||
"""
|
||||
|
||||
type = 'passive'
|
||||
|
||||
@staticmethod
|
||||
def handler(fit, ship, context, projectionRange, **kwargs):
|
||||
fit.modules.filteredItemBoost(
|
||||
lambda mod: mod.item.requiresSkill('Small Vorton Projector'), 'damageMultiplier',
|
||||
ship.getModifiedItemAttr('shipBonusUF2'), skill='EDENCOM Frigate', **kwargs)
|
||||
|
||||
|
||||
class Effect8052(BaseEffect):
|
||||
"""
|
||||
shipBonusUC2ShieldResistance
|
||||
|
||||
Used by:
|
||||
Ship: Stormbringer
|
||||
"""
|
||||
|
||||
type = 'passive'
|
||||
|
||||
@staticmethod
|
||||
def handler(fit, ship, context, projectionRange, **kwargs):
|
||||
for type in ('kinetic', 'thermal', 'explosive', 'em'):
|
||||
fit.ship.boostItemAttr('shield%sDamageResonance' % type.capitalize(),
|
||||
ship.getModifiedItemAttr('shipBonusUC2'),
|
||||
skill='EDENCOM Cruiser', **kwargs)
|
||||
|
||||
|
||||
class Effect8053(BaseEffect):
|
||||
"""
|
||||
shipBonusUC1maxRange
|
||||
|
||||
Used by:
|
||||
Ship: Stormbringer
|
||||
"""
|
||||
|
||||
type = 'passive'
|
||||
|
||||
@staticmethod
|
||||
def handler(fit, ship, context, projectionRange, **kwargs):
|
||||
fit.modules.filteredItemBoost(
|
||||
lambda mod: mod.item.requiresSkill('Medium Vorton Projector'), 'maxRange',
|
||||
ship.getModifiedItemAttr('shipBonusUC1'), skill='EDENCOM Cruiser', **kwargs)
|
||||
|
||||
|
||||
class Effect8054(BaseEffect):
|
||||
"""
|
||||
shipBonusUB1upwellDamage
|
||||
|
||||
Used by:
|
||||
Ship: Thunderchild
|
||||
"""
|
||||
|
||||
type = 'passive'
|
||||
|
||||
@staticmethod
|
||||
def handler(fit, ship, context, projectionRange, **kwargs):
|
||||
fit.modules.filteredItemBoost(
|
||||
lambda mod: mod.item.requiresSkill('Large Vorton Projector'), 'damageMultiplier',
|
||||
ship.getModifiedItemAttr('shipBonusUB1'), skill='EDENCOM Battleship', **kwargs)
|
||||
|
||||
|
||||
class Effect8056(BaseEffect):
|
||||
"""
|
||||
shipBonusUB2upwellROF
|
||||
|
||||
Used by:
|
||||
Ship: Thunderchild
|
||||
"""
|
||||
|
||||
type = 'passive'
|
||||
|
||||
@staticmethod
|
||||
def handler(fit, ship, context, projectionRange, **kwargs):
|
||||
fit.modules.filteredItemBoost(
|
||||
lambda mod: mod.item.requiresSkill('Large Vorton Projector'), 'speed',
|
||||
ship.getModifiedItemAttr('shipBonusUB2'), skill='EDENCOM Battleship', **kwargs)
|
||||
|
||||
|
||||
class Effect8057(BaseEffect):
|
||||
"""
|
||||
vortonWeaponDamageSpeedMultiply
|
||||
|
||||
Used by:
|
||||
Modules from group: Vorton Projector Upgrade (3 of 3)
|
||||
"""
|
||||
|
||||
type = 'passive'
|
||||
|
||||
@staticmethod
|
||||
def handler(fit, module, context, projectionRange, **kwargs):
|
||||
fit.modules.filteredItemMultiply(lambda mod: mod.item.group.name == 'Vorton Projector',
|
||||
'damageMultiplier', module.getModifiedItemAttr('damageMultiplier'),
|
||||
stackingPenalties=True, **kwargs)
|
||||
fit.modules.filteredItemMultiply(lambda mod: mod.item.group.name == 'Vorton Projector',
|
||||
'speed', module.getModifiedItemAttr('speedMultiplier'),
|
||||
stackingPenalties=True, **kwargs)
|
||||
|
||||
|
||||
class Effect8062(BaseEffect):
|
||||
"""
|
||||
ammoAOEvelocityMultiplier
|
||||
|
||||
Used by:
|
||||
Charges from group: Advanced Condenser Pack (6 of 6)
|
||||
"""
|
||||
|
||||
type = 'passive'
|
||||
|
||||
@staticmethod
|
||||
def handler(fit, module, context, projectionRange, **kwargs):
|
||||
module.multiplyItemAttr('aoeVelocity', module.getModifiedChargeAttr('aoeVelocityBonus') or 0, **kwargs)
|
||||
|
||||
|
||||
class Effect8064(BaseEffect):
|
||||
"""
|
||||
vortonProjectorOptimalRangeBonus
|
||||
|
||||
Used by:
|
||||
Implants named like: EDENCOM Vorton Booster RA (3 of 3)
|
||||
"""
|
||||
|
||||
type = 'passive'
|
||||
|
||||
@staticmethod
|
||||
def handler(fit, implant, context, projectionRange, **kwargs):
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill('Vorton Projector Operation'),
|
||||
'maxRange', implant.getModifiedItemAttr('rangeSkillBonus'), **kwargs)
|
||||
|
||||
|
||||
class Effect8065(BaseEffect):
|
||||
"""
|
||||
vortonProjectorSkillRangeBonus
|
||||
|
||||
Used by:
|
||||
Skill: Vorton Arc Extension
|
||||
"""
|
||||
|
||||
type = 'passive'
|
||||
|
||||
@staticmethod
|
||||
def handler(fit, skill, context, projectionRange, **kwargs):
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill('Vorton Projector Operation'),
|
||||
'maxRange', skill.getModifiedItemAttr('rangeSkillBonus') * skill.level, **kwargs)
|
||||
|
||||
@@ -146,6 +146,12 @@ class Effect(EqBase):
|
||||
|
||||
return self.__effectDef is not None
|
||||
|
||||
@property
|
||||
def dealsDamage(self):
|
||||
if not self.__generated:
|
||||
self.__generateHandler()
|
||||
return self.__dealsDamage
|
||||
|
||||
def isType(self, type):
|
||||
"""
|
||||
Check if this effect is of the passed type
|
||||
@@ -167,6 +173,7 @@ class Effect(EqBase):
|
||||
self.__handler = getattr(effectDef, "handler", eos.effects.BaseEffect.handler)
|
||||
self.__runTime = getattr(effectDef, "runTime", "normal")
|
||||
self.__activeByDefault = getattr(effectDef, "activeByDefault", True)
|
||||
self.__dealsDamage = effectDef.dealsDamage
|
||||
effectType = getattr(effectDef, "type", None)
|
||||
effectType = effectType if isinstance(effectType, tuple) or effectType is None else (effectType,)
|
||||
self.__type = effectType
|
||||
@@ -175,6 +182,7 @@ class Effect(EqBase):
|
||||
self.__handler = eos.effects.DummyEffect.handler
|
||||
self.__runTime = "normal"
|
||||
self.__activeByDefault = True
|
||||
self.__dealsDamage = False
|
||||
self.__type = None
|
||||
pyfalog.debug("ImportError generating handler: {0}", e)
|
||||
except AttributeError as e:
|
||||
@@ -182,6 +190,7 @@ class Effect(EqBase):
|
||||
self.__handler = eos.effects.DummyEffect.handler
|
||||
self.__runTime = "normal"
|
||||
self.__activeByDefault = True
|
||||
self.__dealsDamage = False
|
||||
self.__type = None
|
||||
pyfalog.error("AttributeError generating handler: {0}", e)
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
@@ -190,6 +199,7 @@ class Effect(EqBase):
|
||||
self.__handler = eos.effects.DummyEffect.handler
|
||||
self.__runTime = "normal"
|
||||
self.__activeByDefault = True
|
||||
self.__dealsDamage = False
|
||||
self.__type = None
|
||||
pyfalog.critical("Exception generating handler:")
|
||||
pyfalog.critical(e)
|
||||
|
||||
@@ -364,3 +364,11 @@ class Drone(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
|
||||
if self.item.groupID in fitDroneGroupLimits:
|
||||
return True
|
||||
return False
|
||||
|
||||
def canDealDamage(self, ignoreState=False):
|
||||
if self.item is None:
|
||||
return False
|
||||
for effect in self.item.effects.values():
|
||||
if effect.dealsDamage and (ignoreState or self.amountActive > 0):
|
||||
return True
|
||||
return False
|
||||
|
||||
@@ -441,3 +441,15 @@ class Fighter(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def canDealDamage(self, ignoreState=False, ignoreAbilityState=False):
|
||||
if self.item is None:
|
||||
return False
|
||||
if not self.active and not ignoreState:
|
||||
return False
|
||||
for ability in self.abilities:
|
||||
if not ability.active and not ignoreAbilityState:
|
||||
continue
|
||||
if ability.effect.dealsDamage:
|
||||
return True
|
||||
return False
|
||||
|
||||
@@ -461,6 +461,20 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
|
||||
return True
|
||||
return False
|
||||
|
||||
def canDealDamage(self, ignoreState=False):
|
||||
if self.isEmpty:
|
||||
return False
|
||||
for effect in self.item.effects.values():
|
||||
if effect.dealsDamage and (
|
||||
ignoreState or
|
||||
effect.isType('offline') or
|
||||
(effect.isType('passive') and self.state >= FittingModuleState.ONLINE) or
|
||||
(effect.isType('active') and self.state >= FittingModuleState.ACTIVE) or
|
||||
(effect.isType('overheat') and self.state >= FittingModuleState.OVERHEATED)
|
||||
):
|
||||
return True
|
||||
return False
|
||||
|
||||
def getVolleyParameters(self, spoolOptions=None, targetProfile=None, ignoreState=False):
|
||||
if self.isEmpty or (self.state < FittingModuleState.ACTIVE and not ignoreState):
|
||||
return {0: DmgTypes(0, 0, 0, 0)}
|
||||
|
||||
@@ -37,7 +37,14 @@ def getApplicationPerKey(src, tgt, atkSpeed, atkAngle, distance, tgtSpeed, tgtAn
|
||||
for mod in src.item.activeModulesIter():
|
||||
if not mod.isDealingDamage():
|
||||
continue
|
||||
if mod.hardpoint == FittingHardpoint.TURRET:
|
||||
if "ChainLightning" in mod.item.effects:
|
||||
if inLockRange:
|
||||
applicationMap[mod] = getVortonMult(
|
||||
mod=mod,
|
||||
distance=distance,
|
||||
tgtSpeed=tgtSpeed,
|
||||
tgtSigRadius=tgtSigRadius)
|
||||
elif mod.hardpoint == FittingHardpoint.TURRET:
|
||||
if inLockRange:
|
||||
applicationMap[mod] = getTurretMult(
|
||||
mod=mod,
|
||||
@@ -56,7 +63,6 @@ def getApplicationPerKey(src, tgt, atkSpeed, atkAngle, distance, tgtSpeed, tgtAn
|
||||
if inLockRange or (mod.charge is not None and 'fofMissileLaunching' in mod.charge.effects):
|
||||
applicationMap[mod] = getLauncherMult(
|
||||
mod=mod,
|
||||
src=src,
|
||||
distance=distance,
|
||||
tgtSpeed=tgtSpeed,
|
||||
tgtSigRadius=tgtSigRadius)
|
||||
@@ -151,7 +157,21 @@ def getTurretMult(mod, src, tgt, atkSpeed, atkAngle, distance, tgtSpeed, tgtAngl
|
||||
return mult
|
||||
|
||||
|
||||
def getLauncherMult(mod, src, distance, tgtSpeed, tgtSigRadius):
|
||||
def getVortonMult(mod, distance, tgtSpeed, tgtSigRadius):
|
||||
rangeFactor = calculateRangeFactor(
|
||||
mod.getModifiedItemAttr('maxRange'),
|
||||
0,
|
||||
distance)
|
||||
applicationFactor = _calcMissileFactor(
|
||||
atkEr=mod.getModifiedItemAttr('aoeCloudSize'),
|
||||
atkEv=mod.getModifiedItemAttr('aoeVelocity'),
|
||||
atkDrf=mod.getModifiedItemAttr('aoeDamageReductionFactor'),
|
||||
tgtSpeed=tgtSpeed,
|
||||
tgtSigRadius=tgtSigRadius)
|
||||
return rangeFactor * applicationFactor
|
||||
|
||||
|
||||
def getLauncherMult(mod, distance, tgtSpeed, tgtSigRadius):
|
||||
missileMaxRangeData = mod.missileMaxRangeData
|
||||
if missileMaxRangeData is None:
|
||||
return 0
|
||||
|
||||
@@ -27,7 +27,7 @@ import gui.globalEvents as GE
|
||||
import gui.mainFrame
|
||||
from graphs.data.base import FitGraph
|
||||
from graphs.events import RESIST_MODE_CHANGED
|
||||
from gui.auxFrame import AuxiliaryFrame
|
||||
from gui.auxWindow import AuxiliaryFrame
|
||||
from gui.bitmap_loader import BitmapLoader
|
||||
from service.const import GraphCacheCleanupReason
|
||||
from service.settings import GraphSettings
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
import wx
|
||||
|
||||
|
||||
class AuxiliaryFrame(wx.Frame):
|
||||
class AuxiliaryMixin:
|
||||
|
||||
_instance = None
|
||||
|
||||
@@ -55,14 +55,26 @@ class AuxiliaryFrame(wx.Frame):
|
||||
self.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNFACE))
|
||||
|
||||
@classmethod
|
||||
def openOne(cls, parent, *args, **kwargs):
|
||||
def openOne(cls, parent, *args, forceReopen=False, **kwargs):
|
||||
"""If window is open and alive - raise it, open otherwise"""
|
||||
if not cls._instance:
|
||||
if not cls._instance or forceReopen:
|
||||
if cls._instance:
|
||||
cls._instance.Close()
|
||||
frame = cls(parent, *args, **kwargs)
|
||||
cls._instance = frame
|
||||
frame.Show()
|
||||
else:
|
||||
cls._instance.Raise()
|
||||
return cls._instance
|
||||
|
||||
|
||||
def OnSuppressedAction(self, event):
|
||||
return
|
||||
|
||||
|
||||
class AuxiliaryFrame(AuxiliaryMixin, wx.Frame):
|
||||
pass
|
||||
|
||||
|
||||
class AuxiliaryDialog(AuxiliaryMixin, wx.Dialog):
|
||||
pass
|
||||
@@ -36,6 +36,11 @@ import gui.fitCommands as cmd
|
||||
from gui.fitCommands.helpers import droneStackLimit
|
||||
|
||||
|
||||
DRONE_ORDER = ('Light Scout Drones', 'Medium Scout Drones',
|
||||
'Heavy Attack Drones', 'Sentry Drones', 'Combat Utility Drones',
|
||||
'Electronic Warfare Drones', 'Logistic Drones', 'Mining Drones', 'Salvage Drones')
|
||||
|
||||
|
||||
class DroneViewDrop(wx.DropTarget):
|
||||
def __init__(self, dropFn, *args, **kwargs):
|
||||
super(DroneViewDrop, self).__init__(*args, **kwargs)
|
||||
@@ -186,17 +191,13 @@ class DroneView(Display):
|
||||
self.mainFrame.command.Submit(cmd.GuiMergeLocalDroneStacksCommand(
|
||||
fitID=fitID, srcPosition=srcPosition, dstPosition=dstPosition))
|
||||
|
||||
DRONE_ORDER = ('Light Scout Drones', 'Medium Scout Drones',
|
||||
'Heavy Attack Drones', 'Sentry Drones', 'Combat Utility Drones',
|
||||
'Electronic Warfare Drones', 'Logistic Drones', 'Mining Drones', 'Salvage Drones')
|
||||
|
||||
def droneKey(self, drone):
|
||||
@staticmethod
|
||||
def droneKey(drone):
|
||||
sMkt = Market.getInstance()
|
||||
|
||||
groupName = sMkt.getMarketGroupByItem(drone.item).name
|
||||
|
||||
return (self.DRONE_ORDER.index(groupName),
|
||||
drone.item.name)
|
||||
return (DRONE_ORDER.index(groupName), drone.item.name)
|
||||
|
||||
def fitChanged(self, event):
|
||||
event.Skip()
|
||||
|
||||
@@ -34,6 +34,9 @@ from service.fit import Fit
|
||||
from service.market import Market
|
||||
|
||||
|
||||
FIGHTER_ORDER = ('Light Fighter', 'Heavy Fighter', 'Support Fighter')
|
||||
|
||||
|
||||
class FighterViewDrop(wx.DropTarget):
|
||||
def __init__(self, dropFn, *args, **kwargs):
|
||||
super(FighterViewDrop, self).__init__(*args, **kwargs)
|
||||
@@ -250,11 +253,10 @@ class FighterDisplay(d.Display):
|
||||
def _merge(src, dst):
|
||||
return
|
||||
|
||||
FIGHTER_ORDER = ('Light Fighter', 'Heavy Fighter', 'Support Fighter')
|
||||
|
||||
def fighterKey(self, fighter):
|
||||
@staticmethod
|
||||
def fighterKey(fighter):
|
||||
groupName = Market.getInstance().getGroupByItem(fighter.item).name
|
||||
orderPos = self.FIGHTER_ORDER.index(groupName)
|
||||
orderPos = FIGHTER_ORDER.index(groupName)
|
||||
# Sort support fighters by name, ignore their abilities
|
||||
if groupName == 'Support Fighter':
|
||||
abilityEffectIDs = ()
|
||||
|
||||
@@ -119,12 +119,12 @@ class ProjectedView(d.Display):
|
||||
fitID=fitID, itemID=fit.modules[int(data[1])].itemID))
|
||||
elif data[0] == 'market':
|
||||
itemID = int(data[1])
|
||||
category = Market.getInstance().getItem(itemID, eager=('group.category')).category.name
|
||||
if category == 'Module':
|
||||
item = Market.getInstance().getItem(itemID)
|
||||
if item.isModule:
|
||||
self.mainFrame.command.Submit(cmd.GuiAddProjectedModuleCommand(fitID=fitID, itemID=itemID))
|
||||
elif category == 'Drone':
|
||||
elif item.isDrone:
|
||||
self.mainFrame.command.Submit(cmd.GuiAddProjectedDroneCommand(fitID=fitID, itemID=itemID))
|
||||
elif category == 'Fighter':
|
||||
elif item.isFighter:
|
||||
self.mainFrame.command.Submit(cmd.GuiAddProjectedFighterCommand(fitID=fitID, itemID=itemID))
|
||||
|
||||
def kbEvent(self, event):
|
||||
|
||||
@@ -6,6 +6,7 @@ from gui.builtinContextMenus import fitAddCurrentlyOpen
|
||||
from gui.builtinContextMenus import envEffectAdd
|
||||
from gui.builtinContextMenus import commandFitAdd
|
||||
from gui.builtinContextMenus.targetProfile import adder
|
||||
from gui.builtinContextMenus import graphFitAmmoPicker
|
||||
# Often-used item manipulations
|
||||
from gui.builtinContextMenus import shipModeChange
|
||||
from gui.builtinContextMenus import moduleAmmoChange
|
||||
|
||||
241
gui/builtinContextMenus/graphFitAmmoPicker.py
Normal file
@@ -0,0 +1,241 @@
|
||||
# noinspection PyPackageRequirements
|
||||
import wx
|
||||
|
||||
import gui.mainFrame
|
||||
from gui.auxWindow import AuxiliaryDialog
|
||||
from gui.contextMenu import ContextMenuSingle
|
||||
from service.ammo import Ammo
|
||||
from service.market import Market
|
||||
|
||||
|
||||
class GraphFitAmmoPicker(ContextMenuSingle):
|
||||
|
||||
def __init__(self):
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
|
||||
def display(self, callingWindow, srcContext, mainItem):
|
||||
if srcContext != 'graphFitList':
|
||||
return False
|
||||
if mainItem is None or not mainItem.isFit:
|
||||
return False
|
||||
if callingWindow.graphFrame.getView().internalName != 'dmgStatsGraph':
|
||||
return False
|
||||
return True
|
||||
|
||||
def getText(self, callingWindow, itmContext, mainItem):
|
||||
return 'Plot with Different Ammo...'
|
||||
|
||||
def activate(self, callingWindow, fullContext, mainItem, i):
|
||||
AmmoPickerFrame.openOne(callingWindow, mainItem.item, forceReopen=True)
|
||||
|
||||
|
||||
# GraphFitAmmoPicker.register()
|
||||
|
||||
|
||||
class AmmoPickerFrame(AuxiliaryDialog):
|
||||
|
||||
def __init__(self, parent, fit):
|
||||
super().__init__(parent, title='Choose Different Ammo', style=wx.DEFAULT_DIALOG_STYLE, resizeable=True)
|
||||
padding = 5
|
||||
|
||||
mainSizer = wx.BoxSizer(wx.VERTICAL)
|
||||
|
||||
contents = AmmoPickerContents(self, fit)
|
||||
mainSizer.Add(contents, 1, wx.EXPAND | wx.ALL, padding)
|
||||
|
||||
buttonSizer = self.CreateButtonSizer(wx.OK | wx.CANCEL)
|
||||
if buttonSizer:
|
||||
mainSizer.Add(buttonSizer, 0, wx.EXPAND | wx.ALL, padding)
|
||||
|
||||
self.SetSizer(mainSizer)
|
||||
self.Layout()
|
||||
|
||||
contW, contH = contents.GetVirtualSize()
|
||||
bestW = contW + padding * 2
|
||||
bestH = contH + padding * 2
|
||||
if buttonSizer:
|
||||
# Yeah right... whatever
|
||||
buttW, buttH = buttonSizer.GetSize()
|
||||
bestW = max(bestW, buttW + padding * 2)
|
||||
bestH += buttH + padding * 2
|
||||
bestW = min(1000, bestW)
|
||||
bestH = min(700, bestH)
|
||||
self.SetSize(bestW, bestH)
|
||||
self.SetMinSize(wx.Size(int(bestW * 0.7), int(bestH * 0.7)))
|
||||
self.CenterOnParent()
|
||||
self.Bind(wx.EVT_CHAR_HOOK, self.kbEvent)
|
||||
|
||||
def kbEvent(self, event):
|
||||
if event.GetKeyCode() == wx.WXK_ESCAPE and event.GetModifiers() == wx.MOD_NONE:
|
||||
self.Close()
|
||||
return
|
||||
event.Skip()
|
||||
|
||||
|
||||
class AmmoPickerContents(wx.ScrolledCanvas):
|
||||
|
||||
indent = 15
|
||||
|
||||
def __init__(self, parent, fit):
|
||||
wx.ScrolledCanvas.__init__(self, parent)
|
||||
self.SetScrollRate(0, 15)
|
||||
|
||||
mods = self.getMods(fit)
|
||||
drones = self.getDrones(fit)
|
||||
fighters = self.getFighters(fit)
|
||||
self.rbLabelMap = {}
|
||||
self.rbCheckboxMap = {}
|
||||
|
||||
mainSizer = wx.BoxSizer(wx.VERTICAL)
|
||||
|
||||
moduleSizer = wx.BoxSizer(wx.VERTICAL)
|
||||
mainSizer.Add(moduleSizer, 0, wx.ALL, 0)
|
||||
|
||||
self.droneSizer = wx.BoxSizer(wx.VERTICAL)
|
||||
mainSizer.Add(self.droneSizer, 0, wx.ALL, 0)
|
||||
|
||||
fighterSizer = wx.BoxSizer(wx.VERTICAL)
|
||||
mainSizer.Add(fighterSizer, 0, wx.ALL, 0)
|
||||
|
||||
firstRadio = True
|
||||
|
||||
for modInfo, modAmmo in mods:
|
||||
text = '\n'.join('{}x {}'.format(amount, item.name) for item, amount in modInfo)
|
||||
modRb = self.addRadioButton(moduleSizer, text, firstRadio)
|
||||
firstRadio = False
|
||||
# Get actual module, as ammo getters need it
|
||||
mod = next((m for m in fit.modules if m.itemID == next(iter(modInfo))[0].ID), None)
|
||||
_, ammoTree = Ammo.getInstance().getModuleStructuredAmmo(mod)
|
||||
if len(ammoTree) == 1:
|
||||
for ammoCatName, ammos in ammoTree.items():
|
||||
for ammo in ammos:
|
||||
self.addCheckbox(moduleSizer, ammo.name, modRb, indentLvl=1)
|
||||
else:
|
||||
for ammoCatName, ammos in ammoTree.items():
|
||||
if len(ammos) == 1:
|
||||
ammo = next(iter(ammos))
|
||||
self.addCheckbox(moduleSizer, ammo.name, modRb, indentLvl=1)
|
||||
else:
|
||||
self.addLabel(moduleSizer, '{}:'.format(ammoCatName), modRb, indentLvl=1)
|
||||
for ammo in ammos:
|
||||
self.addCheckbox(moduleSizer, ammo.name, modRb, indentLvl=2)
|
||||
if drones:
|
||||
droneRb = self.addRadioButton(self.droneSizer, 'Drones', firstRadio)
|
||||
from gui.builtinAdditionPanes.droneView import DroneView
|
||||
for drone in sorted(drones, key=DroneView.droneKey):
|
||||
self.addCheckbox(self.droneSizer, '{}x {}'.format(drone.amount, drone.item.name), droneRb, indentLvl=1)
|
||||
addBtn = wx.Button(self, wx.ID_ANY, '+', style=wx.BU_EXACTFIT)
|
||||
addBtn.Bind(wx.EVT_BUTTON, self.OnDroneGroupAdd)
|
||||
mainSizer.Add(addBtn, 0, wx.LEFT, self.indent)
|
||||
if fighters:
|
||||
fighterRb = self.addRadioButton(fighterSizer, 'Fighters', firstRadio)
|
||||
from gui.builtinAdditionPanes.fighterView import FighterDisplay
|
||||
for fighter in sorted(fighters, key=FighterDisplay.fighterKey):
|
||||
self.addCheckbox(fighterSizer, '{}x {}'.format(fighter.amount, fighter.item.name), fighterRb, indentLvl=1)
|
||||
|
||||
self.SetSizer(mainSizer)
|
||||
self.refreshStatus()
|
||||
|
||||
def addRadioButton(self, sizer, text, firstRadio=False):
|
||||
if firstRadio:
|
||||
rb = wx.RadioButton(self, wx.ID_ANY, text, style=wx.RB_GROUP)
|
||||
rb.SetValue(True)
|
||||
else:
|
||||
rb = wx.RadioButton(self, wx.ID_ANY, text)
|
||||
rb.SetValue(False)
|
||||
rb.Bind(wx.EVT_RADIOBUTTON, self.rbSelected)
|
||||
sizer.Add(rb, 0, wx.EXPAND | wx.ALL, 0)
|
||||
return rb
|
||||
|
||||
def addCheckbox(self, sizer, text, currentRb, indentLvl=0):
|
||||
cb = wx.CheckBox(self, -1, text)
|
||||
sizer.Add(cb, 0, wx.EXPAND | wx.LEFT, self.indent * indentLvl)
|
||||
if currentRb is not None:
|
||||
self.rbCheckboxMap.setdefault(currentRb, []).append(cb)
|
||||
|
||||
def addLabel(self, sizer, text, currentRb, indentLvl=0):
|
||||
text = text[0].capitalize() + text[1:]
|
||||
label = wx.StaticText(self, wx.ID_ANY, text)
|
||||
sizer.Add(label, 0, wx.EXPAND | wx.LEFT, self.indent * indentLvl)
|
||||
if currentRb is not None:
|
||||
self.rbLabelMap.setdefault(currentRb, []).append(label)
|
||||
|
||||
def getMods(self, fit):
|
||||
sMkt = Market.getInstance()
|
||||
sAmmo = Ammo.getInstance()
|
||||
loadableChargesCache = {}
|
||||
# Modules, format: {frozenset(ammo): {item: count}}
|
||||
modsPrelim = {}
|
||||
if fit is not None:
|
||||
for mod in fit.modules:
|
||||
if not mod.canDealDamage():
|
||||
continue
|
||||
typeID = mod.item.ID
|
||||
if typeID not in loadableChargesCache:
|
||||
loadableChargesCache[typeID] = sAmmo.getModuleFlatAmmo(mod)
|
||||
charges = loadableChargesCache[typeID]
|
||||
# We're not interested in modules which contain no charges
|
||||
if charges:
|
||||
data = modsPrelim.setdefault(frozenset(charges), {})
|
||||
if mod.item not in data:
|
||||
data[mod.item] = 0
|
||||
data[mod.item] += 1
|
||||
# Format: [([(item, count), ...], frozenset(ammo)), ...]
|
||||
modsFinal = []
|
||||
for charges, itemCounts in modsPrelim.items():
|
||||
modsFinal.append((
|
||||
# Sort items within group
|
||||
sorted(itemCounts.items(), key=lambda i: sMkt.itemSort(i[0], reverseMktGrp=True), reverse=True),
|
||||
charges))
|
||||
# Sort item groups
|
||||
modsFinal.sort(key=lambda i: sMkt.itemSort(i[0][0][0], reverseMktGrp=True), reverse=True)
|
||||
return modsFinal
|
||||
|
||||
def getDrones(self, fit):
|
||||
drones = []
|
||||
if fit is not None:
|
||||
for drone in fit.drones:
|
||||
if drone.item is None:
|
||||
continue
|
||||
# Drones are our "ammo", so we want to pick even those which are inactive
|
||||
if drone.canDealDamage(ignoreState=True):
|
||||
drones.append(drone)
|
||||
continue
|
||||
if {'remoteWebifierEntity', 'remoteTargetPaintEntity'}.intersection(drone.item.effects):
|
||||
drones.append(drone)
|
||||
continue
|
||||
return drones
|
||||
|
||||
def getFighters(self, fit):
|
||||
fighters = []
|
||||
if fit is not None:
|
||||
for fighter in fit.fighters:
|
||||
if fighter.item is None:
|
||||
continue
|
||||
# Fighters are our "ammo" as well
|
||||
if fighter.canDealDamage(ignoreState=True):
|
||||
fighters.append(fighter)
|
||||
continue
|
||||
for ability in fighter.abilities:
|
||||
if not ability.active:
|
||||
continue
|
||||
if ability.effect.name == 'fighterAbilityStasisWebifier':
|
||||
fighters.append(fighter)
|
||||
break
|
||||
return fighters
|
||||
|
||||
def OnDroneGroupAdd(self, event):
|
||||
event.Skip()
|
||||
sizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
label = wx.StaticText()
|
||||
self.droneSizer.Add(sizer, 0, wx.EXPAND | wx.LEFT, self.indent)
|
||||
|
||||
def refreshStatus(self):
|
||||
for map in (self.rbLabelMap, self.rbCheckboxMap):
|
||||
for rb, items in map.items():
|
||||
for item in items:
|
||||
item.Enable(rb.GetValue())
|
||||
|
||||
def rbSelected(self, event):
|
||||
event.Skip()
|
||||
self.refreshStatus()
|
||||
@@ -3,33 +3,28 @@ import wx
|
||||
|
||||
import gui.fitCommands as cmd
|
||||
import gui.mainFrame
|
||||
from eos.const import FittingHardpoint
|
||||
from eos.saveddata.module import Module
|
||||
from gui.bitmap_loader import BitmapLoader
|
||||
from gui.contextMenu import ContextMenuCombined
|
||||
from gui.fitCommands.helpers import getSimilarModPositions
|
||||
from service.ammo import Ammo
|
||||
from service.fit import Fit
|
||||
from service.market import Market
|
||||
|
||||
|
||||
class ChangeModuleAmmo(ContextMenuCombined):
|
||||
|
||||
DAMAGE_TYPES = ("em", "explosive", "kinetic", "thermal")
|
||||
MISSILE_ORDER = ("em", "thermal", "kinetic", "explosive", "mixed")
|
||||
|
||||
def __init__(self):
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
# Format: {type ID: set(loadable, charges)}
|
||||
self.loadableCharges = {}
|
||||
self.loadableChargesCache = {}
|
||||
|
||||
def display(self, callingWindow, srcContext, mainItem, selection):
|
||||
if srcContext not in ("fittingModule", "projectedModule"):
|
||||
if srcContext not in ('fittingModule', 'projectedModule'):
|
||||
return False
|
||||
|
||||
if self.mainFrame.getActiveFit() is None:
|
||||
return False
|
||||
|
||||
self.mainCharges = self.getChargesForMod(mainItem)
|
||||
self.mainCharges = self._getAmmo(mainItem)
|
||||
if not self.mainCharges:
|
||||
return False
|
||||
|
||||
@@ -39,186 +34,81 @@ class ChangeModuleAmmo(ContextMenuCombined):
|
||||
return True
|
||||
|
||||
def getText(self, callingWindow, itmContext, mainItem, selection):
|
||||
return "Charge"
|
||||
return 'Charge'
|
||||
|
||||
def getChargesForMod(self, mod):
|
||||
sMkt = Market.getInstance()
|
||||
if mod is None or mod.isEmpty:
|
||||
def _getAmmo(self, mod):
|
||||
if mod.itemID is None:
|
||||
return set()
|
||||
typeID = mod.item.ID
|
||||
if typeID in self.loadableCharges:
|
||||
return self.loadableCharges[typeID]
|
||||
chargeSet = self.loadableCharges.setdefault(typeID, set())
|
||||
# Do not try to grab it for modes which can also be passed as part of selection
|
||||
if isinstance(mod, Module):
|
||||
for charge in mod.getValidCharges():
|
||||
if sMkt.getPublicityByItem(charge):
|
||||
chargeSet.add(charge)
|
||||
return chargeSet
|
||||
if mod.itemID not in self.loadableChargesCache:
|
||||
self.loadableChargesCache[mod.itemID] = Ammo.getInstance().getModuleFlatAmmo(mod)
|
||||
return self.loadableChargesCache[mod.itemID]
|
||||
|
||||
def turretSorter(self, charge):
|
||||
damage = 0
|
||||
range_ = (self.module.item.getAttribute("maxRange")) * \
|
||||
(charge.getAttribute("weaponRangeMultiplier") or 1)
|
||||
falloff = (self.module.item.getAttribute("falloff") or 0) * \
|
||||
(charge.getAttribute("fallofMultiplier") or 1)
|
||||
for type_ in self.DAMAGE_TYPES:
|
||||
d = charge.getAttribute("%sDamage" % type_)
|
||||
if d > 0:
|
||||
damage += d
|
||||
|
||||
# Take optimal and falloff as range factor
|
||||
rangeFactor = range_ + falloff
|
||||
|
||||
return - rangeFactor, charge.name.rsplit()[-2:], damage, charge.name
|
||||
|
||||
def missileSorter(self, charge):
|
||||
# Get charge damage type and total damage
|
||||
chargeDamageType, totalDamage = self.damageInfo(charge)
|
||||
# Find its position in sort list
|
||||
position = self.MISSILE_ORDER.index(chargeDamageType)
|
||||
return position, totalDamage, charge.name
|
||||
|
||||
def damageInfo(self, charge):
|
||||
# Set up data storage for missile damage stuff
|
||||
damageMap = {}
|
||||
totalDamage = 0
|
||||
# Fill them with the data about charge
|
||||
for damageType in self.DAMAGE_TYPES:
|
||||
currentDamage = charge.getAttribute("{0}Damage".format(damageType)) or 0
|
||||
damageMap[damageType] = currentDamage
|
||||
totalDamage += currentDamage
|
||||
# Detect type of ammo
|
||||
chargeDamageType = None
|
||||
for damageType in damageMap:
|
||||
# If all damage belongs to certain type purely, set appropriate
|
||||
# ammoType
|
||||
if damageMap[damageType] == totalDamage:
|
||||
chargeDamageType = damageType
|
||||
break
|
||||
# Else consider ammo as mixed damage
|
||||
if chargeDamageType is None:
|
||||
chargeDamageType = "mixed"
|
||||
|
||||
return chargeDamageType, totalDamage
|
||||
|
||||
@staticmethod
|
||||
def numericConverter(string):
|
||||
return int(string) if string.isdigit() else string
|
||||
|
||||
def nameSorter(self, charge):
|
||||
parts = charge.name.split(" ")
|
||||
return list(map(self.numericConverter, parts))
|
||||
|
||||
def addCharge(self, menu, charge):
|
||||
def _addCharge(self, menu, charge):
|
||||
id_ = ContextMenuCombined.nextID()
|
||||
name = charge.name if charge is not None else "Empty"
|
||||
self.chargeIds[id_] = charge
|
||||
name = charge.name if charge is not None else 'Empty'
|
||||
self.chargeEventMap[id_] = charge
|
||||
item = wx.MenuItem(menu, id_, name)
|
||||
menu.Bind(wx.EVT_MENU, self.handleAmmoSwitch, item)
|
||||
item.charge = charge
|
||||
if charge is not None and charge.iconID is not None:
|
||||
bitmap = BitmapLoader.getBitmap(charge.iconID, "icons")
|
||||
bitmap = BitmapLoader.getBitmap(charge.iconID, 'icons')
|
||||
if bitmap is not None:
|
||||
item.SetBitmap(bitmap)
|
||||
|
||||
return item
|
||||
|
||||
@staticmethod
|
||||
def addSeperator(m, text):
|
||||
def _addSeparator(m, text):
|
||||
id_ = ContextMenuCombined.nextID()
|
||||
m.Append(id_, '─ %s ─' % text)
|
||||
m.Enable(id_, False)
|
||||
|
||||
def getSubMenu(self, callingWindow, context, mainItem, selection, rootMenu, i, pitem):
|
||||
msw = True if "wxMSW" in wx.PlatformInfo else False
|
||||
m = wx.Menu()
|
||||
self.chargeIds = {}
|
||||
hardpoint = self.module.hardpoint
|
||||
moduleName = self.module.item.name
|
||||
# Make sure we do not consider mining turrets as combat turrets
|
||||
if hardpoint == FittingHardpoint.TURRET and self.module.getModifiedItemAttr("miningAmount", None) is None:
|
||||
self.addSeperator(m, "Long Range")
|
||||
items = []
|
||||
range_ = None
|
||||
nameBase = None
|
||||
sub = None
|
||||
chargesSorted = sorted(self.mainCharges, key=self.turretSorter)
|
||||
for charge in chargesSorted:
|
||||
if "civilian" in charge.name.lower():
|
||||
continue
|
||||
currBase = charge.name.rsplit()[-2:]
|
||||
currRange = charge.getAttribute("weaponRangeMultiplier")
|
||||
if nameBase is None or range_ != currRange or nameBase != currBase:
|
||||
if sub is not None:
|
||||
self.addSeperator(sub, "More Damage")
|
||||
|
||||
sub = None
|
||||
base = charge
|
||||
nameBase = currBase
|
||||
range_ = currRange
|
||||
item = self.addCharge(rootMenu if msw else m, charge)
|
||||
items.append(item)
|
||||
msw = True if 'wxMSW' in wx.PlatformInfo else False
|
||||
menu = wx.Menu()
|
||||
self.chargeEventMap = {}
|
||||
modType, chargeDict = Ammo.getInstance().getModuleStructuredAmmo(self.module, ammo=self.mainCharges)
|
||||
if modType == 'ddTurret':
|
||||
self._addSeparator(menu, 'Long Range')
|
||||
menuItems = []
|
||||
for charges in chargeDict.values():
|
||||
if len(charges) == 1:
|
||||
menuItems.append(self._addCharge(rootMenu if msw else menu, charges[0]))
|
||||
else:
|
||||
if sub is None and item and base:
|
||||
sub = wx.Menu()
|
||||
sub.Bind(wx.EVT_MENU, self.handleAmmoSwitch)
|
||||
self.addSeperator(sub, "Less Damage")
|
||||
item.SetSubMenu(sub)
|
||||
sub.Append(self.addCharge(rootMenu if msw else sub, base))
|
||||
|
||||
sub.Append(self.addCharge(rootMenu if msw else sub, charge))
|
||||
|
||||
if sub is not None:
|
||||
self.addSeperator(sub, "More Damage")
|
||||
|
||||
for item in items:
|
||||
m.Append(item)
|
||||
|
||||
self.addSeperator(m, "Short Range")
|
||||
elif hardpoint == FittingHardpoint.MISSILE and moduleName != 'Festival Launcher':
|
||||
type_ = None
|
||||
sub = None
|
||||
defender = None
|
||||
chargesSorted = sorted(self.mainCharges, key=self.missileSorter)
|
||||
for charge in chargesSorted:
|
||||
currType = self.damageInfo(charge)[0]
|
||||
|
||||
if currType != type_ or type_ is None:
|
||||
if sub is not None:
|
||||
self.addSeperator(sub, "More Damage")
|
||||
|
||||
type_ = currType
|
||||
item = wx.MenuItem(m, wx.ID_ANY, type_.capitalize())
|
||||
bitmap = BitmapLoader.getBitmap("%s_small" % type_, "gui")
|
||||
if bitmap is not None:
|
||||
item.SetBitmap(bitmap)
|
||||
|
||||
sub = wx.Menu()
|
||||
sub.Bind(wx.EVT_MENU, self.handleAmmoSwitch)
|
||||
self.addSeperator(sub, "Less Damage")
|
||||
item.SetSubMenu(sub)
|
||||
m.Append(item)
|
||||
|
||||
if charge.name not in ("Light Defender Missile I", "Heavy Defender Missile I"):
|
||||
sub.Append(self.addCharge(rootMenu if msw else sub, charge))
|
||||
else:
|
||||
defender = charge
|
||||
|
||||
if defender is not None:
|
||||
m.Append(self.addCharge(rootMenu if msw else m, defender))
|
||||
if sub is not None:
|
||||
self.addSeperator(sub, "More Damage")
|
||||
else:
|
||||
chargesSorted = sorted(self.mainCharges, key=self.nameSorter)
|
||||
for charge in chargesSorted:
|
||||
m.Append(self.addCharge(rootMenu if msw else m, charge))
|
||||
|
||||
m.Append(self.addCharge(rootMenu if msw else m, None))
|
||||
return m
|
||||
baseCharge = charges[0]
|
||||
menuItem = self._addCharge(rootMenu if msw else menu, baseCharge)
|
||||
menuItems.append(menuItem)
|
||||
subMenu = wx.Menu()
|
||||
subMenu.Bind(wx.EVT_MENU, self.handleAmmoSwitch)
|
||||
menuItem.SetSubMenu(subMenu)
|
||||
self._addSeparator(subMenu, 'Less Damage')
|
||||
for charge in charges:
|
||||
subMenu.Append(self._addCharge(rootMenu if msw else subMenu, charge))
|
||||
self._addSeparator(subMenu, 'More Damage')
|
||||
for menuItem in menuItems:
|
||||
menu.Append(menuItem)
|
||||
self._addSeparator(menu, 'Short Range')
|
||||
elif modType == 'ddMissile':
|
||||
menuItems = []
|
||||
for chargeCatName, charges in chargeDict.items():
|
||||
menuItem = wx.MenuItem(menu, wx.ID_ANY, chargeCatName.capitalize())
|
||||
menuItems.append(menuItem)
|
||||
subMenu = wx.Menu()
|
||||
subMenu.Bind(wx.EVT_MENU, self.handleAmmoSwitch)
|
||||
menuItem.SetSubMenu(subMenu)
|
||||
self._addSeparator(subMenu, 'Less Damage')
|
||||
for charge in charges:
|
||||
subMenu.Append(self._addCharge(rootMenu if msw else subMenu, charge))
|
||||
self._addSeparator(subMenu, 'More Damage')
|
||||
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))
|
||||
menu.Append(self._addCharge(rootMenu if msw else menu, None))
|
||||
return menu
|
||||
|
||||
def handleAmmoSwitch(self, event):
|
||||
charge = self.chargeIds.get(event.Id, False)
|
||||
charge = self.chargeEventMap.get(event.Id, False)
|
||||
if charge is False:
|
||||
event.Skip()
|
||||
return
|
||||
@@ -254,7 +144,7 @@ class ChangeModuleAmmo(ContextMenuCombined):
|
||||
positions = []
|
||||
for position, mod in enumerate(modContainer):
|
||||
if mod in self.selection:
|
||||
modCharges = self.getChargesForMod(mod)
|
||||
modCharges = self._getAmmo(mod)
|
||||
if modCharges.issubset(self.mainCharges):
|
||||
positions.append(position)
|
||||
self.mainFrame.command.Submit(command(
|
||||
|
||||
@@ -35,7 +35,7 @@ class ItemDescription(wx.Panel):
|
||||
self.Layout()
|
||||
|
||||
self.description.Bind(wx.EVT_CONTEXT_MENU, self.onPopupMenu)
|
||||
self.description.Bind(wx.EVT_KEY_DOWN, self.onKeyDown)
|
||||
self.description.Bind(wx.EVT_KEY_UP, self.onKeyUp)
|
||||
|
||||
self.popupMenu = wx.Menu()
|
||||
copyItem = wx.MenuItem(self.popupMenu, 1, 'Copy')
|
||||
@@ -50,7 +50,7 @@ class ItemDescription(wx.Panel):
|
||||
if selectedMenuItem == 1: # Copy was chosen
|
||||
self.copySelectionToClipboard()
|
||||
|
||||
def onKeyDown(self, event):
|
||||
def onKeyUp(self, event):
|
||||
keyCode = event.GetKeyCode()
|
||||
# Ctrl + C
|
||||
if keyCode == 67 and event.ControlDown():
|
||||
|
||||
@@ -14,7 +14,7 @@ class ItemTraits(wx.Panel):
|
||||
self.traits.SetPage(item.traits.traitText)
|
||||
|
||||
self.traits.Bind(wx.EVT_CONTEXT_MENU, self.onPopupMenu)
|
||||
self.traits.Bind(wx.EVT_KEY_DOWN, self.onKeyDown)
|
||||
self.traits.Bind(wx.EVT_KEY_UP, self.onKeyUp)
|
||||
|
||||
mainSizer.Add(self.traits, 1, wx.ALL | wx.EXPAND, 0)
|
||||
self.Layout()
|
||||
@@ -32,7 +32,7 @@ class ItemTraits(wx.Panel):
|
||||
if selectedMenuItem == 1: # Copy was chosen
|
||||
self.copySelectionToClipboard()
|
||||
|
||||
def onKeyDown(self, event):
|
||||
def onKeyUp(self, event):
|
||||
keyCode = event.GetKeyCode()
|
||||
# Ctrl + C
|
||||
if keyCode == 67 and event.ControlDown():
|
||||
|
||||
@@ -203,22 +203,6 @@ class ItemView(Display):
|
||||
self.setToggles()
|
||||
self.filterItemStore()
|
||||
|
||||
def itemSort(self, item):
|
||||
sMkt = self.sMkt
|
||||
catname = sMkt.getCategoryByItem(item).name
|
||||
try:
|
||||
mktgrpid = sMkt.getMarketGroupByItem(item).ID
|
||||
except AttributeError:
|
||||
mktgrpid = -1
|
||||
pyfalog.warning("unable to find market group for {}".format(item.name))
|
||||
parentname = sMkt.getParentItemByItem(item).name
|
||||
# Get position of market group
|
||||
metagrpid = sMkt.getMetaGroupIdByItem(item)
|
||||
metatab = sMkt.META_MAP_REVERSE_INDICES.get(metagrpid)
|
||||
metalvl = item.metaLevel or 0
|
||||
|
||||
return catname, mktgrpid, parentname, metatab, metalvl, item.name
|
||||
|
||||
def contextMenu(self, event):
|
||||
clickedPos = self.getRowByAbs(event.Position)
|
||||
self.ensureSelection(clickedPos)
|
||||
@@ -241,7 +225,7 @@ class ItemView(Display):
|
||||
self.unselectAll()
|
||||
# Perform sorting, using item's meta levels besides other stuff
|
||||
if self.marketBrowser.mode != 'recent':
|
||||
items.sort(key=self.itemSort)
|
||||
items.sort(key=self.sMkt.itemSort)
|
||||
# Mark current item list as active
|
||||
self.active = items
|
||||
# Show them
|
||||
@@ -251,12 +235,10 @@ class ItemView(Display):
|
||||
if len(items) > 1:
|
||||
# Re-sort stuff
|
||||
if self.marketBrowser.mode != 'recent':
|
||||
items.sort(key=self.itemSort)
|
||||
|
||||
items.sort(key=self.sMkt.itemSort)
|
||||
for i, item in enumerate(items[:9]):
|
||||
# set shortcut info for first 9 modules
|
||||
item.marketShortcut = i + 1
|
||||
|
||||
Display.refresh(self, items)
|
||||
|
||||
def columnBackground(self, colItem, item):
|
||||
|
||||
@@ -60,7 +60,8 @@ class MarketTree(wx.TreeCtrl):
|
||||
# If market should have items but it doesn't, do not show it
|
||||
if sMkt.marketGroupValidityCheck(childMktGrp) is False:
|
||||
continue
|
||||
iconId = self.addImage(sMkt.getIconByMarketGroup(childMktGrp))
|
||||
icon = sMkt.getIconByMarketGroup(childMktGrp)
|
||||
iconId = -1 if icon is None else self.addImage(icon)
|
||||
try:
|
||||
childId = self.AppendItem(root, childMktGrp.name, iconId, data=childMktGrp.ID)
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
|
||||
@@ -86,7 +86,7 @@ class PFSearchBox(wx.Window):
|
||||
|
||||
def OnKeyPress(self, event):
|
||||
if event.RawControlDown() and event.GetKeyCode() == wx.WXK_BACK:
|
||||
HandleCtrlBackspace(self.EditBox)
|
||||
HandleCtrlBackspace(self.EditBox)
|
||||
else:
|
||||
event.Skip()
|
||||
|
||||
|
||||
@@ -123,6 +123,15 @@ class Miscellanea(ViewColumn):
|
||||
text = ' | '.join(i[0] for i in info)
|
||||
tooltip = ' and '.join(i[1] for i in info).capitalize()
|
||||
return text, tooltip
|
||||
elif itemGroup == "Vorton Projector":
|
||||
cloudSize = stuff.getModifiedItemAttr("aoeCloudSize")
|
||||
aoeVelocity = stuff.getModifiedItemAttr("aoeVelocity")
|
||||
if not cloudSize or not aoeVelocity:
|
||||
return "", None
|
||||
text = "{0}{1} | {2}{3}".format(formatAmount(cloudSize, 3, 0, 3), "m",
|
||||
formatAmount(aoeVelocity, 3, 0, 3), "m/s")
|
||||
tooltip = "Explosion radius and explosion velocity"
|
||||
return text, tooltip
|
||||
elif itemCategory == "Subsystem":
|
||||
slots = ("hi", "med", "low")
|
||||
info = []
|
||||
@@ -133,7 +142,7 @@ class Miscellanea(ViewColumn):
|
||||
return "+ " + ", ".join(info), "Slot Modifiers"
|
||||
elif (
|
||||
itemGroup in ("Energy Neutralizer", "Structure Energy Neutralizer") or
|
||||
(itemGroup == "Structure Burst Projector" and "doomsdayAOENeut" in item.effects)
|
||||
(itemGroup in ("Structure Burst Projector", "Burst Projectors") and "doomsdayAOENeut" in item.effects)
|
||||
):
|
||||
neutAmount = stuff.getModifiedItemAttr("energyNeutralizerAmount")
|
||||
cycleParams = stuff.getCycleParameters()
|
||||
@@ -182,7 +191,7 @@ class Miscellanea(ViewColumn):
|
||||
return text, tooltip
|
||||
elif (
|
||||
itemGroup in ("Stasis Web", "Stasis Webifying Drone", "Structure Stasis Webifier") or
|
||||
(itemGroup == "Structure Burst Projector" and "doomsdayAOEWeb" in item.effects)
|
||||
(itemGroup in ("Structure Burst Projector", "Burst Projectors") and "doomsdayAOEWeb" in item.effects)
|
||||
):
|
||||
speedFactor = stuff.getModifiedItemAttr("speedFactor")
|
||||
if not speedFactor:
|
||||
@@ -193,7 +202,7 @@ class Miscellanea(ViewColumn):
|
||||
elif (
|
||||
itemGroup == "Target Painter" or
|
||||
(itemGroup == "Structure Disruption Battery" and "structureModuleEffectTargetPainter" in item.effects) or
|
||||
(itemGroup == "Structure Burst Projector" and "doomsdayAOEPaint" in item.effects)
|
||||
(itemGroup in ("Structure Burst Projector", "Burst Projectors") and "doomsdayAOEPaint" in item.effects)
|
||||
):
|
||||
sigRadBonus = stuff.getModifiedItemAttr("signatureRadiusBonus")
|
||||
if not sigRadBonus:
|
||||
@@ -204,7 +213,7 @@ class Miscellanea(ViewColumn):
|
||||
elif (
|
||||
itemGroup == "Sensor Dampener" or
|
||||
(itemGroup == "Structure Disruption Battery" and "structureModuleEffectRemoteSensorDampener" in item.effects) or
|
||||
(itemGroup == "Structure Burst Projector" and "doomsdayAOEDamp" in item.effects)
|
||||
(itemGroup in ("Structure Burst Projector", "Burst Projectors") and "doomsdayAOEDamp" in item.effects)
|
||||
):
|
||||
lockRangeBonus = stuff.getModifiedItemAttr("maxTargetRangeBonus")
|
||||
scanResBonus = stuff.getModifiedItemAttr("scanResolutionBonus")
|
||||
@@ -226,7 +235,7 @@ class Miscellanea(ViewColumn):
|
||||
return text, tooltip
|
||||
elif (
|
||||
itemGroup in ("Weapon Disruptor", "Structure Disruption Battery") or
|
||||
(itemGroup == "Structure Burst Projector" and "doomsdayAOETrack" in item.effects)
|
||||
(itemGroup in ("Structure Burst Projector", "Burst Projectors") and "doomsdayAOETrack" in item.effects)
|
||||
):
|
||||
# Weapon disruption now covers both tracking and guidance (missile) disruptors
|
||||
# First get the attributes for tracking disruptors
|
||||
@@ -279,7 +288,8 @@ class Miscellanea(ViewColumn):
|
||||
"Heat Sink",
|
||||
"Ballistic Control system",
|
||||
"Structure Weapon Upgrade",
|
||||
"Entropic Radiation Sink"
|
||||
"Entropic Radiation Sink",
|
||||
"Vorton Projector Upgrade"
|
||||
):
|
||||
attrMap = {
|
||||
"Gyrostabilizer": ("damageMultiplier", "speedMultiplier", "Projectile weapon"),
|
||||
@@ -287,7 +297,8 @@ class Miscellanea(ViewColumn):
|
||||
"Heat Sink": ("damageMultiplier", "speedMultiplier", "Energy weapon"),
|
||||
"Ballistic Control system": ("missileDamageMultiplierBonus", "speedMultiplier", "Missile"),
|
||||
"Structure Weapon Upgrade": ("missileDamageMultiplierBonus", "speedMultiplier", "Missile"),
|
||||
"Entropic Radiation Sink": ("damageMultiplier", "speedMultiplier", "Precursor weapon")}
|
||||
"Entropic Radiation Sink": ("damageMultiplier", "speedMultiplier", "Precursor weapon"),
|
||||
"Vorton Projector Upgrade": ("damageMultiplier", "speedMultiplier", "Vorton projector")}
|
||||
dmgAttr, rofAttr, weaponName = attrMap[itemGroup]
|
||||
dmg = stuff.getModifiedItemAttr(dmgAttr)
|
||||
rof = stuff.getModifiedItemAttr(rofAttr)
|
||||
@@ -311,8 +322,8 @@ class Miscellanea(ViewColumn):
|
||||
tooltip = "Drone DPS boost"
|
||||
return text, tooltip
|
||||
elif (
|
||||
itemGroup in ("ECM", "Burst Jammer", "Burst Projectors", "Structure ECM Battery") or
|
||||
(itemGroup == "Structure Burst Projector" and "doomsdayAOEECM" in item.effects)
|
||||
itemGroup in ("ECM", "Burst Jammer", "Structure ECM Battery") or
|
||||
(itemGroup in ("Structure Burst Projector", "Burst Projectors") and "doomsdayAOEECM" in item.effects)
|
||||
):
|
||||
grav = stuff.getModifiedItemAttr("scanGravimetricStrengthBonus")
|
||||
ladar = stuff.getModifiedItemAttr("scanLadarStrengthBonus")
|
||||
|
||||
@@ -166,7 +166,7 @@ class FittingView(d.Display):
|
||||
self.hoveredRow = None
|
||||
self.hoveredColumn = None
|
||||
|
||||
self.Bind(wx.EVT_KEY_DOWN, self.kbEvent)
|
||||
self.Bind(wx.EVT_KEY_UP, self.kbEvent)
|
||||
self.Bind(wx.EVT_LEFT_DOWN, self.click)
|
||||
self.Bind(wx.EVT_RIGHT_DOWN, self.click)
|
||||
self.Bind(wx.EVT_MIDDLE_DOWN, self.click)
|
||||
|
||||
@@ -34,7 +34,7 @@ from wx.lib.agw.floatspin import FloatSpin
|
||||
|
||||
import config
|
||||
import gui.globalEvents as GE
|
||||
from gui.auxFrame import AuxiliaryFrame
|
||||
from gui.auxWindow import AuxiliaryFrame
|
||||
from gui.bitmap_loader import BitmapLoader
|
||||
from gui.builtinViews.entityEditor import BaseValidator, EntityEditor, TextEntryValidatedDialog
|
||||
from gui.builtinViews.implantEditor import BaseImplantEditorView
|
||||
|
||||
@@ -26,7 +26,7 @@ import wx
|
||||
from logbook import Logger
|
||||
|
||||
import eos.db
|
||||
from gui.auxFrame import AuxiliaryFrame
|
||||
from gui.auxWindow import AuxiliaryFrame
|
||||
from gui.builtinShipBrowser.events import FitSelected
|
||||
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ import wx
|
||||
from logbook import Logger
|
||||
|
||||
import config
|
||||
from gui.auxFrame import AuxiliaryFrame
|
||||
from gui.auxWindow import AuxiliaryFrame
|
||||
from service.prereqsCheck import version_block
|
||||
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import config
|
||||
import gui.globalEvents as GE
|
||||
from eos.db import getItem
|
||||
from eos.saveddata.cargo import Cargo
|
||||
from gui.auxFrame import AuxiliaryFrame
|
||||
from gui.auxWindow import AuxiliaryFrame
|
||||
from gui.display import Display
|
||||
from gui.characterEditor import APIView
|
||||
from service.character import Character
|
||||
|
||||
@@ -23,7 +23,7 @@ import wx
|
||||
import config
|
||||
import gui.mainFrame
|
||||
from eos.saveddata.module import Module
|
||||
from gui.auxFrame import AuxiliaryFrame
|
||||
from gui.auxWindow import AuxiliaryFrame
|
||||
from gui.bitmap_loader import BitmapLoader
|
||||
from gui.builtinItemStatsViews.itemAffectedBy import ItemAffectedBy
|
||||
from gui.builtinItemStatsViews.itemAttributes import ItemParams
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
import wx
|
||||
from logbook import Logger
|
||||
|
||||
from gui.auxFrame import AuxiliaryFrame
|
||||
from gui.auxWindow import AuxiliaryFrame
|
||||
from gui.bitmap_loader import BitmapLoader
|
||||
from gui.builtinViews.entityEditor import BaseValidator, EntityEditor
|
||||
from gui.utils.clipboard import fromClipboard, toClipboard
|
||||
|
||||
@@ -10,7 +10,7 @@ import gui.builtinMarketBrowser.pfSearchBox as SBox
|
||||
import gui.display as d
|
||||
import gui.globalEvents as GE
|
||||
from eos.db.gamedata.queries import getAttributeInfo, getItem
|
||||
from gui.auxFrame import AuxiliaryFrame
|
||||
from gui.auxWindow import AuxiliaryFrame
|
||||
from gui.bitmap_loader import BitmapLoader
|
||||
from gui.marketBrowser import SearchBox
|
||||
from service.fit import Fit
|
||||
@@ -213,19 +213,7 @@ class ItemView(d.Display):
|
||||
def itemSort(self, item):
|
||||
sMkt = Market.getInstance()
|
||||
isFittable = item.group.name in sMkt.FIT_GROUPS or item.category.name in sMkt.FIT_CATEGORIES
|
||||
catname = sMkt.getCategoryByItem(item).name
|
||||
try:
|
||||
mktgrpid = sMkt.getMarketGroupByItem(item).ID
|
||||
except AttributeError:
|
||||
mktgrpid = -1
|
||||
pyfalog.warning("unable to find market group for {}".format(item.name))
|
||||
parentname = sMkt.getParentItemByItem(item).name
|
||||
# Get position of market group
|
||||
metagrpid = sMkt.getMetaGroupIdByItem(item)
|
||||
metatab = sMkt.META_MAP_REVERSE_INDICES.get(metagrpid)
|
||||
metalvl = item.metaLevel or 0
|
||||
|
||||
return not isFittable, catname, mktgrpid, parentname, metatab, metalvl, item.name
|
||||
return (not isFittable, *sMkt.itemSort(item))
|
||||
|
||||
def populateSearch(self, itemIDs):
|
||||
items = Market.getItems(itemIDs)
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
import wx
|
||||
from logbook import Logger
|
||||
|
||||
from gui.auxFrame import AuxiliaryFrame
|
||||
from gui.auxWindow import AuxiliaryFrame
|
||||
from gui.builtinViews.entityEditor import BaseValidator, EntityEditor
|
||||
from gui.builtinViews.implantEditor import BaseImplantEditorView
|
||||
from gui.utils.clipboard import fromClipboard, toClipboard
|
||||
|
||||
@@ -27,7 +27,7 @@ from logbook import Logger
|
||||
|
||||
import gui.globalEvents as GE
|
||||
import gui.mainFrame
|
||||
from gui.auxFrame import AuxiliaryFrame
|
||||
from gui.auxWindow import AuxiliaryFrame
|
||||
from gui.bitmap_loader import BitmapLoader
|
||||
from gui.builtinViews.entityEditor import BaseValidator, EntityEditor
|
||||
from gui.utils.clipboard import fromClipboard, toClipboard
|
||||
|
||||
|
Before Width: | Height: | Size: 393 B After Width: | Height: | Size: 452 B |
|
Before Width: | Height: | Size: 969 B After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 603 B After Width: | Height: | Size: 703 B |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 605 B After Width: | Height: | Size: 699 B |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 583 B After Width: | Height: | Size: 677 B |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 559 B After Width: | Height: | Size: 701 B |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 604 B After Width: | Height: | Size: 725 B |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 738 B After Width: | Height: | Size: 814 B |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 683 B After Width: | Height: | Size: 781 B |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 699 B After Width: | Height: | Size: 761 B |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 842 B After Width: | Height: | Size: 915 B |
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 842 B After Width: | Height: | Size: 898 B |
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 834 B After Width: | Height: | Size: 894 B |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 762 B After Width: | Height: | Size: 837 B |
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 856 B After Width: | Height: | Size: 938 B |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 858 B After Width: | Height: | Size: 944 B |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 837 B After Width: | Height: | Size: 927 B |
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 884 B After Width: | Height: | Size: 962 B |
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 637 B After Width: | Height: | Size: 696 B |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 931 B After Width: | Height: | Size: 955 B |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 768 B After Width: | Height: | Size: 835 B |
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 851 B After Width: | Height: | Size: 947 B |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 691 B After Width: | Height: | Size: 814 B |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 797 B After Width: | Height: | Size: 894 B |
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 978 B After Width: | Height: | Size: 1022 B |
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 1002 B After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 911 B After Width: | Height: | Size: 937 B |
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 743 B After Width: | Height: | Size: 814 B |
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 650 B After Width: | Height: | Size: 744 B |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 909 B After Width: | Height: | Size: 967 B |
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 935 B After Width: | Height: | Size: 1002 B |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 939 B After Width: | Height: | Size: 1007 B |
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 783 B After Width: | Height: | Size: 863 B |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 711 B After Width: | Height: | Size: 774 B |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 688 B After Width: | Height: | Size: 773 B |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 876 B After Width: | Height: | Size: 931 B |