Merge branch 'master' into attrGroup
# Conflicts: # eos/gamedata.py # eve.db # gui/builtinItemStatsViews/itemAttributes.py
@@ -24,10 +24,10 @@ saveInRoot = False
|
||||
|
||||
# Version data
|
||||
|
||||
version = "2.5.1"
|
||||
version = "2.6.1"
|
||||
tag = "Stable"
|
||||
expansionName = "YC120.10"
|
||||
expansionVersion = "1.0"
|
||||
expansionName = "Onslaught"
|
||||
expansionVersion = "1.5"
|
||||
evemonMinVersion = "4081"
|
||||
|
||||
minItemSearchLength = 3
|
||||
|
||||
@@ -237,20 +237,23 @@ class HandledProjectedModList(HandledList):
|
||||
return
|
||||
|
||||
proj.projected = True
|
||||
isSystemEffect = proj.item.group.name == "Effect Beacon"
|
||||
|
||||
if isSystemEffect:
|
||||
if proj.isExclusiveSystemEffect:
|
||||
self.makeRoom(proj)
|
||||
|
||||
HandledList.append(self, proj)
|
||||
|
||||
# Remove non-projectable modules
|
||||
if not proj.item.isType("projected") and not isSystemEffect:
|
||||
if not proj.item.isType("projected") and not proj.isExclusiveSystemEffect:
|
||||
self.remove(proj)
|
||||
|
||||
@property
|
||||
def currentSystemEffect(self):
|
||||
return next((m for m in self if m.isExclusiveSystemEffect), None)
|
||||
|
||||
def makeRoom(self, proj):
|
||||
# remove other system effects - only 1 per fit plz
|
||||
oldEffect = next((m for m in self if m.item.group.name == "Effect Beacon"), None)
|
||||
oldEffect = self.currentSystemEffect
|
||||
|
||||
if oldEffect:
|
||||
pyfalog.info("System effect occupied with {0}, replacing with {1}", oldEffect.item.name, proj.item.name)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# boosterArmorHpPenalty
|
||||
#
|
||||
# Used by:
|
||||
# Implants named like: Booster (12 of 33)
|
||||
# Implants named like: Booster (12 of 35)
|
||||
type = "boosterSideEffect"
|
||||
|
||||
# User-friendly name for the side effect
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# boosterShieldCapacityPenalty
|
||||
#
|
||||
# Used by:
|
||||
# Implants from group: Booster (12 of 65)
|
||||
# Implants from group: Booster (12 of 69)
|
||||
type = "boosterSideEffect"
|
||||
|
||||
# User-friendly name for the side effect
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# Used by:
|
||||
# Ships from group: Carrier (4 of 4)
|
||||
# Ships from group: Combat Battlecruiser (13 of 13)
|
||||
# Ships from group: Combat Battlecruiser (14 of 14)
|
||||
# Ships from group: Command Ship (8 of 8)
|
||||
# Ships from group: Force Auxiliary (6 of 6)
|
||||
# Ships from group: Supercarrier (6 of 6)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# Used by:
|
||||
# Modules from group: Frequency Mining Laser (3 of 3)
|
||||
type = "passive"
|
||||
|
||||
runTime = "late"
|
||||
|
||||
def handler(fit, module, context):
|
||||
module.preAssignItemAttr("specialtyMiningAmount", module.getModifiedItemAttr("miningAmount"))
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# disintegratorWeaponDamageMultiply
|
||||
#
|
||||
# Used by:
|
||||
# Modules from group: Entropic Radiation Sink (3 of 3)
|
||||
# Modules from group: Entropic Radiation Sink (4 of 4)
|
||||
type = "passive"
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# disintegratorWeaponSpeedMultiply
|
||||
#
|
||||
# Used by:
|
||||
# Modules from group: Entropic Radiation Sink (3 of 3)
|
||||
# Modules from group: Entropic Radiation Sink (4 of 4)
|
||||
type = "passive"
|
||||
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
#
|
||||
# Used by:
|
||||
# Modules named like: Drone Speed Augmentor (6 of 8)
|
||||
# Implant: Overmind 'Goliath' Drone Tuner T25-10S
|
||||
# Implant: Overmind 'Hawkmoth' Drone Tuner S10-25T
|
||||
type = "passive"
|
||||
|
||||
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
# eliteBonusCovertOps3PCTdamagePerCycle
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Hydra
|
||||
type = "passive"
|
||||
|
||||
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
# eliteBonusMaxDmgMultiBonusAdd
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Hydra
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, src, context):
|
||||
fit.modules.filteredItemIncrease(lambda mod: mod.item.requiresSkill("Small Precursor Weapon"), "damageMultiplierBonusMax",
|
||||
src.getModifiedItemAttr("eliteBonusCovertOps3"), skill="Covert Ops")
|
||||
@@ -1,10 +0,0 @@
|
||||
# eliteBonusReconMaxDmgMultiMaxHPT
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Tiamat
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, src, context):
|
||||
fit.modules.filteredItemIncrease(lambda mod: mod.item.requiresSkill("Medium Precursor Weapon"), "damageMultiplierBonusMax",
|
||||
src.getModifiedItemAttr("eliteBonusReconShip3"), skill="Recon Ships")
|
||||
@@ -1,3 +1,7 @@
|
||||
# eliteBonusReconShip3PCTdamagePerCycle
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Tiamat
|
||||
type = "passive"
|
||||
|
||||
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
# emergencyHullEnergizer
|
||||
#
|
||||
# Used by:
|
||||
# Variations of module: Capital Emergency Hull Energizer I (5 of 5)
|
||||
type = "active"
|
||||
runtime = "late"
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# energyWeaponDamageMultiply
|
||||
#
|
||||
# Used by:
|
||||
# Modules from group: Heat Sink (18 of 18)
|
||||
# Modules from group: Heat Sink (19 of 19)
|
||||
type = "passive"
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# energyWeaponSpeedMultiply
|
||||
#
|
||||
# Used by:
|
||||
# Modules from group: Heat Sink (18 of 18)
|
||||
# Modules from group: Heat Sink (19 of 19)
|
||||
type = "passive"
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# hybridWeaponDamageMultiply
|
||||
#
|
||||
# Used by:
|
||||
# Modules from group: Magnetic Field Stabilizer (14 of 14)
|
||||
# Modules from group: Magnetic Field Stabilizer (15 of 15)
|
||||
type = "passive"
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# hybridWeaponSpeedMultiply
|
||||
#
|
||||
# Used by:
|
||||
# Modules from group: Magnetic Field Stabilizer (14 of 14)
|
||||
# Modules from group: Magnetic Field Stabilizer (15 of 15)
|
||||
type = "passive"
|
||||
|
||||
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
# massEntanglerEffect5
|
||||
#
|
||||
# Used by:
|
||||
# Module: Zero-Point Mass Entangler
|
||||
type = "active"
|
||||
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
# Modules from group: Frequency Mining Laser (3 of 3)
|
||||
# Modules from group: Mining Laser (15 of 15)
|
||||
# Modules from group: Strip Miner (5 of 5)
|
||||
# Module: Citizen Miner
|
||||
type = 'active'
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# missileDMGBonus
|
||||
#
|
||||
# Used by:
|
||||
# Modules from group: Ballistic Control system (20 of 20)
|
||||
# Modules from group: Ballistic Control system (21 of 21)
|
||||
type = "passive"
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# missileLauncherSpeedMultiplier
|
||||
#
|
||||
# Used by:
|
||||
# Modules from group: Ballistic Control system (20 of 20)
|
||||
# Modules from group: Ballistic Control system (21 of 21)
|
||||
type = "passive"
|
||||
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
# Used by:
|
||||
# Modules from group: Drone Damage Modules (11 of 11)
|
||||
# Modules named like: C3 'Hivaa Saitsuo' Ballistic Control System (2 of 2)
|
||||
# Module: Abyssal Ballistic Control System
|
||||
type = "passive"
|
||||
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
# Modules from group: Hull Repair Unit (25 of 25)
|
||||
# Modules from group: Remote Armor Repairer (39 of 39)
|
||||
# Modules from group: Remote Capacitor Transmitter (41 of 41)
|
||||
# Modules from group: Remote Hull Repairer (8 of 8)
|
||||
# Modules from group: Remote Shield Booster (38 of 38)
|
||||
# Modules from group: Smart Bomb (118 of 118)
|
||||
# Modules from group: Warp Disrupt Field Generator (7 of 7)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# projectileWeaponDamageMultiply
|
||||
#
|
||||
# Used by:
|
||||
# Modules from group: Gyrostabilizer (13 of 13)
|
||||
# Modules from group: Gyrostabilizer (14 of 14)
|
||||
type = "passive"
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# projectileWeaponSpeedMultiply
|
||||
#
|
||||
# Used by:
|
||||
# Modules from group: Gyrostabilizer (13 of 13)
|
||||
# Modules from group: Gyrostabilizer (14 of 14)
|
||||
type = "passive"
|
||||
|
||||
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
# roleBonusWarpSpeed
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Cynabal
|
||||
# Ship: Dramiel
|
||||
# Ship: Leopard
|
||||
# Ship: Machariel
|
||||
# Ship: Victorieux Luxury Yacht
|
||||
type = "passive"
|
||||
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
# Used by:
|
||||
# Structure Modules from group: Structure Citadel Service Module (2 of 2)
|
||||
# Structure Modules from group: Structure Engineering Service Module (6 of 6)
|
||||
# Structure Modules from group: Structure Navigation Service Module (3 of 3)
|
||||
# Structure Modules from group: Structure Resource Processing Service Module (4 of 4)
|
||||
# Structure Module: Standup Moon Drill I
|
||||
type = "passive"
|
||||
|
||||
10
eos/effects/shiparmoremresistancepbc2.py
Normal file
@@ -0,0 +1,10 @@
|
||||
# shipArmorEMResistancePBC2
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Drekavac
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, ship, context):
|
||||
fit.ship.boostItemAttr("armorEmDamageResonance", ship.getModifiedItemAttr("shipBonusPBC2"),
|
||||
skill="Precursor Battlecruiser")
|
||||
10
eos/effects/shiparmorexplosiveresistancepbc2.py
Normal file
@@ -0,0 +1,10 @@
|
||||
# shipArmorExplosiveResistancePBC2
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Drekavac
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, ship, context):
|
||||
fit.ship.boostItemAttr("armorExplosiveDamageResonance", ship.getModifiedItemAttr("shipBonusPBC2"),
|
||||
skill="Precursor Battlecruiser")
|
||||
10
eos/effects/shiparmorkineticresistancepbc2.py
Normal file
@@ -0,0 +1,10 @@
|
||||
# shipArmorKineticResistancePBC2
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Drekavac
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, ship, context):
|
||||
fit.ship.boostItemAttr("armorKineticDamageResonance", ship.getModifiedItemAttr("shipBonusPBC2"),
|
||||
skill="Precursor Battlecruiser")
|
||||
10
eos/effects/shiparmorthermalresistancepbc2.py
Normal file
@@ -0,0 +1,10 @@
|
||||
# shipArmorThermalResistancePBC2
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Drekavac
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, ship, context):
|
||||
fit.ship.boostItemAttr("armorThermalDamageResonance", ship.getModifiedItemAttr("shipBonusPBC2"),
|
||||
skill="Precursor Battlecruiser")
|
||||
@@ -1,8 +1,7 @@
|
||||
# shipBonusDreadnoughtC2ShieldResists
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Caiman
|
||||
# Ship: Phoenix
|
||||
# Variations of ship: Phoenix (2 of 2)
|
||||
type = "passive"
|
||||
|
||||
|
||||
|
||||
@@ -6,5 +6,5 @@ type = "passive"
|
||||
|
||||
|
||||
def handler(fit, ship, context):
|
||||
fit.drones.filteredItemBoost(lambda drone: drone.item.group.name == "Mining Drone",
|
||||
fit.drones.filteredItemBoost(lambda drone: drone.item.requiresSkill("Drones"),
|
||||
"miningAmount", ship.getModifiedItemAttr("shipBonusAC2"), skill="Amarr Cruiser")
|
||||
|
||||
@@ -7,5 +7,5 @@ type = "passive"
|
||||
|
||||
|
||||
def handler(fit, ship, context):
|
||||
fit.drones.filteredItemBoost(lambda drone: drone.item.group.name == "Mining Drone",
|
||||
fit.drones.filteredItemBoost(lambda drone: drone.item.requiresSkill("Mining Drone Operation"),
|
||||
"miningAmount", ship.getModifiedItemAttr("shipBonusGC2"), skill="Gallente Cruiser")
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
# shipBonusForceAuxiliaryA3CapCapacity
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Apostle
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, src, context):
|
||||
fit.ship.boostItemAttr("capacitorCapacity", src.getModifiedItemAttr("shipBonusForceAuxiliaryA3"),
|
||||
skill="Amarr Carrier")
|
||||
@@ -1,8 +1,7 @@
|
||||
# shipBonusForceAuxiliaryC2ShieldResists
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Loggerhead
|
||||
# Ship: Minokawa
|
||||
# Variations of ship: Minokawa (2 of 2)
|
||||
type = "passive"
|
||||
|
||||
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
# shipBonusForceAuxiliaryC3CapCapacity
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Minokawa
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, src, context):
|
||||
fit.ship.boostItemAttr("capacitorCapacity", src.getModifiedItemAttr("shipBonusForceAuxiliaryC3"),
|
||||
skill="Caldari Carrier")
|
||||
@@ -1,10 +0,0 @@
|
||||
# shipBonusForceAuxiliaryG3CapBoosterStrength
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Ninazu
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, src, context):
|
||||
fit.modules.filteredChargeBoost(lambda mod: mod.charge.group.name == "Capacitor Booster Charge", "capacitorBonus",
|
||||
src.getModifiedItemAttr("shipBonusForceAuxiliaryG3"), skill="Gallente Carrier")
|
||||
@@ -1,10 +0,0 @@
|
||||
# shipBonusForceAuxiliaryM3CapBoosterStrength
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Lif
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, src, context):
|
||||
fit.modules.filteredChargeBoost(lambda mod: mod.charge.group.name == "Capacitor Booster Charge", "capacitorBonus",
|
||||
src.getModifiedItemAttr("shipBonusForceAuxiliaryM3"), skill="Minmatar Carrier")
|
||||
@@ -9,5 +9,5 @@ type = "passive"
|
||||
|
||||
|
||||
def handler(fit, container, context):
|
||||
fit.drones.filteredItemBoost(lambda drone: drone.item.group.name == "Mining Drone",
|
||||
fit.drones.filteredItemBoost(lambda drone: drone.item.requiresSkill("Mining Drone Operation"),
|
||||
"miningAmount", container.getModifiedItemAttr("rookieDroneBonus"))
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Damavik
|
||||
# Ship: Drekavac
|
||||
# Ship: Hydra
|
||||
# Ship: Kikimora
|
||||
# Ship: Leshak
|
||||
# Ship: Tiamat
|
||||
# Ship: Vedmak
|
||||
|
||||
11
eos/effects/shipbonuspbc1disintegratordamage.py
Normal file
@@ -0,0 +1,11 @@
|
||||
# shipBonusPBC1DisintegratorDamage
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Drekavac
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, ship, context):
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Medium Precursor Weapon"),
|
||||
"damageMultiplier", ship.getModifiedItemAttr("shipBonusPBC1"),
|
||||
skill="Precursor Battlecruiser")
|
||||
11
eos/effects/shipbonuspd1disintegratordamage.py
Normal file
@@ -0,0 +1,11 @@
|
||||
# shipBonusPD1DisintegratorDamage
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Kikimora
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, ship, context):
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Small Precursor Weapon"),
|
||||
"damageMultiplier", ship.getModifiedItemAttr("shipBonusPD1"),
|
||||
skill="Precursor Destroyer")
|
||||
11
eos/effects/shipbonuspd2disintegratormaxrange.py
Normal file
@@ -0,0 +1,11 @@
|
||||
# shipBonusPD2DisintegratorMaxRange
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Kikimora
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, ship, context):
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Small Precursor Weapon"),
|
||||
"maxRange", ship.getModifiedItemAttr("shipBonusPD2"),
|
||||
skill="Precursor Destroyer")
|
||||
@@ -2,7 +2,9 @@
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Damavik
|
||||
# Ship: Drekavac
|
||||
# Ship: Hydra
|
||||
# Ship: Kikimora
|
||||
# Ship: Leshak
|
||||
# Ship: Tiamat
|
||||
# Ship: Vedmak
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Damavik
|
||||
# Ship: Drekavac
|
||||
# Ship: Hydra
|
||||
# Ship: Kikimora
|
||||
# Ship: Leshak
|
||||
# Ship: Tiamat
|
||||
# Ship: Vedmak
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
# shipBonusRole3XLTorpdeoVelocityBonus
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Komodo
|
||||
# Ship: Leviathan
|
||||
# Variations of ship: Leviathan (2 of 2)
|
||||
type = "passive"
|
||||
|
||||
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Damavik
|
||||
# Ship: Drekavac
|
||||
# Ship: Hydra
|
||||
# Ship: Kikimora
|
||||
# Ship: Leshak
|
||||
# Ship: Tiamat
|
||||
# Ship: Vedmak
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
# shipBonusTitanA3WarpStrength
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Avatar
|
||||
# Ship: Molok
|
||||
# Variations of ship: Avatar (2 of 2)
|
||||
type = "passive"
|
||||
|
||||
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
# shipBonusTitanC2ROFBonus
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Komodo
|
||||
# Ship: Leviathan
|
||||
# Variations of ship: Leviathan (2 of 2)
|
||||
type = "passive"
|
||||
|
||||
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
# shipBonusTitanC3WarpStrength
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Komodo
|
||||
# Ship: Leviathan
|
||||
# Variations of ship: Leviathan (2 of 2)
|
||||
type = "passive"
|
||||
|
||||
|
||||
|
||||
10
eos/effects/shiproledisintegratormaxrangecbc.py
Normal file
@@ -0,0 +1,10 @@
|
||||
# shipRoleDisintegratorMaxRangeCBC
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Drekavac
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, ship, context):
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Medium Precursor Weapon"),
|
||||
"maxRange", ship.getModifiedItemAttr("roleBonusCBC"))
|
||||
@@ -1,7 +1,7 @@
|
||||
# skillBonusDroneDurability
|
||||
#
|
||||
# Used by:
|
||||
# Implants from group: Cyber Drones (2 of 2)
|
||||
# Implants from group: Cyber Drones (4 of 4)
|
||||
# Skill: Drone Durability
|
||||
type = "passive"
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
# skillBonusDroneInterfacing
|
||||
#
|
||||
# Used by:
|
||||
# Implants from group: Cyber Drones (2 of 2)
|
||||
# Implant: CreoDron 'Bumblebee' Drone Tuner T10-5D
|
||||
# Implant: CreoDron 'Yellowjacket' Drone Tuner D5-10T
|
||||
# Skill: Drone Interfacing
|
||||
type = "passive"
|
||||
|
||||
|
||||
10
eos/effects/smalldisintegratormaxrangebonus.py
Normal file
@@ -0,0 +1,10 @@
|
||||
# smallDisintegratorMaxRangeBonus
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Kikimora
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, ship, context):
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Small Precursor Weapon"),
|
||||
"maxRange", ship.getModifiedItemAttr("maxRangeBonus"))
|
||||
@@ -1,7 +1,8 @@
|
||||
# structureAoERoFRoleBonus
|
||||
#
|
||||
# Used by:
|
||||
# Items from category: Structure (11 of 14)
|
||||
# Items from category: Structure (11 of 17)
|
||||
# Structures from group: Citadel (8 of 9)
|
||||
type = "passive"
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# structureArmorHPMultiply
|
||||
# structureArmorHPBonus
|
||||
#
|
||||
# Used by:
|
||||
# Structure Modules from group: Structure Armor Reinforcer (2 of 2)
|
||||
@@ -7,4 +7,4 @@ runTime = "early"
|
||||
|
||||
|
||||
def handler(fit, src, context):
|
||||
fit.ship.multiplyItemAttr("hiddenArmorHPMultiplier", src.getModifiedItemAttr("armorHPMultiplier"))
|
||||
fit.ship.boostItemAttr("hiddenArmorHPMultiplier", src.getModifiedItemAttr("armorHpBonus"), stackingPenalties=True)
|
||||
@@ -3,14 +3,20 @@
|
||||
# Used by:
|
||||
# Structure Modules from group: Structure Energy Neutralizer (5 of 5)
|
||||
from eos.saveddata.module import State
|
||||
from eos.modifiedAttributeDict import ModifiedAttributeDict
|
||||
|
||||
type = "active", "projected"
|
||||
|
||||
|
||||
def handler(fit, container, context):
|
||||
def handler(fit, src, context, **kwargs):
|
||||
amount = 0
|
||||
if "projected" in context:
|
||||
if (hasattr(container, "state") and container.state >= State.ACTIVE) or hasattr(container, "amountActive"):
|
||||
amount = container.getModifiedItemAttr("energyNeutralizerAmount")
|
||||
time = container.getModifiedItemAttr("duration")
|
||||
fit.addDrain(container, time, amount, 0)
|
||||
if (hasattr(src, "state") and src.state >= State.ACTIVE) or hasattr(src, "amountActive"):
|
||||
amount = src.getModifiedItemAttr("energyNeutralizerAmount")
|
||||
|
||||
if 'effect' in kwargs:
|
||||
amount *= ModifiedAttributeDict.getResistance(fit, kwargs['effect'])
|
||||
|
||||
time = src.getModifiedItemAttr("duration")
|
||||
|
||||
fit.addDrain(src, time, amount, 0)
|
||||
@@ -1,7 +1,7 @@
|
||||
# structureFullPowerStateHitpointModifier
|
||||
#
|
||||
# Used by:
|
||||
# Items from category: Structure (14 of 14)
|
||||
# Items from category: Structure (17 of 17)
|
||||
type = "passive"
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# structureHiddenArmorHPMultiplier
|
||||
#
|
||||
# Used by:
|
||||
# Items from category: Structure (14 of 14)
|
||||
# Items from category: Structure (17 of 17)
|
||||
type = "passive"
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# structureHiddenMissileDamageMultiplier
|
||||
#
|
||||
# Used by:
|
||||
# Items from category: Structure (14 of 14)
|
||||
# Items from category: Structure (14 of 17)
|
||||
type = "passive"
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# targetAttack
|
||||
#
|
||||
# Used by:
|
||||
# Drones from group: Combat Drone (74 of 74)
|
||||
# Drones from group: Combat Drone (75 of 75)
|
||||
# Modules from group: Energy Weapon (212 of 214)
|
||||
type = 'active'
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# warpScramble
|
||||
# warpDisrupt
|
||||
#
|
||||
# Used by:
|
||||
# Modules named like: Warp Disruptor (28 of 28)
|
||||
@@ -4,15 +4,15 @@
|
||||
# Celestial: darkness_weather_1
|
||||
# Celestial: darkness_weather_2
|
||||
# Celestial: darkness_weather_3
|
||||
# Celestial: pvp_weather_1
|
||||
runTime = "early"
|
||||
type = ("projected", "passive", "gang")
|
||||
|
||||
|
||||
def handler(fit, beacon, context, **kwargs):
|
||||
for x in range(1, 3):
|
||||
for x in range(1, 5):
|
||||
if beacon.getModifiedItemAttr("warfareBuff{}ID".format(x)):
|
||||
value = beacon.getModifiedItemAttr("warfareBuff{}Value".format(x))
|
||||
id = beacon.getModifiedItemAttr("warfareBuff{}ID".format(x))
|
||||
|
||||
if id:
|
||||
fit.addCommandBonus(id, value, beacon, kwargs['effect'], 'early')
|
||||
|
||||
@@ -576,51 +576,67 @@ class Unit(EqBase):
|
||||
""" This is a mapping of various tweaks that we have to do between the internal representation of an attribute
|
||||
value and the display (for example, 'Millisecond' units have the display name of 's', so we have to convert value
|
||||
from ms to s) """
|
||||
# Each entry contains:
|
||||
# Function to convert value to display value
|
||||
# Function to convert value to display format (which sometimes can be a string)
|
||||
# Function which controls unit name used with attribute
|
||||
# Function to convert display value to value
|
||||
return {
|
||||
"Inverse Absolute Percent": (
|
||||
lambda v: (1 - v) * 100,
|
||||
lambda d: -1 * (d / 100) + 1,
|
||||
lambda u: u),
|
||||
lambda v: (1 - v) * 100,
|
||||
lambda u: u,
|
||||
lambda d: -1 * (d / 100) + 1),
|
||||
"Inversed Modifier Percent": (
|
||||
lambda v: (1 - v) * 100,
|
||||
lambda d: -1 * (d / 100) + 1,
|
||||
lambda u: u),
|
||||
lambda v: (1 - v) * 100,
|
||||
lambda u: u,
|
||||
lambda d: -1 * (d / 100) + 1),
|
||||
"Modifier Percent": (
|
||||
lambda v: (v - 1) * 100,
|
||||
lambda v: ("%+.2f" if ((v - 1) * 100) % 1 else "%+d") % ((v - 1) * 100),
|
||||
lambda d: (d / 100) + 1,
|
||||
lambda u: u),
|
||||
lambda u: u,
|
||||
lambda d: (d / 100) + 1),
|
||||
"Volume": (
|
||||
lambda v: v,
|
||||
lambda d: d,
|
||||
lambda u: "m³"),
|
||||
lambda v: v,
|
||||
lambda u: "m³",
|
||||
lambda d: d),
|
||||
"Sizeclass": (
|
||||
lambda v: self.rigSizes[v],
|
||||
lambda v: self.rigSizes[v],
|
||||
lambda d: next(i for i in self.rigSizes.keys() if self.rigSizes[i] == 'Medium'),
|
||||
lambda u: ""),
|
||||
"Absolute Percent": (
|
||||
lambda v: (v * 100),
|
||||
lambda d: d / 100,
|
||||
lambda u: u),
|
||||
lambda v: v * 100,
|
||||
lambda v: v * 100,
|
||||
lambda u: u,
|
||||
lambda d: d / 100),
|
||||
"Milliseconds": (
|
||||
lambda v: v / 1000.0,
|
||||
lambda d: d * 1000.0,
|
||||
lambda u: u),
|
||||
lambda v: v / 1000,
|
||||
lambda v: v / 1000,
|
||||
lambda u: u,
|
||||
lambda d: d * 1000),
|
||||
"Boolean": (
|
||||
lambda v: "Yes" if v == 1 else "No",
|
||||
lambda d: 1.0 if d == "Yes" else 0.0,
|
||||
lambda u: ""),
|
||||
lambda v: True if v else False,
|
||||
lambda v: "Yes" if v else "No",
|
||||
lambda u: "",
|
||||
lambda d: 1.0 if d == "Yes" else 0.0),
|
||||
"typeID": (
|
||||
self.itemIDCallback,
|
||||
None, # we could probably convert these back if we really tried hard enough
|
||||
lambda u: ""),
|
||||
self.itemIDCallback,
|
||||
lambda u: "",
|
||||
None), # we could probably convert these back if we really tried hard enough
|
||||
"groupID": (
|
||||
self.groupIDCallback,
|
||||
None,
|
||||
lambda u: ""),
|
||||
self.groupIDCallback,
|
||||
lambda u: "",
|
||||
None),
|
||||
"attributeID": (
|
||||
self.attributeIDCallback,
|
||||
None,
|
||||
lambda u: ""),
|
||||
self.attributeIDCallback,
|
||||
lambda u: "",
|
||||
None),
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
@@ -643,25 +659,33 @@ class Unit(EqBase):
|
||||
attribute = eos.db.getAttributeInfo(v, eager="unit")
|
||||
return "%s (%d)" % (attribute.name.capitalize(), v)
|
||||
|
||||
def TranslateValue(self, value):
|
||||
def PreformatValue(self, value):
|
||||
"""Attributes have to be translated certain ways based on their unit (ex: decimals converting to percentages).
|
||||
This allows us to get an easy representation of how the attribute should be printed """
|
||||
|
||||
override = self.translations.get(self.name)
|
||||
if override is not None:
|
||||
return override[0](value), override[2](self.displayName)
|
||||
return override[1](value), override[2](self.displayName)
|
||||
|
||||
return value, self.displayName
|
||||
|
||||
def SimplifyValue(self, value):
|
||||
"""Takes the internal representation value and convert it into the display value"""
|
||||
|
||||
override = self.translations.get(self.name)
|
||||
if override is not None:
|
||||
return override[0](value)
|
||||
|
||||
return value
|
||||
|
||||
def ComplicateValue(self, value):
|
||||
"""Takes the display value and turns it back into the internal representation of it"""
|
||||
|
||||
override = self.translations.get(self.name)
|
||||
if override is not None:
|
||||
return override[1](value)
|
||||
return override[3](value)
|
||||
|
||||
return value
|
||||
|
||||
|
||||
class Traits(EqBase):
|
||||
pass
|
||||
|
||||
@@ -93,6 +93,8 @@ class FitDpsGraph(Graph):
|
||||
|
||||
# this is janky as fuck
|
||||
for fighter in fit.fighters:
|
||||
if not fighter.active:
|
||||
continue
|
||||
for ability in fighter.abilities:
|
||||
if ability.dealsDamage and ability.active:
|
||||
multiplier = self.calculateFighterMissileMultiplier(ability, data)
|
||||
|
||||
@@ -692,7 +692,7 @@ class Fit(object):
|
||||
self.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Operation"),
|
||||
"duration", value, stackingPenalties=True)
|
||||
|
||||
# Abysmal Weather Effects
|
||||
# Abyssal Weather Effects
|
||||
|
||||
if warfareBuffID == 90: # Weather_electric_storm_EM_resistance_penalty
|
||||
for tankType in ("shield", "armor"):
|
||||
|
||||
@@ -272,7 +272,17 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
|
||||
@property
|
||||
def modPosition(self):
|
||||
if self.owner:
|
||||
return self.owner.modules.index(self)
|
||||
return self.owner.modules.index(self) if not self.isProjected else self.owner.projectedModules.index(self)
|
||||
|
||||
@property
|
||||
def isProjected(self):
|
||||
if self.owner:
|
||||
return self in self.owner.projectedModules
|
||||
return None
|
||||
|
||||
@property
|
||||
def isExclusiveSystemEffect(self):
|
||||
return self.item.group.name in ("Effect Beacon", "Non-Interactable Object", "MassiveEnvironments")
|
||||
|
||||
@property
|
||||
def isCapitalSize(self):
|
||||
|
||||
@@ -167,8 +167,6 @@ class AttributeGauge(wx.Window):
|
||||
|
||||
def SetValue(self, value, animate=True):
|
||||
""" Sets the current position of the gauge. """
|
||||
|
||||
print("=" * 20, self._percentage)
|
||||
if self._value == value:
|
||||
return
|
||||
|
||||
|
||||
@@ -151,7 +151,7 @@ class CargoView(d.Display):
|
||||
self.original = fit.cargo if fit is not None else None
|
||||
self.cargo = stuff = fit.cargo if fit is not None else None
|
||||
if stuff is not None:
|
||||
stuff.sort(key=lambda cargo: cargo.itemID)
|
||||
stuff.sort(key=lambda c: (c.item.group.category.name, c.item.group.name, c.item.name))
|
||||
|
||||
if event.fitID != self.lastFitId:
|
||||
self.lastFitId = event.fitID
|
||||
|
||||
@@ -23,6 +23,7 @@ import gui.display as d
|
||||
from gui.builtinMarketBrowser.events import ITEM_SELECTED
|
||||
import gui.mainFrame
|
||||
from gui.builtinViewColumns.state import State
|
||||
from gui.utils.staticHelpers import DragDropHelper
|
||||
from gui.contextMenu import ContextMenu
|
||||
import gui.globalEvents as GE
|
||||
from eos.saveddata.fit import ImplantLocation
|
||||
@@ -31,6 +32,22 @@ from service.market import Market
|
||||
import gui.fitCommands as cmd
|
||||
|
||||
|
||||
class ImplantViewDrop(wx.DropTarget):
|
||||
def __init__(self, dropFn, *args, **kwargs):
|
||||
super(ImplantViewDrop, self).__init__(*args, **kwargs)
|
||||
self.dropFn = dropFn
|
||||
# this is really transferring an EVE itemID
|
||||
self.dropData = wx.TextDataObject()
|
||||
self.SetDataObject(self.dropData)
|
||||
|
||||
def OnData(self, x, y, t):
|
||||
if self.GetData():
|
||||
dragged_data = DragDropHelper.data
|
||||
data = dragged_data.split(':')
|
||||
self.dropFn(x, y, data)
|
||||
return t
|
||||
|
||||
|
||||
class ImplantView(wx.Panel):
|
||||
def __init__(self, parent):
|
||||
wx.Panel.__init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, style=wx.TAB_TRAVERSAL)
|
||||
@@ -77,10 +94,7 @@ class ImplantView(wx.Panel):
|
||||
def OnRadioSelect(self, event):
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
if fitID is not None:
|
||||
sFit = Fit.getInstance()
|
||||
sFit.toggleImplantSource(fitID, ImplantLocation.FIT if self.rbFit.GetValue() else ImplantLocation.CHARACTER)
|
||||
|
||||
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID))
|
||||
self.mainFrame.command.Submit(cmd.GuiChangeImplantLocation(fitID, ImplantLocation.FIT if self.rbFit.GetValue() else ImplantLocation.CHARACTER))
|
||||
|
||||
|
||||
class ImplantDisplay(d.Display):
|
||||
@@ -102,12 +116,27 @@ class ImplantDisplay(d.Display):
|
||||
self.Bind(wx.EVT_LEFT_DCLICK, self.removeItem)
|
||||
self.Bind(wx.EVT_LEFT_DOWN, self.click)
|
||||
self.Bind(wx.EVT_KEY_UP, self.kbEvent)
|
||||
self.SetDropTarget(ImplantViewDrop(self.handleListDrag))
|
||||
|
||||
|
||||
if "__WXGTK__" in wx.PlatformInfo:
|
||||
self.Bind(wx.EVT_RIGHT_UP, self.scheduleMenu)
|
||||
else:
|
||||
self.Bind(wx.EVT_RIGHT_DOWN, self.scheduleMenu)
|
||||
|
||||
def handleListDrag(self, x, y, data):
|
||||
"""
|
||||
Handles dragging of items from various pyfa displays which support it
|
||||
|
||||
data is list with two indices:
|
||||
data[0] is hard-coded str of originating source
|
||||
data[1] is typeID or index of data we want to manipulate
|
||||
"""
|
||||
|
||||
if data[0] == "market":
|
||||
if self.mainFrame.command.Submit(cmd.GuiAddImplantCommand(self.mainFrame.getActiveFit(), int(data[1]))):
|
||||
self.mainFrame.additionsPane.select("Implants")
|
||||
|
||||
def kbEvent(self, event):
|
||||
keycode = event.GetKeyCode()
|
||||
if keycode == wx.WXK_DELETE or keycode == wx.WXK_NUMPAD_DELETE:
|
||||
|
||||
@@ -30,8 +30,9 @@ class ModuleGlobalAmmoPicker(ModuleAmmoPicker):
|
||||
fit = db_getFit(fitID)
|
||||
|
||||
selectedModule = self.modules[0]
|
||||
source = fit.modules if not selectedModule.isProjected else fit.projectedModules
|
||||
allModules = []
|
||||
for mod in fit.modules:
|
||||
for mod in source:
|
||||
if mod.itemID is None:
|
||||
continue
|
||||
if mod.itemID == selectedModule.itemID:
|
||||
|
||||
@@ -15,7 +15,7 @@ class WhProjector(ContextMenu):
|
||||
|
||||
# CCP doesn't currently provide a mapping between the general Environment, and the specific environment effect
|
||||
# (which can be random when going into Abyssal space). This is how we currently define it:
|
||||
# environment type: specific type name previx
|
||||
# environment type: specific type name prefix
|
||||
abyssal_mapping = {
|
||||
'caustic_toxin_weather': 47862, # Exotic Particle Storm
|
||||
'darkness_weather': 47863, # Dark Matter Field
|
||||
@@ -50,13 +50,13 @@ class WhProjector(ContextMenu):
|
||||
wormhole_item.SetSubMenu(wormhole_menu)
|
||||
sub.Append(wormhole_item)
|
||||
|
||||
effdata = self.getEffectBeacons()
|
||||
self.buildMenu(effdata, wormhole_menu, rootMenu, msw)
|
||||
grouped_data, flat_data = self.getEffectBeacons()
|
||||
self.buildMenu(grouped_data, flat_data, wormhole_menu, rootMenu, msw)
|
||||
|
||||
# Incursions
|
||||
|
||||
effdata = self.getEffectBeacons(incursions=True)
|
||||
self.buildMenu(effdata, sub, rootMenu, msw)
|
||||
grouped_data, flat_data = self.getEffectBeacons(incursions=True)
|
||||
self.buildMenu(grouped_data, flat_data, sub, rootMenu, msw)
|
||||
|
||||
# Abyssal Weather
|
||||
|
||||
@@ -65,8 +65,8 @@ class WhProjector(ContextMenu):
|
||||
abyssal_item.SetSubMenu(abyssal_menu)
|
||||
sub.Append(abyssal_item)
|
||||
|
||||
effdata = self.getAbyssalWeather()
|
||||
self.buildMenu(effdata, abyssal_menu, rootMenu, msw)
|
||||
grouped_data, flat_data = self.getAbyssalWeather()
|
||||
self.buildMenu(grouped_data, flat_data, abyssal_menu, rootMenu, msw)
|
||||
|
||||
# Localized Weather
|
||||
|
||||
@@ -75,8 +75,8 @@ class WhProjector(ContextMenu):
|
||||
local_item.SetSubMenu(local_menu)
|
||||
sub.Append(local_item)
|
||||
|
||||
effdata = self.getLocalizedEnvironments()
|
||||
self.buildMenu(effdata, local_menu, rootMenu, msw)
|
||||
grouped_data, flat_data = self.getLocalizedEnvironments()
|
||||
self.buildMenu(grouped_data, flat_data, local_menu, rootMenu, msw)
|
||||
|
||||
return sub
|
||||
|
||||
@@ -91,33 +91,38 @@ class WhProjector(ContextMenu):
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
self.mainFrame.command.Submit(cmd.GuiAddProjectedCommand(fitID, swObj.ID, 'item'))
|
||||
|
||||
def buildMenu(self, data, local_menu, rootMenu, msw):
|
||||
for swType in sorted(data):
|
||||
def buildMenu(self, grouped_data, flat_data, local_menu, rootMenu, msw):
|
||||
|
||||
def processFlat(data, root, sub):
|
||||
for swData in sorted(data, key=lambda tpl: tpl[2]):
|
||||
wxid = ContextMenu.nextID()
|
||||
swObj, swName, swClass = swData
|
||||
self.idmap[wxid] = (swObj, swName)
|
||||
subItem = wx.MenuItem(sub, wxid, swClass)
|
||||
if msw:
|
||||
root.Bind(wx.EVT_MENU, self.handleSelection, subItem)
|
||||
else:
|
||||
sub.Bind(wx.EVT_MENU, self.handleSelection, subItem)
|
||||
sub.Append(subItem)
|
||||
|
||||
for swType in sorted(grouped_data):
|
||||
subItem = wx.MenuItem(local_menu, wx.ID_ANY, swType)
|
||||
grandSub = wx.Menu()
|
||||
subItem.SetSubMenu(grandSub)
|
||||
local_menu.Append(subItem)
|
||||
processFlat(grouped_data[swType], rootMenu, grandSub)
|
||||
|
||||
for swData in sorted(data[swType], key=lambda tpl: tpl[2]):
|
||||
wxid = ContextMenu.nextID()
|
||||
swObj, swName, swClass = swData
|
||||
self.idmap[wxid] = (swObj, swName)
|
||||
grandSubItem = wx.MenuItem(grandSub, wxid, swClass)
|
||||
if msw:
|
||||
rootMenu.Bind(wx.EVT_MENU, self.handleSelection, grandSubItem)
|
||||
else:
|
||||
grandSub.Bind(wx.EVT_MENU, self.handleSelection, grandSubItem)
|
||||
grandSub.Append(grandSubItem)
|
||||
processFlat(flat_data, rootMenu, local_menu)
|
||||
|
||||
def getEffectBeacons(self, incursions=False):
|
||||
"""
|
||||
Get dictionary with system-wide effects
|
||||
Get dictionary with wormhole system-wide effects
|
||||
"""
|
||||
sMkt = Market.getInstance()
|
||||
|
||||
# todo: rework this
|
||||
# Container for system-wide effects
|
||||
effects = {}
|
||||
grouped = {}
|
||||
|
||||
# Expressions for matching when detecting effects we're looking for
|
||||
if incursions:
|
||||
@@ -158,13 +163,13 @@ class WhProjector(ContextMenu):
|
||||
groupname = re.sub(garbage, "", groupname)
|
||||
groupname = re.sub(" {2,}", " ", groupname).strip()
|
||||
# Add stuff to dictionary
|
||||
if groupname not in effects:
|
||||
effects[groupname] = set()
|
||||
effects[groupname].add((beacon, beaconname, shortname))
|
||||
if groupname not in grouped:
|
||||
grouped[groupname] = set()
|
||||
grouped[groupname].add((beacon, beaconname, shortname))
|
||||
# Break loop on 1st result
|
||||
break
|
||||
|
||||
return effects
|
||||
return grouped, ()
|
||||
|
||||
def getAbyssalWeather(self):
|
||||
sMkt = Market.getInstance()
|
||||
@@ -172,7 +177,8 @@ class WhProjector(ContextMenu):
|
||||
environments = {x.ID: x for x in sMkt.getGroup("Abyssal Environment").items}
|
||||
items = chain(sMkt.getGroup("MassiveEnvironments").items, sMkt.getGroup("Non-Interactable Object").items)
|
||||
|
||||
effects = {}
|
||||
grouped = {}
|
||||
flat = set()
|
||||
|
||||
for beacon in items:
|
||||
if not beacon.isType('projected'):
|
||||
@@ -183,20 +189,23 @@ class WhProjector(ContextMenu):
|
||||
if type is None:
|
||||
continue
|
||||
|
||||
if type.name not in effects:
|
||||
effects[type.name] = set()
|
||||
if type.name not in grouped:
|
||||
grouped[type.name] = set()
|
||||
|
||||
display_name = "{} {}".format(type.name, beacon.name[-1:])
|
||||
effects[type.name].add((beacon, display_name, display_name))
|
||||
grouped[type.name].add((beacon, display_name, display_name))
|
||||
|
||||
return effects
|
||||
# PVP weather
|
||||
flat.add((sMkt.getItem(49766), 'PvP Weather', 'PvP Weather'))
|
||||
|
||||
return grouped, flat
|
||||
|
||||
def getLocalizedEnvironments(self):
|
||||
sMkt = Market.getInstance()
|
||||
|
||||
grp = sMkt.getGroup("Abyssal Hazards")
|
||||
|
||||
effects = dict()
|
||||
grouped = dict()
|
||||
|
||||
for beacon in grp.items:
|
||||
if not beacon.isType('projected'):
|
||||
@@ -206,12 +215,12 @@ class WhProjector(ContextMenu):
|
||||
name_parts = beacon.name.split(" ")
|
||||
|
||||
key = name_parts[1].strip()
|
||||
if key not in effects:
|
||||
effects[key] = set()
|
||||
if key not in grouped:
|
||||
grouped[key] = set()
|
||||
|
||||
effects[key].add((beacon, beacon.name, beacon.name))
|
||||
grouped[key].add((beacon, beacon.name, beacon.name))
|
||||
|
||||
return effects
|
||||
return grouped, ()
|
||||
|
||||
|
||||
WhProjector.register()
|
||||
|
||||
@@ -46,17 +46,17 @@ class AttributeSlider(wx.Panel):
|
||||
# Slider which abstracts users values from internal values (because the built in slider does not deal with floats
|
||||
# and the like), based on http://wxpython-users.wxwidgets.narkive.com/ekgBzA7u/anyone-ever-thought-of-a-floating-point-slider
|
||||
|
||||
def __init__(self, parent, baseValue, minMod, maxMod, inverse=False, id=-1):
|
||||
def __init__(self, parent, baseValue, minValue, maxValue, inverse=False, id=-1):
|
||||
wx.Panel.__init__(self, parent, id=id)
|
||||
|
||||
self.parent = parent
|
||||
|
||||
self.inverse = inverse
|
||||
|
||||
self.base_value = baseValue
|
||||
|
||||
self.UserMinValue = minMod
|
||||
self.UserMaxValue = maxMod
|
||||
self.UserMinValue = minValue
|
||||
self.UserMaxValue = maxValue
|
||||
|
||||
self.inverse = inverse
|
||||
|
||||
# The internal slider basically represents the percentage towards the end of the range. It has to be normalized
|
||||
# in this way, otherwise when we start off with a base, if the range is skewed to one side, the base value won't
|
||||
@@ -65,12 +65,12 @@ class AttributeSlider(wx.Panel):
|
||||
|
||||
# Additionally, since we want the slider to be accurate to 3 decimal places, we need to blow out the two ends here
|
||||
# (if we have a slider that needs to land on 66.66% towards the right, it will actually be converted to 66%. Se we need it to support 6,666)
|
||||
#
|
||||
# self.SliderMinValue = -100
|
||||
# self.SliderMaxValue = 100
|
||||
# self.SliderValue = 0
|
||||
|
||||
self.SliderMinValue = -100
|
||||
self.SliderMaxValue = 100
|
||||
self.SliderValue = 0
|
||||
|
||||
range = [(self.UserMinValue * self.base_value), (self.UserMaxValue * self.base_value)]
|
||||
range = [self.UserMinValue, self.UserMaxValue]
|
||||
|
||||
self.ctrl = wx.SpinCtrlDouble(self, min=min(range), max=max(range))
|
||||
self.ctrl.SetDigits(3)
|
||||
@@ -92,19 +92,12 @@ class AttributeSlider(wx.Panel):
|
||||
evt.Skip()
|
||||
|
||||
def SetValue(self, value, post_event=True):
|
||||
# todo: check this against values that might be 2.5x and whatnot
|
||||
mod = value / self.base_value
|
||||
self.ctrl.SetValue(value)
|
||||
slider_percentage = 0
|
||||
if mod < 1:
|
||||
modEnd = self.UserMinValue
|
||||
slider_percentage = (1 - mod) / (1 - modEnd) * -100
|
||||
elif mod > 1:
|
||||
modEnd = self.UserMaxValue
|
||||
slider_percentage = ((mod - 1) / (modEnd - 1)) * 100
|
||||
# print(slider_percentage)
|
||||
if self.inverse:
|
||||
slider_percentage *= -1
|
||||
invert_factor = -1 if self.inverse else 1
|
||||
if value >= self.base_value:
|
||||
slider_percentage = (value - self.base_value) / (self.UserMaxValue - self.base_value) * 100 * invert_factor
|
||||
else:
|
||||
slider_percentage = (value - self.base_value) / (self.base_value - self.UserMinValue) * 100 * invert_factor
|
||||
self.slider.SetValue(slider_percentage)
|
||||
if post_event:
|
||||
wx.PostEvent(self, ValueChanged(self, None, value, None, slider_percentage))
|
||||
|
||||
@@ -7,7 +7,7 @@ import wx.lib.agw.hypertreelist
|
||||
from gui.builtinItemStatsViews.helpers import AutoListCtrl
|
||||
|
||||
from gui.bitmap_loader import BitmapLoader
|
||||
from gui.utils.numberFormatter import formatAmount
|
||||
from gui.utils.numberFormatter import formatAmount, roundDec
|
||||
from enum import IntEnum
|
||||
from gui.builtinItemStatsViews.attributeGrouping import *
|
||||
|
||||
@@ -294,14 +294,14 @@ class ItemParams(wx.Panel):
|
||||
if self.toggleView != 1:
|
||||
valueUnit = str(value)
|
||||
elif info and info.unit:
|
||||
valueUnit = self.FormatValue(*info.unit.TranslateValue(value))
|
||||
valueUnit = self.FormatValue(*info.unit.PreformatValue(value))
|
||||
else:
|
||||
valueUnit = formatAmount(value, 3, 0, 0)
|
||||
|
||||
if self.toggleView != 1:
|
||||
valueUnitDefault = str(valueDefault)
|
||||
elif info and info.unit:
|
||||
valueUnitDefault = self.FormatValue(*info.unit.TranslateValue(valueDefault))
|
||||
valueUnitDefault = self.FormatValue(*info.unit.PreformatValue(valueDefault))
|
||||
else:
|
||||
valueUnitDefault = formatAmount(valueDefault, 3, 0, 0)
|
||||
|
||||
@@ -314,11 +314,13 @@ class ItemParams(wx.Panel):
|
||||
# self.paramList.SetItemImage(index, attrIcon, which=wx.TreeItemIcon_Normal)
|
||||
|
||||
@staticmethod
|
||||
def FormatValue(value, unit):
|
||||
def FormatValue(value, unit, rounding='prec', digits=3):
|
||||
"""Formats a value / unit combination into a string
|
||||
@todo: move this to a more central location, since this is also used in the item mutator panel"""
|
||||
if isinstance(value, (int, float)):
|
||||
fvalue = formatAmount(value, 3, 0, 0)
|
||||
if isinstance(value, (int, float)) and rounding == 'prec':
|
||||
fvalue = formatAmount(value, digits, 0, 0)
|
||||
elif isinstance(value, (int, float)) and rounding == 'dec':
|
||||
fvalue = roundDec(value, digits)
|
||||
else:
|
||||
fvalue = value
|
||||
return "%s %s" % (fvalue, unit)
|
||||
|
||||
@@ -30,17 +30,9 @@ class ItemMutator(wx.Panel):
|
||||
self.event_mapping = {}
|
||||
|
||||
for m in sorted(stuff.mutators.values(), key=lambda x: x.attribute.displayName):
|
||||
baseValueFormated = m.attribute.unit.TranslateValue(m.baseValue)[0]
|
||||
valueFormated = m.attribute.unit.TranslateValue(m.value)[0]
|
||||
slider = AttributeSlider(self, baseValueFormated, m.minMod, m.maxMod, not m.highIsGood)
|
||||
slider.SetValue(valueFormated, False)
|
||||
slider.Bind(EVT_VALUE_CHANGED, self.changeMutatedValue)
|
||||
self.event_mapping[slider] = m
|
||||
headingSizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
|
||||
# create array for the two ranges
|
||||
min_t = [round(m.minValue, 3), m.minMod, None]
|
||||
max_t = [round(m.maxValue, 3), m.maxMod, None]
|
||||
min_t = [m.minValue, m.minMod, None]
|
||||
max_t = [m.maxValue, m.maxMod, None]
|
||||
|
||||
# Then we need to determine if it's better than original, which will be the color
|
||||
min_t[2] = min_t[1] < 1 if not m.highIsGood else 1 < min_t[1]
|
||||
@@ -56,14 +48,8 @@ class ItemMutator(wx.Panel):
|
||||
worse_range = max_t
|
||||
else:
|
||||
worse_range = min_t
|
||||
#
|
||||
# print("{}: \nHigh is good: {}".format(m.attribute.displayName, m.attribute.highIsGood))
|
||||
# print("Value {}".format(m.baseValue))
|
||||
#
|
||||
# print(min_t)
|
||||
# print(max_t)
|
||||
# print(better_range)
|
||||
# print(worse_range)
|
||||
|
||||
headingSizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
|
||||
font = parent.GetFont()
|
||||
font.SetWeight(wx.BOLD)
|
||||
@@ -75,19 +61,30 @@ class ItemMutator(wx.Panel):
|
||||
|
||||
headingSizer.Add(displayName, 3, wx.ALL | wx.EXPAND, 0)
|
||||
|
||||
range_low = wx.StaticText(self, wx.ID_ANY, ItemParams.FormatValue(*m.attribute.unit.TranslateValue(worse_range[0])))
|
||||
range_low.SetForegroundColour(self.goodColor if worse_range[2] else self.badColor)
|
||||
worst_val = ItemParams.FormatValue(*m.attribute.unit.PreformatValue(worse_range[0]), rounding='dec')
|
||||
worst_text = wx.StaticText(self, wx.ID_ANY, worst_val)
|
||||
worst_text.SetForegroundColour(self.goodColor if worse_range[2] else self.badColor)
|
||||
|
||||
range_high = wx.StaticText(self, wx.ID_ANY, ItemParams.FormatValue(*m.attribute.unit.TranslateValue(better_range[0])))
|
||||
range_high.SetForegroundColour(self.goodColor if better_range[2] else self.badColor)
|
||||
best_val = ItemParams.FormatValue(*m.attribute.unit.PreformatValue(better_range[0]), rounding='dec')
|
||||
best_text = wx.StaticText(self, wx.ID_ANY, best_val)
|
||||
best_text.SetForegroundColour(self.goodColor if better_range[2] else self.badColor)
|
||||
|
||||
headingSizer.Add(range_low, 0, wx.ALL | wx.EXPAND, 0)
|
||||
headingSizer.Add(worst_text, 0, wx.ALL | wx.EXPAND, 0)
|
||||
headingSizer.Add(wx.StaticText(self, wx.ID_ANY, " ─ "), 0, wx.RIGHT | wx.LEFT | wx.EXPAND, 5)
|
||||
headingSizer.Add(range_high, 0, wx.RIGHT | wx.EXPAND, 10)
|
||||
headingSizer.Add(best_text, 0, wx.RIGHT | wx.EXPAND, 10)
|
||||
|
||||
mainSizer.Add(headingSizer, 0, wx.ALL | wx.EXPAND, 5)
|
||||
|
||||
slider = AttributeSlider(parent=self,
|
||||
baseValue=m.attribute.unit.SimplifyValue(m.baseValue),
|
||||
minValue=m.attribute.unit.SimplifyValue(min_t[0]),
|
||||
maxValue=m.attribute.unit.SimplifyValue(max_t[0]),
|
||||
inverse=better_range is min_t)
|
||||
slider.SetValue(m.attribute.unit.SimplifyValue(m.value), False)
|
||||
slider.Bind(EVT_VALUE_CHANGED, self.changeMutatedValue)
|
||||
self.event_mapping[slider] = m
|
||||
mainSizer.Add(slider, 0, wx.RIGHT | wx.LEFT | wx.EXPAND, 10)
|
||||
|
||||
mainSizer.Add(wx.StaticLine(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL), 0, wx.ALL | wx.EXPAND, 5)
|
||||
|
||||
mainSizer.AddStretchSpacer()
|
||||
@@ -132,7 +129,7 @@ class ItemMutator(wx.Panel):
|
||||
|
||||
for slider, m in self.event_mapping.items():
|
||||
value = sFit.changeMutatedValue(m, m.baseValue)
|
||||
value = m.attribute.unit.TranslateValue(value)[0]
|
||||
value = m.attribute.unit.SimplifyValue(value)
|
||||
slider.SetValue(value)
|
||||
|
||||
evt.Skip()
|
||||
@@ -143,7 +140,7 @@ class ItemMutator(wx.Panel):
|
||||
for slider, m in self.event_mapping.items():
|
||||
value = random.uniform(m.minValue, m.maxValue)
|
||||
value = sFit.changeMutatedValue(m, value)
|
||||
value = m.attribute.unit.TranslateValue(value)[0]
|
||||
value = m.attribute.unit.SimplifyValue(value)
|
||||
slider.SetValue(value)
|
||||
|
||||
evt.Skip()
|
||||
|
||||
@@ -736,6 +736,7 @@ class _TabsContainer(wx.Panel):
|
||||
self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnErase)
|
||||
self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
|
||||
self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
|
||||
self.Bind(wx.EVT_MIDDLE_UP, self.OnMiddleUp)
|
||||
self.Bind(wx.EVT_MOTION, self.OnMotion)
|
||||
self.Bind(wx.EVT_SIZE, self.OnSize)
|
||||
self.Bind(wx.EVT_SYS_COLOUR_CHANGED, self.OnSysColourChanged)
|
||||
@@ -776,6 +777,29 @@ class _TabsContainer(wx.Panel):
|
||||
|
||||
self.dragged_tab = tab
|
||||
|
||||
def OnMiddleUp(self, event):
|
||||
mposx, mposy = event.GetPosition()
|
||||
|
||||
tab = self.FindTabAtPos(mposx, mposy)
|
||||
|
||||
if tab is None or not tab.closeable: # if not able to close, return False
|
||||
return False
|
||||
|
||||
index = self.tabs.index(tab)
|
||||
ev = PageClosing(index)
|
||||
wx.PostEvent(self.Parent, ev)
|
||||
|
||||
if ev.isVetoed():
|
||||
return False
|
||||
|
||||
index = self.GetTabIndex(tab)
|
||||
self.Parent.DeletePage(index)
|
||||
wx.PostEvent(self.Parent, PageClosed(index=index))
|
||||
|
||||
sel = self.GetSelected()
|
||||
if sel is not None:
|
||||
wx.PostEvent(self.Parent, PageChanged(-1, sel))
|
||||
|
||||
def OnMotion(self, event):
|
||||
"""
|
||||
Determines what happens when the mouse moves. This handles primarily
|
||||
|
||||
@@ -131,7 +131,7 @@ class EveFittings(wx.Frame):
|
||||
return
|
||||
data = self.fitTree.fittingsTreeCtrl.GetItemData(selection)
|
||||
sPort = Port.getInstance()
|
||||
fits = sPort.importFitFromBuffer(data)
|
||||
import_type, fits = sPort.importFitFromBuffer(data)
|
||||
self.mainFrame._openAfterImport(fits)
|
||||
|
||||
def deleteFitting(self, event):
|
||||
|
||||
@@ -31,4 +31,6 @@ from .guiChangeProjectedFitQty import GuiChangeProjectedFitQty
|
||||
from .guiChangeDroneQty import GuiChangeDroneQty
|
||||
from .guiChangeProjectedDroneQty import GuiChangeProjectedDroneQty
|
||||
from .guiToggleDrone import GuiToggleDroneCommand
|
||||
from .guiFitRename import GuiFitRenameCommand
|
||||
from .guiFitRename import GuiFitRenameCommand
|
||||
from .guiChangeImplantLocation import GuiChangeImplantLocation
|
||||
from .guiImportMutatedModule import GuiImportMutatedModuleCommand
|
||||
|
||||
@@ -28,11 +28,12 @@ class FitAddProjectedEnvCommand(wx.Command):
|
||||
|
||||
# todo: thing to check for existing environmental effects
|
||||
|
||||
self.old_item = fit.projectedModules.makeRoom(module)
|
||||
|
||||
module.state = State.ONLINE
|
||||
fit.projectedModules.append(module)
|
||||
if module.isExclusiveSystemEffect:
|
||||
# if this is an exclusive system effect, we need to cache the old one. We make room for the new one here, which returns the old one
|
||||
self.old_item = fit.projectedModules.makeRoom(module)
|
||||
|
||||
fit.projectedModules.append(module)
|
||||
eos.db.commit()
|
||||
self.new_index = fit.projectedModules.index(module)
|
||||
return True
|
||||
|
||||
25
gui/fitCommands/calc/fitChangeImplantLocation.py
Normal file
@@ -0,0 +1,25 @@
|
||||
import wx
|
||||
import eos.db
|
||||
from logbook import Logger
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
class FitChangeImplantLocation(wx.Command):
|
||||
def __init__(self, fitID, source):
|
||||
wx.Command.__init__(self, True, "Drone add")
|
||||
self.fitID = fitID
|
||||
self.source = source
|
||||
self.old_source = None
|
||||
|
||||
def Do(self):
|
||||
pyfalog.debug("Toggling implant source for fit ID: {0}", self.fitID)
|
||||
fit = eos.db.getFit(self.fitID)
|
||||
self.old_source = fit.implantSource
|
||||
fit.implantSource = self.source
|
||||
eos.db.commit()
|
||||
return True
|
||||
|
||||
|
||||
def Undo(self):
|
||||
cmd = FitChangeImplantLocation(self.fitID, self.old_source)
|
||||
return cmd.Do()
|
||||
93
gui/fitCommands/calc/fitImportMutatedModule.py
Normal file
@@ -0,0 +1,93 @@
|
||||
import wx
|
||||
from eos.saveddata.module import Module, State
|
||||
import eos.db
|
||||
from eos.db.gamedata.queries import getDynamicItem
|
||||
from logbook import Logger
|
||||
from service.fit import Fit
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
class FitImportMutatedCommand(wx.Command):
|
||||
""""
|
||||
Fitting command that takes info about mutated module, composes it and adds it to a fit
|
||||
"""
|
||||
def __init__(self, fitID, baseItem, mutaItem, attrMap):
|
||||
wx.Command.__init__(self, True)
|
||||
self.fitID = fitID
|
||||
self.baseItem = baseItem
|
||||
self.mutaItem = mutaItem
|
||||
self.attrMap = attrMap
|
||||
self.new_position = None
|
||||
self.change = None
|
||||
self.replace_cmd = None
|
||||
|
||||
def Do(self):
|
||||
sFit = Fit.getInstance()
|
||||
fitID = self.fitID
|
||||
fit = eos.db.getFit(fitID)
|
||||
|
||||
if self.baseItem is None:
|
||||
pyfalog.warning("Unable to build non-mutated module: no base item to build from")
|
||||
return False
|
||||
|
||||
try:
|
||||
mutaTypeID = self.mutaItem.ID
|
||||
except AttributeError:
|
||||
mutaplasmid = None
|
||||
else:
|
||||
mutaplasmid = getDynamicItem(mutaTypeID)
|
||||
# Try to build simple item even though no mutaplasmid found
|
||||
if mutaplasmid is None:
|
||||
try:
|
||||
module = Module(self.baseItem)
|
||||
except ValueError:
|
||||
pyfalog.warning("Unable to build non-mutated module: {}", self.baseItem)
|
||||
return False
|
||||
# Build mutated module otherwise
|
||||
else:
|
||||
try:
|
||||
module = Module(mutaplasmid.resultingItem, self.baseItem, mutaplasmid)
|
||||
except ValueError:
|
||||
pyfalog.warning("Unable to build mutated module: {} {}", self.baseItem, self.mutaItem)
|
||||
return False
|
||||
else:
|
||||
for attrID, mutator in module.mutators.items():
|
||||
if attrID in self.attrMap:
|
||||
mutator.value = self.attrMap[attrID]
|
||||
|
||||
|
||||
# this is essentially the same as the FitAddModule command. possibly look into centralizing this functionality somewhere?
|
||||
if module.fits(fit):
|
||||
pyfalog.debug("Adding {} as module for fit {}", module, fit)
|
||||
module.owner = fit
|
||||
numSlots = len(fit.modules)
|
||||
fit.modules.append(module)
|
||||
if module.isValidState(State.ACTIVE):
|
||||
module.state = State.ACTIVE
|
||||
|
||||
# todo: fix these
|
||||
# As some items may affect state-limiting attributes of the ship, calculate new attributes first
|
||||
# self.recalc(fit)
|
||||
# Then, check states of all modules and change where needed. This will recalc if needed
|
||||
sFit.checkStates(fit, module)
|
||||
|
||||
# fit.fill()
|
||||
eos.db.commit()
|
||||
|
||||
self.change = numSlots != len(fit.modules)
|
||||
self.new_position = module.modPosition
|
||||
else:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def Undo(self):
|
||||
# We added a subsystem module, which actually ran the replace command. Run the undo for that guy instead
|
||||
if self.replace_cmd:
|
||||
return self.replace_cmd.Undo()
|
||||
|
||||
from .fitRemoveModule import FitRemoveModuleCommand # Avoid circular import
|
||||
if self.new_position is not None:
|
||||
cmd = FitRemoveModuleCommand(self.fitID, [self.new_position])
|
||||
cmd.Do()
|
||||
return True
|
||||
@@ -23,6 +23,13 @@ class FitReplaceModuleCommand(wx.Command):
|
||||
self.old_module = None
|
||||
|
||||
def Do(self):
|
||||
fit = eos.db.getFit(self.fitID)
|
||||
|
||||
mod = fit.modules[self.position]
|
||||
if not mod.isEmpty:
|
||||
self.old_module = ModuleInfoCache(mod.modPosition, mod.item.ID, mod.state, mod.charge, mod.baseItemID,
|
||||
mod.mutaplasmidID)
|
||||
|
||||
return self.change_module(self.fitID, self.position, self.itemID)
|
||||
|
||||
def Undo(self):
|
||||
@@ -30,7 +37,6 @@ class FitReplaceModuleCommand(wx.Command):
|
||||
fit = eos.db.getFit(self.fitID)
|
||||
fit.modules.toDummy(self.position)
|
||||
return True
|
||||
|
||||
self.change_module(self.fitID, self.position, self.old_module.itemID)
|
||||
self.module.state = self.old_module.state
|
||||
self.module.charge = self.old_module.charge
|
||||
@@ -52,10 +58,7 @@ class FitReplaceModuleCommand(wx.Command):
|
||||
pyfalog.debug("Changing position of module from position ({0}) for fit ID: {1}", self.position, fitID)
|
||||
|
||||
item = eos.db.getItem(itemID, eager=("attributes", "group.category"))
|
||||
|
||||
mod = fit.modules[self.position]
|
||||
if not mod.isEmpty:
|
||||
self.old_module = ModuleInfoCache(mod.modPosition, mod.item.ID, mod.state, mod.charge, mod.baseItemID, mod.mutaplasmidID)
|
||||
|
||||
try:
|
||||
self.module = Module(item)
|
||||
@@ -75,6 +78,9 @@ class FitReplaceModuleCommand(wx.Command):
|
||||
if self.module.isValidState(State.ACTIVE):
|
||||
self.module.state = State.ACTIVE
|
||||
|
||||
if self.old_module.charge and self.module.isValidCharge(self.old_module.charge):
|
||||
self.module.charge = self.old_module.charge
|
||||
|
||||
# Then, check states of all modules and change where needed. This will recalc if needed
|
||||
# self.checkStates(fit, m)
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
class FitSetChargeCommand(wx.Command):
|
||||
def __init__(self, fitID, positions, chargeID=None):
|
||||
def __init__(self, fitID, positions, chargeID=None, projected=False):
|
||||
# todo: determine if this command really should be used with a group of modules, or a simple per module basis
|
||||
wx.Command.__init__(self, True, "Module Charge Add")
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
@@ -17,6 +17,7 @@ class FitSetChargeCommand(wx.Command):
|
||||
self.fitID = fitID
|
||||
self.chargeID = chargeID
|
||||
self.positions = positions
|
||||
self.projected = projected
|
||||
self.cache = None
|
||||
|
||||
def Do(self):
|
||||
@@ -29,7 +30,8 @@ class FitSetChargeCommand(wx.Command):
|
||||
|
||||
def __setAmmo(self, positions, chargeID):
|
||||
fit = eos.db.getFit(self.fitID)
|
||||
self.cache = {fit.modules[i].modPosition: fit.modules[i].chargeID for i in positions}
|
||||
source = fit.modules if not self.projected else fit.projectedModules
|
||||
self.cache = {source[i].modPosition: source[i].chargeID for i in positions}
|
||||
ammo = eos.db.getItem(chargeID) if chargeID else None
|
||||
|
||||
if ammo is not None and not ammo.isCharge:
|
||||
@@ -37,7 +39,7 @@ class FitSetChargeCommand(wx.Command):
|
||||
result = False
|
||||
|
||||
for pos in positions:
|
||||
mod = fit.modules[pos]
|
||||
mod = source[pos]
|
||||
if not mod.isEmpty and mod.isValidCharge(ammo):
|
||||
pyfalog.debug("Set ammo {} for {} on fit {}", ammo, mod, self.fitID)
|
||||
result = True
|
||||
|
||||
@@ -15,9 +15,10 @@ class GuiModuleAddChargeCommand(wx.Command):
|
||||
self.fitID = fitID
|
||||
self.itemID = itemID
|
||||
self.positions = [mod.modPosition for mod in modules]
|
||||
self.projected = modules[0].isProjected
|
||||
|
||||
def Do(self):
|
||||
if self.internal_history.Submit(FitSetChargeCommand(self.fitID, self.positions, self.itemID)):
|
||||
if self.internal_history.Submit(FitSetChargeCommand(self.fitID, self.positions, self.itemID, self.projected)):
|
||||
self.sFit.recalc(self.fitID)
|
||||
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID))
|
||||
return True
|
||||
|
||||
@@ -3,7 +3,9 @@ from service.fit import Fit
|
||||
|
||||
import gui.mainFrame
|
||||
from gui import globalEvents as GE
|
||||
from eos.saveddata.fit import ImplantLocation
|
||||
from .calc.fitAddImplant import FitAddImplantCommand
|
||||
from .calc.fitChangeImplantLocation import FitChangeImplantLocation
|
||||
|
||||
|
||||
class GuiAddImplantCommand(wx.Command):
|
||||
@@ -16,7 +18,7 @@ class GuiAddImplantCommand(wx.Command):
|
||||
self.itemID = itemID
|
||||
|
||||
def Do(self):
|
||||
if self.internal_history.Submit(FitAddImplantCommand(self.fitID, self.itemID)):
|
||||
if self.internal_history.Submit(FitAddImplantCommand(self.fitID, self.itemID)) and self.internal_history.Submit(FitChangeImplantLocation(self.fitID, ImplantLocation.FIT)):
|
||||
self.sFit.recalc(self.fitID)
|
||||
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID))
|
||||
return True
|
||||
|
||||
30
gui/fitCommands/guiChangeImplantLocation.py
Normal file
@@ -0,0 +1,30 @@
|
||||
import wx
|
||||
from service.fit import Fit
|
||||
|
||||
import gui.mainFrame
|
||||
from gui import globalEvents as GE
|
||||
from .calc.fitChangeImplantLocation import FitChangeImplantLocation
|
||||
|
||||
|
||||
class GuiChangeImplantLocation(wx.Command):
|
||||
def __init__(self, fitID, source):
|
||||
wx.Command.__init__(self, True, "Implant Source Change")
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
self.sFit = Fit.getInstance()
|
||||
self.internal_history = wx.CommandProcessor()
|
||||
self.fitID = fitID
|
||||
self.source = source
|
||||
|
||||
def Do(self):
|
||||
if self.internal_history.Submit(FitChangeImplantLocation(self.fitID, self.source)):
|
||||
self.sFit.recalc(self.fitID)
|
||||
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID))
|
||||
return True
|
||||
return False
|
||||
|
||||
def Undo(self):
|
||||
for _ in self.internal_history.Commands:
|
||||
self.internal_history.Undo()
|
||||
self.sFit.recalc(self.fitID)
|
||||
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID))
|
||||
return True
|
||||
38
gui/fitCommands/guiImportMutatedModule.py
Normal file
@@ -0,0 +1,38 @@
|
||||
import wx
|
||||
import eos.db
|
||||
import gui.mainFrame
|
||||
from gui import globalEvents as GE
|
||||
from .calc.fitImportMutatedModule import FitImportMutatedCommand
|
||||
from service.fit import Fit
|
||||
from logbook import Logger
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
class GuiImportMutatedModuleCommand(wx.Command):
|
||||
|
||||
def __init__(self, fitID, baseItem, mutaItem, attrMap):
|
||||
wx.Command.__init__(self, True, "Mutated Module Import: {} {} {}".format(baseItem, mutaItem, attrMap))
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
self.sFit = Fit.getInstance()
|
||||
self.fitID = fitID
|
||||
self.baseItem = baseItem
|
||||
self.mutaItem = mutaItem
|
||||
self.attrMap = attrMap
|
||||
self.internal_history = wx.CommandProcessor()
|
||||
|
||||
def Do(self):
|
||||
pyfalog.debug("{} Do()".format(self))
|
||||
|
||||
if self.internal_history.Submit(FitImportMutatedCommand(self.fitID, self.baseItem, self.mutaItem, self.attrMap)):
|
||||
self.sFit.recalc(self.fitID)
|
||||
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID, action="modadd"))
|
||||
return True
|
||||
return False
|
||||
|
||||
def Undo(self):
|
||||
pyfalog.debug("{} Undo()".format(self))
|
||||
for _ in self.internal_history.Commands:
|
||||
self.internal_history.Undo()
|
||||
self.sFit.recalc(self.fitID)
|
||||
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID, action="moddel"))
|
||||
return True
|
||||
@@ -17,6 +17,7 @@ class GuiRemoveImplantCommand(wx.Command):
|
||||
|
||||
def Do(self):
|
||||
if self.internal_history.Submit(FitRemoveImplantCommand(self.fitID, self.position)):
|
||||
self.sFit.recalc(self.fitID)
|
||||
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID))
|
||||
return True
|
||||
return False
|
||||
@@ -24,5 +25,6 @@ class GuiRemoveImplantCommand(wx.Command):
|
||||
def Undo(self):
|
||||
for _ in self.internal_history.Commands:
|
||||
self.internal_history.Undo()
|
||||
self.sFit.recalc(self.fitID)
|
||||
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID))
|
||||
return True
|
||||
|
||||
@@ -73,6 +73,7 @@ from service.fit import Fit
|
||||
from service.port import EfsPort, IPortUser, Port
|
||||
from service.settings import HTMLExportSettings, SettingsProvider
|
||||
from service.update import Update
|
||||
import gui.fitCommands as cmd
|
||||
|
||||
disableOverrideEditor = False
|
||||
|
||||
@@ -728,12 +729,18 @@ class MainFrame(wx.Frame):
|
||||
|
||||
def importFromClipboard(self, event):
|
||||
clipboard = fromClipboard()
|
||||
activeFit = self.getActiveFit()
|
||||
try:
|
||||
fits = Port().importFitFromBuffer(clipboard, self.getActiveFit())
|
||||
importType, importData = Port().importFitFromBuffer(clipboard, activeFit)
|
||||
# If it's mutated item - make sure there's at least base item specified
|
||||
if importType == "MutatedItem":
|
||||
# we've imported an Abyssal module, need to fire off the command to add it to the fit
|
||||
self.command.Submit(cmd.GuiImportMutatedModuleCommand(activeFit, *importData[0]))
|
||||
return # no need to do anything else
|
||||
except:
|
||||
pyfalog.error("Attempt to import failed:\n{0}", clipboard)
|
||||
else:
|
||||
self._openAfterImport(fits)
|
||||
self._openAfterImport(importData)
|
||||
|
||||
def exportToClipboard(self, event):
|
||||
CopySelectDict = {CopySelectDialog.copyFormatEft: self.clipboardEft,
|
||||
|
||||
@@ -110,3 +110,9 @@ def roundToPrec(val, prec):
|
||||
if int(val) == val:
|
||||
val = int(val)
|
||||
return val
|
||||
|
||||
|
||||
def roundDec(val, prec):
|
||||
if int(val) == val:
|
||||
return int(val)
|
||||
return round(val, prec)
|
||||
|
||||
BIN
imgs/icons/10886@1x.png
Normal file
|
After Width: | Height: | Size: 773 B |
BIN
imgs/icons/10886@2x.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
imgs/icons/10887@1x.png
Normal file
|
After Width: | Height: | Size: 787 B |
BIN
imgs/icons/10887@2x.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
imgs/icons/21562@1x.png
Normal file
|
After Width: | Height: | Size: 1002 B |
BIN
imgs/icons/21562@2x.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
imgs/icons/2205@1x.png
Normal file
|
After Width: | Height: | Size: 854 B |
BIN
imgs/icons/2205@2x.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |