Compare commits

..

38 Commits

Author SHA1 Message Date
blitzmann
6f1872fb94 Disable implants for read-only characters 2016-03-19 22:10:09 -04:00
blitzmann
ff56e70b81 Opps, dunno how this happened 2016-03-19 22:09:31 -04:00
blitzmann
201263237f Add migration to update fits tablet for implant source 2016-03-19 21:20:20 -04:00
blitzmann
1ddd37f381 Enable implant searching. 2016-03-19 20:55:29 -04:00
blitzmann
f9d2a78c5e Fix up styling for character implants and fitting window implant view 2016-03-19 19:30:42 -04:00
blitzmann
443c917c6b Get context menus working for character implants 2016-03-19 18:23:34 -04:00
blitzmann
7c787cd13b Recalc fit when changing implant source 2016-03-19 15:42:49 -04:00
blitzmann
dc8aff6b6c Merge branch 'master' into charImplants 2016-03-19 15:33:35 -04:00
blitzmann
397040549f Merge branch 'aacn500-validate-import' 2016-03-18 23:52:11 -04:00
blitzmann
0b858d6e94 Clean up call to checkStates 2016-03-18 23:51:55 -04:00
blitzmann
6c8efcda12 Fix traceback when ship is missing launcher / turret attribute (#539) 2016-03-18 23:31:19 -04:00
blitzmann
3fa0aa9242 Bump dev 2016-03-18 23:30:40 -04:00
aacn500
18775286c0 only check states when first loading a fit from db 2016-03-17 11:56:00 +00:00
aacn500
57433efe80 Check that modules fit on imported fits #512 #522 2016-03-16 20:12:26 +00:00
blitzmann
c42748a5dd Fix #537 - cap battery causing remote cap transfers to apply incorrect values.
Bump to stable 1.20.1
2016-03-15 22:46:51 -04:00
blitzmann
b5cf835959 Add a toggle between fit-specific implants and character implants. This avoids a lot of the problems of how to mix these two sources of implants. Character implants cannot change stage. 2016-03-13 14:48:43 -04:00
blitzmann
48b45b5f51 Merge branch 'master' into charImplants
# Conflicts:
#	gui/characterEditor.py
2016-03-12 23:20:26 -05:00
blitzmann
91980c9f2c Bump release 2016-03-11 00:20:26 -05:00
blitzmann
db1c80c7e3 Update effect headers 2016-03-11 00:18:33 -05:00
blitzmann
e53bd70c2c Merge pull request #497 from SpeedProg/master
Added commandline arguments to specify window title and path for savefiles
2016-03-10 23:58:56 -05:00
blitzmann
fe64e2e24c Fix module states when loading from database with an incorrect state (see #529) 2016-03-10 23:55:12 -05:00
blitzmann
a020ca9a71 Fix tracking / guidance disrupters 2016-03-10 23:43:24 -05:00
blitzmann
7a9fde822c Add some missing icons to the database and image store 2016-03-10 23:28:56 -05:00
blitzmann
152af02336 Fix effects involving XL missiles 2016-03-10 20:37:09 -05:00
blitzmann
be7d3a921a Update database to TQ 1017528 2016-03-10 20:17:26 -05:00
blitzmann
78acb205d3 Merge branch 'singularity' 2016-03-10 20:16:57 -05:00
blitzmann
627dac692c Modify applied cap drain based on ship's cap resistance 2016-03-08 18:23:35 -05:00
blitzmann
68a6a828d8 Revert "Disable setting new database version and bump pre-release"
This reverts commit d36bf41ecf.
2016-03-08 16:55:03 -05:00
blitzmann
e8604788df Replace locale formating with regular string formatting due to issues with setting locale. 2016-03-06 11:48:01 -05:00
Constantin Wenger
cf60bbc904 Merge remote-tracking branch 'upstream/master'
updated from upstream
2016-02-11 06:53:01 +01:00
Constantin Wenger
02d4ac81dd renamed parameter savepath to customSavePath for better distinguishability to savePath 2016-02-05 13:10:18 +01:00
Constantin Wenger
f0775af439 added command line option to specify the savepath 2016-01-12 21:28:15 +01:00
Constantin Wenger
96048b5133 added command line option to set the window title 2016-01-12 21:28:15 +01:00
blitzmann
ca34d7cced Differentiate between character implants and fits 2015-11-10 02:06:44 -05:00
blitzmann
938e2a871d Merge branch 'master' into charImplants
Conflicts:
	gui/characterEditor.py
2015-11-08 21:19:04 -05:00
blitzmann
dc55dbdf36 Polish some events 2015-09-25 14:48:05 -04:00
blitzmann
d0ec17feba Some syntax 2015-09-25 14:13:33 -04:00
blitzmann
5b5fdd97d6 Enable and fix market tree for character implant view 2015-09-25 13:59:37 -04:00
115 changed files with 491 additions and 314 deletions

View File

@@ -18,10 +18,10 @@ debug = False
saveInRoot = False
# Version data
version = "1.19.2"
version = "1.20.2"
tag = "git"
expansionName = "Singularity"
expansionVersion = "1015913"
expansionName = "March 2016"
expansionVersion = "1.3"
evemonMinVersion = "4081"
pyfaPath = None
@@ -60,7 +60,7 @@ def __createDirs(path):
if not os.path.exists(path):
os.makedirs(path)
def defPaths():
def defPaths(customSavePath):
global debug
global pyfaPath
global savePath
@@ -87,8 +87,11 @@ def defPaths():
else:
savePath = getattr(configforced, "savePath", None)
if savePath is None:
savePath = unicode(os.path.expanduser(os.path.join("~", ".pyfa")),
if customSavePath is None: # customSavePath is not overriden
savePath = unicode(os.path.expanduser(os.path.join("~", ".pyfa")),
sys.getfilesystemencoding())
else:
savePath = customSavePath
__createDirs(savePath)

View File

@@ -4,6 +4,9 @@ import time
import re
import os
import migrations
import logging
logger = logging.getLogger(__name__)
def getVersion(db):
cursor = db.execute('PRAGMA user_version')
@@ -30,11 +33,10 @@ def update(saveddata_engine):
shutil.copyfile(config.saveDB, toFile)
for version in xrange(dbVersion, appVersion):
func = migrations.updates[version+1]
if func:
print "applying update",version+1
logger.info("Applying database update: %d", version+1)
func(saveddata_engine)
# when all is said and done, set version to current
# saveddata_engine.execute("PRAGMA user_version = {}".format(appVersion))
saveddata_engine.execute("PRAGMA user_version = {}".format(appVersion))

View File

@@ -0,0 +1,15 @@
"""
Migration 13
- Alters fits table to introduce implant location attribute
"""
import sqlalchemy
def upgrade(saveddata_engine):
# Update fits schema to include implant location attribute
try:
saveddata_engine.execute("SELECT implantLocation FROM fits LIMIT 1")
except sqlalchemy.exc.DatabaseError:
saveddata_engine.execute("ALTER TABLE fits ADD COLUMN implantLocation INTEGER;")
saveddata_engine.execute("UPDATE fits SET implantLocation = 0")

View File

@@ -36,9 +36,22 @@ characters_table = Table("characters", saveddata_meta,
Column("ownerID", ForeignKey("users.ID"), nullable = True))
mapper(Character, characters_table,
properties = {"_Character__owner" : relation(User, backref = "characters"),
"_Character__skills" : relation(Skill, backref="character", cascade = "all,delete-orphan"),
"_Character__implants" : relation(Implant, collection_class = HandledImplantBoosterList, cascade='all,delete-orphan', single_parent=True,
primaryjoin = charImplants_table.c.charID == characters_table.c.ID,
secondaryjoin = charImplants_table.c.implantID == Implant.ID,
secondary = charImplants_table),})
properties = {
"_Character__owner": relation(
User,
backref = "characters"),
"_Character__skills": relation(
Skill,
backref="character",
cascade = "all,delete-orphan"),
"_Character__implants": relation(
Implant,
collection_class = HandledImplantBoosterList,
cascade='all,delete-orphan',
backref='character',
single_parent=True,
primaryjoin = charImplants_table.c.charID == characters_table.c.ID,
secondaryjoin = charImplants_table.c.implantID == Implant.ID,
secondary = charImplants_table),
}
)

View File

@@ -28,7 +28,7 @@ from eos.db.saveddata.module import modules_table
from eos.db.saveddata.drone import drones_table
from eos.db.saveddata.cargo import cargo_table
from eos.db.saveddata.implant import fitImplants_table
from eos.types import Fit, Module, User, Booster, Drone, Cargo, Implant, Character, DamagePattern, TargetResists
from eos.types import Fit, Module, User, Booster, Drone, Cargo, Implant, Character, DamagePattern, TargetResists, ImplantLocation
from eos.effectHandlerHelpers import *
fits_table = Table("fits", saveddata_meta,
@@ -42,6 +42,7 @@ fits_table = Table("fits", saveddata_meta,
Column("booster", Boolean, nullable = False, index = True, default = 0),
Column("targetResistsID", ForeignKey("targetResists.ID"), nullable=True),
Column("modeID", Integer, nullable=True),
Column("implantLocation", Integer, nullable=False, default=ImplantLocation.FIT),
)
projectedFits_table = Table("projectedFits", saveddata_meta,

View File

@@ -131,6 +131,10 @@ class HandledModuleList(HandledList):
self.remove(mod)
return
# fix for #529, where a module may be in incorrect state after CCP changes mechanics of module
if not mod.isValidState(mod.state):
mod.state = eos.types.State.ONLINE
mod.position = len(self)
HandledList.append(self, mod)
if mod.isInvalid:

View File

@@ -1,7 +1,7 @@
# ammoInfluenceCapNeed
#
# Used by:
# Items from category: Charge (458 of 833)
# Items from category: Charge (458 of 851)
type = "passive"
def handler(fit, module, context):
# Dirty hack to work around cap charges setting cap booster

View File

@@ -1,7 +1,7 @@
# ammoInfluenceRange
#
# Used by:
# Items from category: Charge (559 of 833)
# Items from category: Charge (559 of 851)
type = "passive"
def handler(fit, module, context):
module.multiplyItemAttr("maxRange", module.getModifiedChargeAttr("weaponRangeMultiplier"))

View File

@@ -2,6 +2,7 @@
#
# Used by:
# Implants named like: Exile Booster (4 of 4)
# Implant: Antipharmakon Kosybo
type = "passive"
def handler(fit, booster, context):
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Repair Systems") or mod.item.requiresSkill("Capital Repair Systems"),

View File

@@ -1,7 +1,7 @@
# boosterArmorHpPenalty
#
# Used by:
# Implants from group: Booster (12 of 37)
# Implants from group: Booster (12 of 42)
type = "boosterSideEffect"
def handler(fit, booster, context):
fit.ship.boostItemAttr("armorHP", booster.getModifiedItemAttr("boosterArmorHPPenalty"))

View File

@@ -1,7 +1,7 @@
# boosterArmorRepairAmountPenalty
#
# Used by:
# Implants from group: Booster (9 of 37)
# Implants from group: Booster (9 of 42)
type = "boosterSideEffect"
def handler(fit, booster, context):
fit.modules.filteredItemBoost(lambda mod: mod.item.group.name == "Armor Repair Unit",

View File

@@ -1,7 +1,7 @@
# boosterMaxVelocityPenalty
#
# Used by:
# Implants from group: Booster (12 of 37)
# Implants from group: Booster (12 of 42)
type = "boosterSideEffect"
def handler(fit, booster, context):
fit.ship.boostItemAttr("maxVelocity", booster.getModifiedItemAttr("boosterMaxVelocityPenalty"))

View File

@@ -1,7 +1,7 @@
# boosterShieldCapacityPenalty
#
# Used by:
# Implants from group: Booster (12 of 37)
# Implants from group: Booster (12 of 42)
type = "boosterSideEffect"
def handler(fit, booster, context):
fit.ship.boostItemAttr("shieldCapacity", booster.getModifiedItemAttr("boosterShieldCapacityPenalty"))

View File

@@ -1,7 +1,7 @@
# boosterTurretOptimalRangePenalty
#
# Used by:
# Implants from group: Booster (9 of 37)
# Implants from group: Booster (9 of 42)
type = "boosterSideEffect"
def handler(fit, booster, context):
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Gunnery"),

View File

@@ -1,7 +1,7 @@
# capacitorCapacityBonus
#
# Used by:
# Modules from group: Capacitor Battery (27 of 27)
# Modules from group: Capacitor Battery (22 of 22)
type = "passive"
def handler(fit, ship, context):
fit.ship.increaseItemAttr("capacitorCapacity", ship.getModifiedItemAttr("capacitorBonus"))

View File

@@ -2,9 +2,9 @@
#
# Used by:
# Implants named like: Hardwiring Zainou 'Sharpshooter' ZMX (6 of 6)
# Skill: Citadel Torpedoes
# Skill: XL Torpedoes
type = "passive"
def handler(fit, container, context):
level = container.level if "skill" in context else 1
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Citadel Torpedoes"),
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("XL Torpedoes"),
"emDamage", container.getModifiedItemAttr("damageMultiplierBonus") * level)

View File

@@ -2,9 +2,9 @@
#
# Used by:
# Implants named like: Hardwiring Zainou 'Sharpshooter' ZMX (6 of 6)
# Skill: Citadel Torpedoes
# Skill: XL Torpedoes
type = "passive"
def handler(fit, container, context):
level = container.level if "skill" in context else 1
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Citadel Torpedoes"),
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("XL Torpedoes"),
"explosiveDamage", container.getModifiedItemAttr("damageMultiplierBonus") * level)

View File

@@ -2,9 +2,9 @@
#
# Used by:
# Implants named like: Hardwiring Zainou 'Sharpshooter' ZMX (6 of 6)
# Skill: Citadel Torpedoes
# Skill: XL Torpedoes
type = "passive"
def handler(fit, container, context):
level = container.level if "skill" in context else 1
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Citadel Torpedoes"),
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("XL Torpedoes"),
"kineticDamage", container.getModifiedItemAttr("damageMultiplierBonus") * level)

View File

@@ -2,9 +2,9 @@
#
# Used by:
# Implants named like: Hardwiring Zainou 'Sharpshooter' ZMX (6 of 6)
# Skill: Citadel Torpedoes
# Skill: XL Torpedoes
type = "passive"
def handler(fit, container, context):
level = container.level if "skill" in context else 1
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Citadel Torpedoes"),
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("XL Torpedoes"),
"thermalDamage", container.getModifiedItemAttr("damageMultiplierBonus") * level)

View File

@@ -1,8 +1,8 @@
# capitalLauncherSkillCruiseCitadelEmDamage1
#
# Used by:
# Skill: Citadel Cruise Missiles
# Skill: XL Cruise Missiles
type = "passive"
def handler(fit, skill, context):
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Citadel Cruise Missiles"),
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("XL Cruise Missiles"),
"emDamage", skill.getModifiedItemAttr("damageMultiplierBonus") * skill.level)

View File

@@ -1,8 +1,8 @@
# capitalLauncherSkillCruiseCitadelExplosiveDamage1
#
# Used by:
# Skill: Citadel Cruise Missiles
# Skill: XL Cruise Missiles
type = "passive"
def handler(fit, skill, context):
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Citadel Cruise Missiles"),
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("XL Cruise Missiles"),
"explosiveDamage", skill.getModifiedItemAttr("damageMultiplierBonus") * skill.level)

View File

@@ -1,8 +1,8 @@
# capitalLauncherSkillCruiseCitadelKineticDamage1
#
# Used by:
# Skill: Citadel Cruise Missiles
# Skill: XL Cruise Missiles
type = "passive"
def handler(fit, skill, context):
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Citadel Cruise Missiles"),
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("XL Cruise Missiles"),
"kineticDamage", skill.getModifiedItemAttr("damageMultiplierBonus") * skill.level)

View File

@@ -1,8 +1,8 @@
# capitalLauncherSkillCruiseCitadelThermalDamage1
#
# Used by:
# Skill: Citadel Cruise Missiles
# Skill: XL Cruise Missiles
type = "passive"
def handler(fit, skill, context):
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Citadel Cruise Missiles"),
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("XL Cruise Missiles"),
"thermalDamage", skill.getModifiedItemAttr("damageMultiplierBonus") * skill.level)

View File

@@ -1,7 +1,7 @@
# damageControl
#
# Used by:
# Modules from group: Damage Control (14 of 14)
# Modules from group: Damage Control (17 of 17)
type = "passive"
def handler(fit, module, context):
for layer, attrPrefix in (('shield', 'shield'), ('armor', 'armor'), ('hull', '')):

View File

@@ -2,7 +2,6 @@
#
# Used by:
# Drones from group: Stasis Webifying Drone (3 of 3)
# Modules from group: Stasis Web (19 of 19)
type = "active", "projected"
def handler(fit, module, context):
if "projected" not in context:

View File

@@ -1,7 +1,7 @@
# droneDamageBonusOnline
#
# Used by:
# Modules from group: Drone Damage Modules (10 of 10)
# Modules from group: Drone Damage Modules (11 of 11)
type = "passive"
def handler(fit, module, context):
fit.drones.filteredItemBoost(lambda drone: drone.item.requiresSkill("Drones"),

View File

@@ -1,7 +1,7 @@
# droneTrackingComputerBonus
#
# Used by:
# Modules from group: Drone Tracking Modules (8 of 8)
# Modules from group: Drone Tracking Modules (10 of 10)
type = "active"
def handler(fit, module, context):
fit.drones.filteredItemBoost(lambda drone: drone.item.requiresSkill("Drones"),

View File

@@ -1,7 +1,7 @@
# droneTrackingEnhancerBonus
#
# Used by:
# Modules from group: Drone Tracking Enhancer (9 of 9)
# Modules from group: Drone Tracking Enhancer (10 of 10)
type = "passive"
def handler(fit, module, context):
fit.drones.filteredItemBoost(lambda drone: drone.item.requiresSkill("Drones"),

View File

@@ -1,7 +1,7 @@
# ecmBurst
#
# Used by:
# Modules from group: ECM Burst (7 of 7)
# Modules from group: Burst Jammer (11 of 11)
type = "active"
def handler(fit, module, context):
pass

View File

@@ -4,6 +4,7 @@
# Implants named like: Inherent Implants 'Squire' Capacitor Management EM (6 of 6)
# Implants named like: Mindflood Booster (4 of 4)
# Modules named like: Semiconductor Memory Cell (8 of 8)
# Implant: Antipharmakon Aeolis
# Implant: Genolution Core Augmentation CA-1
# Skill: Capacitor Management
type = "passive"

View File

@@ -1,7 +1,7 @@
# energyWeaponDamageMultiply
#
# Used by:
# Modules from group: Heat Sink (25 of 25)
# Modules from group: Heat Sink (18 of 18)
# Modules named like: QA Multiship Module Players (4 of 4)
# Module: QA Damage Module
type = "passive"

View File

@@ -1,7 +1,7 @@
# energyWeaponSpeedMultiply
#
# Used by:
# Modules from group: Heat Sink (25 of 25)
# Modules from group: Heat Sink (18 of 18)
type = "passive"
def handler(fit, module, context):
fit.modules.filteredItemMultiply(lambda mod: mod.item.group.name == "Energy Weapon",

View File

@@ -1,8 +0,0 @@
# ewSkillEcmBurstFalloffBonus
#
# Used by:
# Skill: Frequency Modulation
type = "passive"
def handler(fit, skill, context):
fit.modules.filteredItemBoost(lambda mod: mod.item.group.name == "Burst Jammer",
"falloffEffectiveness", skill.getModifiedItemAttr("falloffBonus") * skill.level)

View File

@@ -1,7 +1,6 @@
# ewTargetPaint
#
# Used by:
# Modules from group: Target Painter (9 of 9)
# Drones named like: TP (3 of 3)
type = "projected", "active"
def handler(fit, container, context):

View File

@@ -1,7 +1,6 @@
# ewTestEffectJam
#
# Used by:
# Modules from group: ECM (44 of 44)
# Drones named like: EC (3 of 3)
type = "projected", "active"
def handler(fit, module, context):

View File

@@ -1,7 +1,7 @@
# gunneryFalloffBonusOnline
#
# Used by:
# Modules from group: Tracking Enhancer (17 of 17)
# Modules from group: Tracking Enhancer (10 of 10)
# Module: QA Damage Module
type = "passive"
def handler(fit, module, context):

View File

@@ -1,7 +1,7 @@
# gunneryMaxRangeBonusOnline
#
# Used by:
# Modules from group: Tracking Enhancer (17 of 17)
# Modules from group: Tracking Enhancer (10 of 10)
# Module: QA Damage Module
type = "passive"
def handler(fit, module, context):

View File

@@ -1,7 +1,7 @@
# gunneryMaxRangeFalloffTrackingSpeedBonus
#
# Used by:
# Modules from group: Tracking Computer (14 of 14)
# Modules from group: Tracking Computer (11 of 11)
type = "active"
def handler(fit, module, context):
for attr in ("maxRange", "falloff", "trackingSpeed"):

View File

@@ -1,7 +1,7 @@
# gunneryTrackingSpeedBonusOnline
#
# Used by:
# Modules from group: Tracking Enhancer (17 of 17)
# Modules from group: Tracking Enhancer (10 of 10)
# Module: QA Damage Module
type = "passive"
def handler(fit, module, context):

View File

@@ -1,7 +1,7 @@
# hybridWeaponDamageMultiply
#
# Used by:
# Modules from group: Magnetic Field Stabilizer (20 of 20)
# Modules from group: Magnetic Field Stabilizer (12 of 12)
# Modules named like: QA Multiship Module Players (4 of 4)
# Module: QA Damage Module
type = "passive"

View File

@@ -1,7 +1,7 @@
# hybridWeaponSpeedMultiply
#
# Used by:
# Modules from group: Magnetic Field Stabilizer (20 of 20)
# Modules from group: Magnetic Field Stabilizer (12 of 12)
type = "passive"
def handler(fit, module, context):
fit.modules.filteredItemMultiply(lambda mod: mod.item.group.name == "Hybrid Weapon",

View File

@@ -3,6 +3,7 @@
# Used by:
# Implants named like: Zainou 'Deadeye' Missile Bombardment MB (6 of 6)
# Modules named like: Rocket Fuel Cache Partition (8 of 8)
# Implant: Antipharmakon Toxot
# Skill: Missile Bombardment
type = "passive"
def handler(fit, container, context):

View File

@@ -1,7 +1,7 @@
# missileDMGBonus
#
# Used by:
# Modules from group: Ballistic Control system (21 of 21)
# Modules from group: Ballistic Control system (17 of 17)
# Modules named like: QA Multiship Module Players (4 of 4)
type = "passive"
def handler(fit, container, context):

View File

@@ -1,7 +1,7 @@
# missileLauncherSpeedMultiplier
#
# Used by:
# Modules from group: Ballistic Control system (21 of 21)
# Modules from group: Ballistic Control system (17 of 17)
type = "passive"
def handler(fit, module, context):
fit.modules.filteredItemMultiply(lambda mod: mod.item.requiresSkill("Missile Launcher Operation"),

View File

@@ -1,3 +1,7 @@
# modifyEnergyWarfareResistance
#
# Used by:
# Modules from group: Capacitor Battery (22 of 22)
type = "passive"
def handler(fit, module, context):
fit.ship.boostItemAttr("energyWarfareResistance",

View File

@@ -1,8 +0,0 @@
# neutAttackReflect
#
# Used by:
# Modules from group: Capacitor Battery (27 of 27)
type = "passive"
def handler(fit, module, context):
fit.ship.boostItemAttr("neutReflector", module.getModifiedItemAttr("capAttackReflector"),
stackingPenalties = True)

View File

@@ -1,7 +0,0 @@
# neutReflectAmount
#
# Used by:
# Modules from group: Capacitor Battery (27 of 27)
type = "passive"
def handler(fit, module, context):
fit.ship.boostItemAttr("neutReflectAmount", module.getModifiedItemAttr("neutReflectAmountBonus"))

View File

@@ -1,8 +0,0 @@
# nosAttackReflect
#
# Used by:
# Modules from group: Capacitor Battery (27 of 27)
type = "passive"
def handler(fit, module, context):
fit.ship.boostItemAttr("nosReflector", module.getModifiedItemAttr("capAttackReflector"),
stackingPenalties = True)

View File

@@ -1,7 +0,0 @@
# nosReflectAmount
#
# Used by:
# Modules from group: Capacitor Battery (27 of 27)
type = "passive"
def handler(fit, module, context):
fit.ship.boostItemAttr("nosReflectAmount", module.getModifiedItemAttr("nosReflectAmountBonus"))

View File

@@ -1,13 +1,9 @@
# overloadRofBonus
#
# Used by:
# Modules from group: Energy Weapon (100 of 187)
# Modules from group: Hybrid Weapon (110 of 202)
# Modules from group: Missile Launcher Citadel (4 of 4)
# Modules from group: Missile Launcher Heavy (12 of 12)
# Modules from group: Missile Launcher Rocket (15 of 15)
# Modules from group: Projectile Weapon (60 of 146)
# Modules named like: Launcher (125 of 138)
# Modules from group: Missile Launcher Torpedo (22 of 22)
# Items from market group: Ship Equipment > Turrets & Bays (397 of 767)
# Module: Interdiction Sphere Launcher I
type = "overheat"
def handler(fit, module, context):
module.boostItemAttr("speed", module.getModifiedItemAttr("overloadRofBonus"))

View File

@@ -1,10 +0,0 @@
# overloadSelfECCMStrenghtBonus
#
# Used by:
# Modules from group: ECCM (44 of 44)
# Modules from group: Projected ECCM (7 of 7)
type = "overheat"
def handler(fit, module, context):
for scanType in ("Gravimetric", "Magnetometric", "Radar", "Ladar"):
module.boostItemAttr("scan%sStrengthPercent" % scanType,
module.getModifiedItemAttr("overloadECCMStrenghtBonus"))

View File

@@ -1,8 +1,8 @@
# overloadSelfECMStrenghtBonus
#
# Used by:
# Modules from group: ECM (44 of 44)
# Modules from group: ECM Burst (7 of 7)
# Modules from group: Burst Jammer (11 of 11)
# Modules from group: ECM (39 of 39)
type = "overheat"
def handler(fit, module, context):
if "projected" not in context:

View File

@@ -1,7 +1,7 @@
# overloadSelfPainterBonus
#
# Used by:
# Modules from group: Target Painter (9 of 9)
# Modules from group: Target Painter (8 of 8)
type = "overheat"
def handler(fit, module, context):
module.boostItemAttr("signatureRadiusBonus", module.getModifiedItemAttr("overloadPainterStrengthBonus") or 0)

View File

@@ -1,7 +1,8 @@
# overloadSelfRangeBonus
#
# Used by:
# Modules from group: Stasis Web (19 of 19)
# Modules from group: Stasis Grappler (7 of 7)
# Modules from group: Stasis Web (18 of 18)
# Modules from group: Warp Scrambler (38 of 39)
type = "overheat"
def handler(fit, module, context):

View File

@@ -2,8 +2,8 @@
#
# Used by:
# Modules from group: Remote Sensor Booster (8 of 8)
# Modules from group: Remote Sensor Damper (8 of 8)
# Modules from group: Sensor Booster (12 of 12)
# Modules from group: Sensor Booster (16 of 16)
# Modules from group: Sensor Dampener (6 of 6)
type = "overheat"
def handler(fit, module, context):
module.boostItemAttr("maxTargetRangeBonus", module.getModifiedItemAttr("overloadSensorModuleStrengthBonus"))

View File

@@ -1,9 +1,8 @@
# overloadSelfTrackingModuleBonus
#
# Used by:
# Modules from group: Drone Tracking Modules (8 of 8)
# Modules from group: Remote Tracking Computer (10 of 10)
# Modules from group: Tracking Computer (14 of 14)
# Modules from group: Drone Tracking Modules (10 of 10)
# Modules named like: Tracking Computer (19 of 19)
# Variations of module: Tracking Disruptor I (6 of 6)
type = "overheat"
def handler(fit, module, context):

View File

@@ -1,7 +1,7 @@
# projectileWeaponDamageMultiply
#
# Used by:
# Modules from group: Gyrostabilizer (20 of 20)
# Modules from group: Gyrostabilizer (12 of 12)
# Modules named like: QA Multiship Module Players (4 of 4)
# Module: QA Damage Module
type = "passive"

View File

@@ -1,7 +1,7 @@
# projectileWeaponSpeedMultiply
#
# Used by:
# Modules from group: Gyrostabilizer (20 of 20)
# Modules from group: Gyrostabilizer (12 of 12)
type = "passive"
def handler(fit, module, context):
fit.modules.filteredItemMultiply(lambda mod: mod.item.group.name == "Projectile Weapon",

View File

@@ -1,3 +1,7 @@
# remoteECMFalloff
#
# Used by:
# Modules from group: ECM (39 of 39)
type = "projected", "active"
def handler(fit, module, context):
if "projected" in context:

View File

@@ -1,4 +1,4 @@
# targetMissileDisruptorHostile
# remoteGuidanceDisruptFalloff
#
# Used by:
# Variations of module: Guidance Disruptor I (6 of 6)

View File

@@ -1,3 +1,7 @@
# remoteSensorBoostFalloff
#
# Used by:
# Modules from group: Remote Sensor Booster (8 of 8)
type= "projected", "active"
def handler(fit, module, context):
if "projected" not in context:

View File

@@ -1,3 +1,7 @@
# remoteSensorDampFalloff
#
# Used by:
# Modules from group: Sensor Dampener (6 of 6)
type= "projected", "active"
def handler(fit, module, context):
if "projected" not in context:

View File

@@ -1,3 +1,7 @@
# remoteTargetPaintFalloff
#
# Used by:
# Modules from group: Target Painter (8 of 8)
type = "projected", "active"
def handler(fit, container, context):
if "projected" in context:

View File

@@ -1,3 +1,7 @@
# remoteTrackingAssistFalloff
#
# Used by:
# Modules from group: Remote Tracking Computer (8 of 8)
type= "projected", "active"
def handler(fit, module, context):
if "projected" in context:

View File

@@ -1,4 +1,4 @@
# targetGunneryMaxRangeAndTrackingSpeedAndFalloffBonusHostile
# remoteTrackingDisruptFalloff
#
# Used by:
# Variations of module: Tracking Disruptor I (6 of 6)

View File

@@ -1,3 +1,8 @@
# remoteWebifierFalloff
#
# Used by:
# Modules from group: Stasis Grappler (7 of 7)
# Modules from group: Stasis Web (18 of 18)
type = "active", "projected"
def handler(fit, module, context):
if "projected" not in context: return

View File

@@ -1,7 +1,6 @@
# scanStrengthBonusPercentActivate
#
# Used by:
# Modules from group: ECCM (44 of 44)
# Module: QA ECCM
type = "active"
def handler(fit, module, context):

View File

@@ -1,7 +1,7 @@
# scanStrengthBonusPercentOnline
#
# Used by:
# Modules from group: Sensor Backup Array (72 of 72)
# Modules from group: Signal Amplifier (7 of 7)
type = "passive"
def handler(fit, module, context):
for type in ("Gravimetric", "Magnetometric", "Radar", "Ladar"):

View File

@@ -1,11 +0,0 @@
# scanStrengthTargetPercentBonus
#
# Used by:
# Modules from group: Projected ECCM (7 of 7)
type = "projected", "active"
def handler(fit, module, context):
if "projected" not in context: return
for type in ("Gravimetric", "Magnetometric", "Radar", "Ladar"):
fit.ship.boostItemAttr("scan%sStrength" % type,
module.getModifiedItemAttr("scan%sStrengthPercent" % type),
stackingPenalties = True)

View File

@@ -1,7 +1,7 @@
# scriptSensorBoosterMaxTargetRangeBonusBonus
#
# Used by:
# Charges from group: Sensor Booster Script (2 of 2)
# Charges from group: Sensor Booster Script (3 of 3)
# Charges from group: Sensor Dampener Script (2 of 2)
type = "passive"
def handler(fit, module, context):

View File

@@ -1,7 +1,7 @@
# scriptSensorBoosterScanResolutionBonusBonus
#
# Used by:
# Charges from group: Sensor Booster Script (2 of 2)
# Charges from group: Sensor Booster Script (3 of 3)
# Charges from group: Sensor Dampener Script (2 of 2)
type = "passive"
def handler(fit, module, context):

View File

@@ -1,3 +1,7 @@
# scriptSensorBoosterSensorStrengthBonusBonus
#
# Used by:
# Charges from group: Sensor Booster Script (3 of 3)
type = "active"
def handler(fit, module, context):
for scanType in ("Gravimetric", "Magnetometric", "Radar", "Ladar"):

View File

@@ -1,7 +1,7 @@
# sensorBoosterActivePercentage
#
# Used by:
# Modules from group: Sensor Booster (12 of 12)
# Modules from group: Sensor Booster (16 of 16)
type = "active"
def handler(fit, module, context):
fit.ship.boostItemAttr("maxTargetRange", module.getModifiedItemAttr("maxTargetRangeBonus"),

View File

@@ -2,6 +2,7 @@
#
# Used by:
# Implants named like: Blue Pill Booster (5 of 5)
# Implant: Antipharmakon Thureo
type = "passive"
def handler(fit, container, context):
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Operation") or mod.item.requiresSkill("Capital Shield Operation"),

View File

@@ -4,5 +4,5 @@
# Ship: Phoenix
type = "passive"
def handler(fit, ship, context):
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Citadel Cruise Missiles"),
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("XL Cruise Missiles"),
"speed", ship.getModifiedItemAttr("dreadnoughtShipBonusC1"), skill="Caldari Dreadnought")

View File

@@ -4,5 +4,5 @@
# Ship: Phoenix
type = "passive"
def handler(fit, ship, context):
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Citadel Torpedoes"),
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("XL Torpedoes"),
"speed", ship.getModifiedItemAttr("dreadnoughtShipBonusC1"), skill="Caldari Dreadnought")

View File

@@ -1,3 +1,7 @@
# shipBonusRemoteTrackingComputerFalloffGC2
#
# Used by:
# Ship: Oneiros
type = "passive"
def handler(fit, ship, context):
fit.modules.filteredItemBoost(lambda mod: mod.item.group.name == "Remote Tracking Computer",

View File

@@ -1,3 +1,7 @@
# shipBonusRemoteTrackingComputerFalloffMC
#
# Used by:
# Ship: Scimitar
type = "passive"
def handler(fit, ship, context):
fit.modules.filteredItemBoost(lambda mod: mod.item.group.name == "Remote Tracking Computer",

View File

@@ -1,7 +1,7 @@
# shipMaxLockedTargetsBonusAddOnline
#
# Used by:
# Modules from group: Signal Amplifier (11 of 11)
# Modules from group: Signal Amplifier (7 of 7)
type = "passive"
def handler(fit, module, context):
fit.ship.increaseItemAttr("maxLockedTargets", module.getModifiedItemAttr("maxLockedTargetsBonus"))

View File

@@ -1,7 +1,7 @@
# shipMaxTargetRangeBonusOnline
#
# Used by:
# Modules from group: Signal Amplifier (11 of 11)
# Modules from group: Signal Amplifier (7 of 7)
type = "passive"
def handler(fit, module, context):
fit.ship.boostItemAttr("maxTargetRange", module.getModifiedItemAttr("maxTargetRangeBonus"),

View File

@@ -1,7 +1,7 @@
# shipScanResolutionBonusOnline
#
# Used by:
# Modules from group: Signal Amplifier (11 of 11)
# Modules from group: Signal Amplifier (7 of 7)
# Module: QA Damage Module
type = "passive"
def handler(fit, module, context):

View File

@@ -18,12 +18,12 @@ def handler(fit, module, context):
#Missiles
for type in ("kinetic", "thermal", "explosive", "em"):
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Citadel Torpedoes") or \
mod.charge.requiresSkill("Citadel Cruise Missiles"),
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("XL Torpedoes") or \
mod.charge.requiresSkill("XL Cruise Missiles"),
"%sDamage" % type, module.getModifiedItemAttr("damageMultiplierBonus"))
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Citadel Torpedoes") or \
mod.charge.requiresSkill("Citadel Cruise Missiles"),
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("XL Torpedoes") or \
mod.charge.requiresSkill("XL Cruise Missiles"),
"aoeVelocity", module.getModifiedItemAttr("aoeVelocityBonus"))
#Shield Boosters

View File

@@ -1,16 +0,0 @@
# targetGunneryMaxRangeFalloffTrackingSpeedBonusAssistance
#
# Used by:
# Modules from group: Remote Tracking Computer (10 of 10)
type= "projected", "active"
def handler(fit, module, context):
if "projected" in context:
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Gunnery"),
"trackingSpeed", module.getModifiedItemAttr("trackingSpeedBonus"),
stackingPenalties = True)
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Gunnery"),
"maxRange", module.getModifiedItemAttr("maxRangeBonus"),
stackingPenalties = True)
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Gunnery"),
"falloff", module.getModifiedItemAttr("falloffBonus"),
stackingPenalties = True)

View File

@@ -1,13 +0,0 @@
# targetMaxTargetRangeAndScanResolutionBonusAssistance
#
# Used by:
# Modules from group: Remote Sensor Booster (8 of 8)
type= "projected", "active"
def handler(fit, module, context):
if "projected" not in context:
return
fit.ship.boostItemAttr("maxTargetRange", module.getModifiedItemAttr("maxTargetRangeBonus"),
stackingPenalties = True)
fit.ship.boostItemAttr("scanResolution", module.getModifiedItemAttr("scanResolutionBonus"),
stackingPenalties = True)

View File

@@ -1,12 +0,0 @@
# targetMaxTargetRangeAndScanResolutionBonusHostile
#
# Used by:
# Modules from group: Remote Sensor Damper (8 of 8)
type= "projected", "active"
def handler(fit, module, context):
if "projected" not in context:
return
fit.ship.boostItemAttr("maxTargetRange", module.getModifiedItemAttr("maxTargetRangeBonus"),
stackingPenalties = True)
fit.ship.boostItemAttr("scanResolution", module.getModifiedItemAttr("scanResolutionBonus"),
stackingPenalties = True)

View File

@@ -3,6 +3,7 @@
# Used by:
# Implants named like: Drop Booster (4 of 4)
# Implants named like: Eifyr and Co. 'Gunslinger' Motion Prediction MR (6 of 6)
# Implant: Antipharmakon Iokira
# Implant: Ogdin's Eye Coordination Enhancer
# Skill: Motion Prediction
type = "passive"

View File

@@ -1,9 +1,9 @@
# useMissiles
#
# Used by:
# Modules from group: Missile Launcher Citadel (4 of 4)
# Modules from group: Missile Launcher Heavy (12 of 12)
# Modules from group: Missile Launcher Rocket (15 of 15)
# Modules from group: XL Missile Launcher (4 of 4)
# Modules named like: Launcher (138 of 138)
type = 'active'
def handler(fit, module, context):

View File

@@ -20,7 +20,7 @@
from sqlalchemy.orm import validates, reconstructor
from eos.effectHandlerHelpers import HandledItem
from eos.effectHandlerHelpers import HandledItem, HandledImplantBoosterList
import eos.db
import eos
import logging
@@ -100,7 +100,7 @@ class Character(object):
for item in self.getSkillList():
self.addSkill(Skill(item.ID, self.defaultLevel))
self.__implants = eos.saveddata.fit.HandledImplantBoosterList()
self.__implants = HandledImplantBoosterList()
self.apiKey = None
@reconstructor

View File

@@ -31,6 +31,8 @@ import eos.db
import time
import copy
from utils.timer import Timer
from eos.enum import Enum
import logging
@@ -41,6 +43,10 @@ try:
except ImportError:
from utils.compat import OrderedDict
class ImplantLocation(Enum):
FIT = 0
CHARACTER = 1
class Fit(object):
"""Represents a fitting, with modules, ship, implants, etc."""
@@ -318,17 +324,20 @@ class Fit(object):
return -log(0.25) * agility * mass / 1000000
@property
def implantSource(self):
return self.implantLocation
@implantSource.setter
def implantSource(self, source):
self.implantLocation = source
@property
def appliedImplants(self):
implantsBySlot = {}
if self.character:
for implant in self.character.implants:
implantsBySlot[implant.slot] = implant
for implant in self.implants:
implantsBySlot[implant.slot] = implant
return implantsBySlot.values()
if self.implantLocation == ImplantLocation.CHARACTER:
return self.character.implants
else:
return self.implants
@validates("ID", "ownerID", "shipID")
def validator(self, key, val):
@@ -823,7 +832,9 @@ class Fit(object):
return 10 / rechargeRate * sqrt(percent) * (1 - sqrt(percent)) * capacity
def addDrain(self, cycleTime, capNeed, clipSize=0):
self.__extraDrains.append((cycleTime, capNeed, clipSize))
""" Used for both cap drains and cap fills (fills have negative capNeed) """
resistance = self.ship.getModifiedItemAttr("energyWarfareResistance") or 1 if capNeed > 0 else 1
self.__extraDrains.append((cycleTime, capNeed * resistance, clipSize))
def removeDrain(self, i):
del self.__extraDrains[i]

View File

@@ -416,10 +416,10 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
# Check this only if we're told to do so
if hardpointLimit:
if self.hardpoint == Hardpoint.TURRET:
if fit.ship.getModifiedItemAttr('turretSlotsLeft') - fit.getHardpointsUsed(Hardpoint.TURRET) < 1:
if (fit.ship.getModifiedItemAttr('turretSlotsLeft') or 0) - fit.getHardpointsUsed(Hardpoint.TURRET) < 1:
return False
elif self.hardpoint == Hardpoint.MISSILE:
if fit.ship.getModifiedItemAttr('launcherSlotsLeft') - fit.getHardpointsUsed(Hardpoint.MISSILE) < 1:
if (fit.ship.getModifiedItemAttr('launcherSlotsLeft')or 0) - fit.getHardpointsUsed(Hardpoint.MISSILE) < 1:
return False
return True

View File

@@ -32,7 +32,7 @@ from eos.saveddata.implant import Implant
from eos.saveddata.booster import SideEffect
from eos.saveddata.booster import Booster
from eos.saveddata.ship import Ship
from eos.saveddata.fit import Fit
from eos.saveddata.fit import Fit, ImplantLocation
from eos.saveddata.mode import Mode
from eos.saveddata.fleet import Fleet, Wing, Squad
from eos.saveddata.miscData import MiscData

BIN
eve.db

Binary file not shown.

View File

@@ -16,7 +16,7 @@ class ItemStats(ContextMenu):
"implantItem", "boosterItem",
"skillItem", "projectedModule",
"projectedDrone", "projectedCharge",
"itemStats")
"itemStats", "implantItemChar")
def getText(self, itmContext, selection):
return "{0} Stats".format(itmContext if itmContext is not None else "Item")

View File

@@ -12,7 +12,8 @@ class MarketJump(ContextMenu):
"fittingCharge", "droneItem",
"implantItem", "boosterItem",
"projectedModule", "projectedDrone",
"projectedCharge", "cargoItem")
"projectedCharge", "cargoItem",
"implantItemChar")
if not srcContext in validContexts or selection is None or len(selection) < 1:
return False
@@ -33,12 +34,10 @@ class MarketJump(ContextMenu):
def activate(self, fullContext, selection, i):
srcContext = fullContext[0]
if srcContext in ("fittingModule", "droneItem", "implantItem",
"boosterItem", "projectedModule", "projectedDrone",
"cargoItem"):
item = selection[0].item
elif srcContext in ("fittingCharge", "projectedCharge"):
if srcContext in ("fittingCharge", "projectedCharge"):
item = selection[0].charge
elif hasattr(selection[0], "item"):
item = selection[0].item
else:
item = selection[0]

View File

@@ -23,7 +23,6 @@ from gui import builtinStatsViews
from gui.bitmapLoader import BitmapLoader
from gui.utils.numberFormatter import formatAmount
import service
import locale
class PriceViewFull(StatsView):
name = "priceViewFull"
@@ -107,15 +106,15 @@ class PriceViewFull(StatsView):
if self._cachedShip != shipPrice:
self.labelPriceShip.SetLabel("%s ISK" % formatAmount(shipPrice, 3, 3, 9, currency=True))
self.labelPriceShip.SetToolTip(wx.ToolTip(locale.format('%.2f', shipPrice, 1)))
self.labelPriceShip.SetToolTip(wx.ToolTip('{:,.2f}'.format(shipPrice)))
self._cachedShip = shipPrice
if self._cachedFittings != modPrice:
self.labelPriceFittings.SetLabel("%s ISK" % formatAmount(modPrice, 3, 3, 9, currency=True))
self.labelPriceFittings.SetToolTip(wx.ToolTip(locale.format('%.2f', modPrice, 1)))
self.labelPriceFittings.SetToolTip(wx.ToolTip('{:,.2f}'.format(modPrice)))
self._cachedFittings = modPrice
if self._cachedTotal != (shipPrice+modPrice):
self.labelPriceTotal.SetLabel("%s ISK" % formatAmount(shipPrice + modPrice, 3, 3, 9, currency=True))
self.labelPriceTotal.SetToolTip(wx.ToolTip(locale.format('%.2f', (shipPrice + modPrice), 1)))
self.labelPriceTotal.SetToolTip(wx.ToolTip('{:,.2f}'.format(shipPrice + modPrice)))
self._cachedTotal = shipPrice + modPrice
self.panel.Layout()

View File

@@ -22,7 +22,6 @@ from gui.statsView import StatsView
from gui import builtinStatsViews
from gui.utils.numberFormatter import formatAmount
import locale
try:
from collections import OrderedDict
except ImportError:
@@ -201,17 +200,15 @@ class TargetingMiscViewFull(StatsView):
label.SetToolTip(wx.ToolTip("Type: %s" % (fit.scanType)))
elif labelName == "labelFullAlignTime":
alignTime = "Align:\t%.3fs"%mainValue
mass = "Mass:\t%skg"%locale.format('%d', fit.ship.getModifiedItemAttr("mass"), 1)
mass = 'Mass:\t{:,.0f}kg'.format(fit.ship.getModifiedItemAttr("mass"))
agility = "Agility:\t%.3fx"%fit.ship.getModifiedItemAttr("agility")
label.SetToolTip(wx.ToolTip("%s\n%s\n%s" % (alignTime, mass, agility)))
elif labelName == "labelFullCargo":
tipLines = []
tipLines.append(u"Cargohold: %sm\u00B3 / %sm\u00B3"% (
locale.format('%.2f', fit.cargoBayUsed, 1),
locale.format('%.2f', newValues["main"], 1)))
tipLines.append(u"Cargohold: {:,.2f}m\u00B3 / {:,.2f}m\u00B3".format(fit.cargoBayUsed, newValues["main"]))
for attrName, tipAlias in cargoNamesOrder.items():
if newValues[attrName] > 0:
tipLines.append(u"%s: %sm\u00B3"% (tipAlias, locale.format('%.2f', newValues[attrName], 1)))
tipLines.append(u"{}: {:,.2f}m\u00B3".format(tipAlias, newValues[attrName]))
label.SetToolTip(wx.ToolTip(u"\n".join(tipLines)))
else:
label.SetToolTip(wx.ToolTip("%.1f" % mainValue))
@@ -237,12 +234,10 @@ class TargetingMiscViewFull(StatsView):
# if you add stuff to cargo, the capacity doesn't change and thus it is still cached
# This assures us that we force refresh of cargo tooltip
tipLines = []
tipLines.append(u"Cargohold: %sm\u00B3 / %sm\u00B3"% (
locale.format('%.2f', fit.cargoBayUsed, 1),
locale.format('%.2f', cachedCargo["main"], 1)))
tipLines.append(u"Cargohold: {:,.2f}m\u00B3 / {:,.2f}m\u00B3".format(fit.cargoBayUsed, cachedCargo["main"]))
for attrName, tipAlias in cargoNamesOrder.items():
if cachedCargo[attrName] > 0:
tipLines.append(u"%s: %sm\u00B3"% (tipAlias, locale.format('%.2f', cachedCargo[attrName], 1)))
tipLines.append(u"{}: {:,.2f}m\u00B3".format(tipAlias, cachedCargo[attrName]))
label.SetToolTip(wx.ToolTip(u"\n".join(tipLines)))
else:
label.SetToolTip(wx.ToolTip(""))

View File

@@ -2,7 +2,7 @@ from gui import builtinViewColumns
from gui.viewColumn import ViewColumn
from gui.bitmapLoader import BitmapLoader
import wx
from eos.types import Drone, Fit, Module, Slot, Rack
from eos.types import Drone, Fit, Module, Slot, Rack, Implant
class BaseIcon(ViewColumn):
name = "Base Icon"
@@ -21,6 +21,11 @@ class BaseIcon(ViewColumn):
return self.shipImage
if isinstance(stuff, Rack):
return -1
if isinstance(stuff, Implant):
if stuff.character: # if it has a character as it's parent
return self.fittingView.imageList.GetImageIndex("character_small", "gui")
else:
return self.shipImage
if isinstance(stuff, Module):
if stuff.isEmpty:
return self.fittingView.imageList.GetImageIndex("slot_%s_small" % Slot.getName(stuff.slot).lower(), "gui")

View File

@@ -22,7 +22,7 @@ from gui.viewColumn import ViewColumn
import gui.mainFrame
import wx
from eos.types import Drone, Cargo, Fit, Module, Slot, Rack
from eos.types import Drone, Cargo, Fit, Module, Slot, Rack, Implant
import service
class BaseName(ViewColumn):
@@ -61,6 +61,8 @@ class BaseName(ViewColumn):
return "%s Slot" % Slot.getName(stuff.slot).capitalize()
else:
return stuff.item.name
elif isinstance(stuff, Implant):
return stuff.item.name
else:
item = getattr(stuff, "item", stuff)

View File

@@ -22,7 +22,7 @@ from gui.bitmapLoader import BitmapLoader
import gui.mainFrame
import wx
from eos.types import Drone, Module, Rack, Fit
from eos.types import Drone, Module, Rack, Fit, Implant
from eos.types import State as State_
class State(ViewColumn):
@@ -67,6 +67,9 @@ class State(ViewColumn):
if projectionInfo.active:
return generic_active
return generic_inactive
elif isinstance(stuff, Implant) and stuff.character:
# if we're showing character implants, show an "online" state, which should not be changed
return self.fittingView.imageList.GetImageIndex("state_%s_small" % State_.getName(0).lower(), "gui")
else:
active = getattr(stuff, "active", None)
if active is None:

View File

@@ -29,6 +29,9 @@ from gui.contextMenu import ContextMenu
from wx.lib.buttons import GenBitmapButton
import gui.globalEvents as GE
import gui.PFSearchBox as SBox
from gui.marketBrowser import SearchBox
class CharacterEditor(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__ (self, parent, id=wx.ID_ANY, title=u"pyfa: Character Editor", pos=wx.DefaultPosition,
@@ -38,8 +41,8 @@ class CharacterEditor(wx.Frame):
self.SetIcon(i)
self.mainFrame = parent
#self.disableWin = wx.WindowDisabler(self)
self.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNFACE ) )
mainSizer = wx.BoxSizer(wx.VERTICAL)
@@ -94,19 +97,11 @@ class CharacterEditor(wx.Frame):
self.viewsNBContainer = wx.Notebook(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, 0)
self.sview = SkillTreeView(self.viewsNBContainer)
#self.iview = ImplantsTreeView(self.viewsNBContainer)
#=======================================================================
# RC2
#self.iview.Show(False)
#=======================================================================
self.iview = ImplantsTreeView(self.viewsNBContainer)
self.aview = APIView(self.viewsNBContainer)
self.viewsNBContainer.AddPage(self.sview, "Skills")
#=======================================================================
# Disabled for RC2
# self.viewsNBContainer.AddPage(self.iview, "Implants")
#=======================================================================
self.viewsNBContainer.AddPage(self.iview, "Implants")
self.viewsNBContainer.AddPage(self.aview, "API")
mainSizer.Add(self.viewsNBContainer, 1, wx.EXPAND | wx.ALL, 5)
@@ -206,25 +201,14 @@ class CharacterEditor(wx.Frame):
def restrict(self):
self.btnRename.Enable(False)
self.btnDelete.Enable(False)
self.aview.stDisabledTip.Show()
self.aview.inputID.Enable(False)
self.aview.inputKey.Enable(False)
self.aview.charChoice.Enable(False)
self.aview.btnFetchCharList.Enable(False)
self.aview.btnFetchSkills.Enable(False)
self.aview.stStatus.SetLabel("")
self.aview.Layout()
self.iview.Enable(False)
self.aview.Enable(False)
def unrestrict(self):
self.btnRename.Enable(True)
self.btnDelete.Enable(True)
self.aview.stDisabledTip.Hide()
self.aview.inputID.Enable(True)
self.aview.inputKey.Enable(True)
self.aview.btnFetchCharList.Enable(True)
self.aview.btnFetchSkills.Enable(True)
self.aview.stStatus.SetLabel("")
self.aview.Layout()
self.iview.Enable(True)
self.aview.Enable(True)
def charChanged(self, event):
self.sview.populateSkillTree()
@@ -488,15 +472,26 @@ class ImplantsTreeView (wx.Panel):
def __init__(self, parent):
wx.Panel.__init__ (self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.Size(500, 300), style=wx.TAB_TRAVERSAL)
self.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW))
pmainSizer = wx.BoxSizer(wx.HORIZONTAL)
availableSizer = wx.BoxSizer(wx.VERTICAL)
pmainSizer.Add(availableSizer, 1, wx.ALL | wx.EXPAND, 5)
self.searchBox = SearchBox(self)
self.itemView = ItemView(self)
self.itemView.Hide()
availableSizer.Add(self.searchBox, 0, wx.EXPAND)
availableSizer.Add(self.itemView, 1, wx.EXPAND)
'''
self.availableImplantsSearch = wx.SearchCtrl(self, wx.ID_ANY, style=wx.TE_PROCESS_ENTER)
self.availableImplantsSearch.ShowCancelButton(True)
availableSizer.Add(self.availableImplantsSearch, 0, wx.BOTTOM | wx.EXPAND, 2)
'''
self.availableImplantsTree = wx.TreeCtrl(self, wx.ID_ANY, style=wx.TR_DEFAULT_STYLE | wx.TR_HIDE_ROOT)
root = self.availableRoot = self.availableImplantsTree.AddRoot("Available")
@@ -505,21 +500,32 @@ class ImplantsTreeView (wx.Panel):
availableSizer.Add(self.availableImplantsTree, 1, wx.EXPAND)
pmainSizer.Add(availableSizer, 1, wx.ALL | wx.EXPAND, 5)
buttonSizer = wx.BoxSizer(wx.VERTICAL)
pmainSizer.Add(buttonSizer, 0, wx.TOP, 5)
buttonSizer.AddSpacer(( 0, 0), 1)
#pmainSizer.Add(buttonSizer, 0, wx.TOP, 5)
self.btnAdd = GenBitmapButton(self, wx.ID_ADD, BitmapLoader.getBitmap("fit_add_small", "gui"), style = wx.BORDER_NONE)
buttonSizer.Add(self.btnAdd, 0)
self.btnRemove = GenBitmapButton(self, wx.ID_REMOVE, BitmapLoader.getBitmap("fit_delete_small", "gui"), style = wx.BORDER_NONE)
buttonSizer.Add(self.btnRemove, 0)
self.pluggedImplantsTree = AvailableImplantsView(self, style=wx.LC_SINGLE_SEL)
buttonSizer.AddSpacer(( 0, 0), 1)
pmainSizer.Add(buttonSizer, 0, wx.EXPAND, 0)
pmainSizer.Add(self.pluggedImplantsTree, 1, wx.ALL | wx.EXPAND, 5)
characterImplantSizer = wx.BoxSizer(wx.VERTICAL)
self.pluggedImplantsTree = AvailableImplantsView(self)
characterImplantSizer.Add(self.pluggedImplantsTree, 1, wx.ALL|wx.EXPAND, 5)
pmainSizer.Add(characterImplantSizer, 1, wx.EXPAND, 5)
self.SetSizer(pmainSizer)
# Populate the market tree
sMkt = service.Market.getInstance()
for mktGrp in sMkt.getImplantTree():
iconId = self.addMarketViewImage(sMkt.getIconByMarketGroup(mktGrp))
@@ -531,6 +537,9 @@ class ImplantsTreeView (wx.Panel):
#Bind the event to replace dummies by real data
self.availableImplantsTree.Bind(wx.EVT_TREE_ITEM_EXPANDING, self.expandLookup)
self.availableImplantsTree.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.addImplant)
self.itemView.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.itemActivated)
#Bind add & remove buttons
self.btnAdd.Bind(wx.EVT_BUTTON, self.addImplant)
@@ -538,9 +547,28 @@ class ImplantsTreeView (wx.Panel):
#Bind the change of a character*
self.Parent.Parent.Bind(GE.CHAR_CHANGED, self.charChanged)
self.Enable(False)
# We update with an empty list first to set the initial size for Layout(), then update later with actual
# implants for character. This helps with sizing issues.
self.update([])
self.Layout()
sChar = service.Character.getInstance()
charID = self.Parent.Parent.getActiveCharacter()
self.update(sChar.getImplants(charID))
def itemActivated(self, event):
sel = event.EventObject.GetFirstSelected()
item = self.itemView.items[sel]
if item:
sChar = service.Character.getInstance()
charID = self.Parent.Parent.getActiveCharacter()
sChar.addImplant(charID, item.ID)
self.update(sChar.getImplants(charID))
def update(self, implants):
self.implants = implants[:]
self.implants.sort(key=lambda i: int(i.getModifiedItemAttr("implantness")))
@@ -560,35 +588,35 @@ class ImplantsTreeView (wx.Panel):
def expandLookup(self, event):
tree = self.availableImplantsTree
root = event.Item
child, cookie = tree.GetFirstChild(root)
sMkt = service.Market.getInstance()
parent = event.Item
child, _ = tree.GetFirstChild(parent)
text = tree.GetItemText(child)
if text == "dummy" or text == "itemdummy":
sMkt = service.Market.getInstance()
#A DUMMY! Keeeel!!! EBUL DUMMY MUST DIAF!
tree.Delete(child)
# if the dummy item is a market group, replace with actual market groups
if text == "dummy":
#Add 'real stoof!' instead
for id, name, iconFile, more in sMkt.getChildren(tree.GetPyData(root)):
iconId = self.addMarketViewImage(iconFile)
childId = tree.AppendItem(root, name, iconId, data=wx.TreeItemData(id))
if more:
currentMktGrp = sMkt.getMarketGroup(tree.GetPyData(parent), eager="children")
for childMktGrp in sMkt.getMarketGroupChildren(currentMktGrp):
iconId = self.addMarketViewImage(sMkt.getIconByMarketGroup(childMktGrp))
childId = tree.AppendItem(parent, childMktGrp.name, iconId, data=wx.TreeItemData(childMktGrp.ID))
if sMkt.marketGroupHasTypesCheck(childMktGrp) is False:
tree.AppendItem(childId, "dummy")
else:
tree.AppendItem(childId, "itemdummy")
# replace dummy with actual items
if text == "itemdummy":
sMkt = service.Market.getInstance()
data, usedMetas = sMkt.getVariations(tree.GetPyData(root))
for item in data:
id = item.ID
name = item.name
iconFile = item.icon.iconFile
iconId = self.addMarketViewImage(iconFile)
tree.AppendItem(root, name, iconId, data=wx.TreeItemData(id))
currentMktGrp = sMkt.getMarketGroup(tree.GetPyData(parent))
items = sMkt.getItemsByMarketGroup(currentMktGrp)
for item in items:
iconId = self.addMarketViewImage(item.icon.iconFile)
tree.AppendItem(parent, item.name, iconId, data=wx.TreeItemData(item.ID))
tree.SortChildren(root)
tree.SortChildren(parent)
def addImplant(self, event):
root = self.availableImplantsTree.GetSelection()
@@ -603,21 +631,86 @@ class ImplantsTreeView (wx.Panel):
itemID = self.availableImplantsTree.GetPyData(root)
sChar.addImplant(charID, itemID)
self.update(sChar.getImplants(charID))
else:
event.Skip()
def removeImplant(self, event):
pos = self.pluggedImplantsTree.GetFirstSelected()
if pos != -1:
sChar = service.Character.getInstance()
charID = self.Parent.Parent.getActiveCharacter()
sChar.removeImplant(charID, self.implants[pos].slot)
sChar.removeImplant(charID, self.implants[pos])
self.update(sChar.getImplants(charID))
class AvailableImplantsView(d.Display):
DEFAULT_COLS = ["Base Name",
"attr:implantness"]
DEFAULT_COLS = ["attr:implantness",
"Base Icon",
"Base Name"]
def __init__(self, parent):
d.Display.__init__(self, parent, style=wx.LC_SINGLE_SEL)
self.Bind(wx.EVT_LEFT_DCLICK, parent.removeImplant)
#if "__WXGTK__" in wx.PlatformInfo:
# self.Bind(wx.EVT_RIGHT_UP, self.scheduleMenu)
#else:
# self.Bind(wx.EVT_RIGHT_DOWN, self.scheduleMenu)
class ItemView(d.Display):
DEFAULT_COLS = ["Base Icon",
"Base Name",
"attr:power,,,True",
"attr:cpu,,,True"]
def __init__(self, parent):
d.Display.__init__(self, parent)
self.parent = parent
self.searchBox = parent.searchBox
self.items = []
# Bind search actions
self.searchBox.Bind(SBox.EVT_TEXT_ENTER, self.scheduleSearch)
self.searchBox.Bind(SBox.EVT_SEARCH_BTN, self.scheduleSearch)
self.searchBox.Bind(SBox.EVT_CANCEL_BTN, self.clearSearch)
self.searchBox.Bind(SBox.EVT_TEXT, self.scheduleSearch)
def clearSearch(self, event=None):
if self.IsShown():
self.parent.availableImplantsTree.Show()
self.Hide()
self.parent.Layout()
if event:
self.searchBox.Clear()
self.items = []
self.update(self.items)
def scheduleSearch(self, event=None):
sMkt = service.Market.getInstance()
search = self.searchBox.GetLineText(0)
# Make sure we do not count wildcard as search symbol
realsearch = search.replace("*", "")
# Show nothing if query is too short
if len(realsearch) < 3:
self.clearSearch()
return
sMkt.searchItems(search, self.populateSearch, ["Implant"])
def populateSearch(self, items):
if not self.IsShown():
self.parent.availableImplantsTree.Hide()
self.Show()
self.parent.Layout()
self.items = sorted(list(items), key=lambda i: i.name)
self.update(self.items)
def __init__(self, parent, style):
d.Display.__init__(self, parent, style=style)
class APIView (wx.Panel):
def __init__(self, parent):

Some files were not shown because too many files have changed in this diff Show More