diff --git a/config.py b/config.py index 21b88fdd3..8b0f4b9ae 100644 --- a/config.py +++ b/config.py @@ -1,90 +1,90 @@ -import os -import sys - -# Load variable overrides specific to distribution type -try: - import configforced -except ImportError: - configforced = None - -# Turns on debug mode -debug = False -# Defines if our saveddata will be in pyfa root or not -saveInRoot = False - -# Version data -version = "1.7.2" -tag = "git" -expansionName = "Rhea" -expansionVersion = "1.0" -evemonMinVersion = "4081" - -# Database version (int ONLY) -# Increment every time we need to flag for user database upgrade/modification -dbversion = 3 - -pyfaPath = None -savePath = None -staticPath = None -saveDB = None -gameDB = None - -def defPaths(): - global pyfaPath - global savePath - global staticPath - global saveDB - global gameDB - global saveInRoot - # The main pyfa directory which contains run.py - # Python 2.X uses ANSI by default, so we need to convert the character encoding - pyfaPath = getattr(configforced, "pyfaPath", pyfaPath) - if pyfaPath is None: - pyfaPath = unicode(os.path.dirname(os.path.realpath(os.path.abspath( - sys.modules['__main__'].__file__))), sys.getfilesystemencoding()) - - # Where we store the saved fits etc, default is the current users home directory - if saveInRoot is True: - savePath = getattr(configforced, "savePath", None) - if savePath is None: - savePath = os.path.join(pyfaPath, "saveddata") - else: - savePath = getattr(configforced, "savePath", None) - if savePath is None: - savePath = unicode(os.path.expanduser(os.path.join("~", ".pyfa")), - sys.getfilesystemencoding()) - - # Redirect stderr to file if we're requested to do so - stderrToFile = getattr(configforced, "stderrToFile", None) - if stderrToFile is True: - if not os.path.exists(savePath): - os.mkdir(savePath) - sys.stderr = open(os.path.join(savePath, "error_log.txt"), "w") - - # Same for stdout - stdoutToFile = getattr(configforced, "stdoutToFile", None) - if stdoutToFile is True: - if not os.path.exists(savePath): - os.mkdir(savePath) - sys.stdout = open(os.path.join(savePath, "output_log.txt"), "w") - - # Static EVE Data from the staticdata repository, should be in the staticdata - # directory in our pyfa directory - staticPath = os.path.join(pyfaPath, "staticdata") - - # The database where we store all the fits etc - saveDB = os.path.join(savePath, "saveddata.db") - - # The database where the static EVE data from the datadump is kept. - # This is not the standard sqlite datadump but a modified version created by eos - # maintenance script - gameDB = os.path.join(staticPath, "eve.db") - - ## DON'T MODIFY ANYTHING BELOW ## - import eos.config - - #Caching modifiers, disable all gamedata caching, its unneeded. - eos.config.gamedataCache = False - # saveddata db location modifier, shouldn't ever need to touch this - eos.config.saveddata_connectionstring = "sqlite:///" + saveDB + "?check_same_thread=False" - eos.config.gamedata_connectionstring = "sqlite:///" + gameDB + "?check_same_thread=False" +import os +import sys + +# Load variable overrides specific to distribution type +try: + import configforced +except ImportError: + configforced = None + +# Turns on debug mode +debug = False +# Defines if our saveddata will be in pyfa root or not +saveInRoot = False + +# Version data +version = "1.10.1" +tag = "git" +expansionName = "Scylla" +expansionVersion = "1.0" +evemonMinVersion = "4081" + +# Database version (int ONLY) +# Increment every time we need to flag for user database upgrade/modification +dbversion = 6 + +pyfaPath = None +savePath = None +staticPath = None +saveDB = None +gameDB = None + +def defPaths(): + global pyfaPath + global savePath + global staticPath + global saveDB + global gameDB + global saveInRoot + # The main pyfa directory which contains run.py + # Python 2.X uses ANSI by default, so we need to convert the character encoding + pyfaPath = getattr(configforced, "pyfaPath", pyfaPath) + if pyfaPath is None: + pyfaPath = unicode(os.path.dirname(os.path.realpath(os.path.abspath( + sys.modules['__main__'].__file__))), sys.getfilesystemencoding()) + + # Where we store the saved fits etc, default is the current users home directory + if saveInRoot is True: + savePath = getattr(configforced, "savePath", None) + if savePath is None: + savePath = os.path.join(pyfaPath, "saveddata") + else: + savePath = getattr(configforced, "savePath", None) + if savePath is None: + savePath = unicode(os.path.expanduser(os.path.join("~", ".pyfa")), + sys.getfilesystemencoding()) + + # Redirect stderr to file if we're requested to do so + stderrToFile = getattr(configforced, "stderrToFile", None) + if stderrToFile is True: + if not os.path.exists(savePath): + os.mkdir(savePath) + sys.stderr = open(os.path.join(savePath, "error_log.txt"), "w") + + # Same for stdout + stdoutToFile = getattr(configforced, "stdoutToFile", None) + if stdoutToFile is True: + if not os.path.exists(savePath): + os.mkdir(savePath) + sys.stdout = open(os.path.join(savePath, "output_log.txt"), "w") + + # Static EVE Data from the staticdata repository, should be in the staticdata + # directory in our pyfa directory + staticPath = os.path.join(pyfaPath, "staticdata") + + # The database where we store all the fits etc + saveDB = os.path.join(savePath, "saveddata.db") + + # The database where the static EVE data from the datadump is kept. + # This is not the standard sqlite datadump but a modified version created by eos + # maintenance script + gameDB = os.path.join(staticPath, "eve.db") + + ## DON'T MODIFY ANYTHING BELOW ## + import eos.config + + #Caching modifiers, disable all gamedata caching, its unneeded. + eos.config.gamedataCache = False + # saveddata db location modifier, shouldn't ever need to touch this + eos.config.saveddata_connectionstring = "sqlite:///" + saveDB + "?check_same_thread=False" + eos.config.gamedata_connectionstring = "sqlite:///" + gameDB + "?check_same_thread=False" diff --git a/eos/config.py b/eos/config.py index 192982e1f..35e2fe0dc 100644 --- a/eos/config.py +++ b/eos/config.py @@ -1,11 +1,11 @@ -import os.path +from os.path import realpath, join, dirname, abspath import sys debug = False gamedataCache = True saveddataCache = True -gamedata_connectionstring = 'sqlite:///' + os.path.expanduser(os.path.join("~", ".pyfa","eve.db")) +gamedata_connectionstring = 'sqlite:///' + unicode(realpath(join(dirname(abspath(__file__)), "..", "staticdata", "eve.db")), sys.getfilesystemencoding()) saveddata_connectionstring = 'sqlite:///:memory:' #Autodetect path, only change if the autodetection bugs out. -path = os.path.dirname(unicode(__file__, sys.getfilesystemencoding())) +path = dirname(unicode(__file__, sys.getfilesystemencoding())) diff --git a/eos/db/__init__.py b/eos/db/__init__.py index bedb917d6..8867d63c5 100644 --- a/eos/db/__init__.py +++ b/eos/db/__init__.py @@ -75,7 +75,7 @@ from eos.db.saveddata.queries import getUser, getCharacter, getFit, getFitsWithS getFitList, getFleetList, getFleet, save, remove, commit, add, \ getCharactersForUser, getMiscData, getSquadsIDsWithFitID, getWing, \ getSquad, getBoosterFits, getProjectedFits, getTargetResistsList, getTargetResists,\ - clearPrices + clearPrices, countAllFits #If using in memory saveddata, you'll want to reflect it so the data structure is good. if config.saveddata_connectionstring == "sqlite:///:memory:": diff --git a/eos/db/migrations/upgrade3.py b/eos/db/migrations/upgrade3.py index 5467fdf2d..0350ded72 100644 --- a/eos/db/migrations/upgrade3.py +++ b/eos/db/migrations/upgrade3.py @@ -8,6 +8,6 @@ import sqlalchemy def upgrade(saveddata_engine): try: - saveddata_engine.execute("SELECT mode FROM fits LIMIT 1") + saveddata_engine.execute("SELECT modeID FROM fits LIMIT 1") except sqlalchemy.exc.DatabaseError: saveddata_engine.execute("ALTER TABLE fits ADD COLUMN modeID INTEGER") diff --git a/eos/db/migrations/upgrade4.py b/eos/db/migrations/upgrade4.py new file mode 100644 index 000000000..87906cffc --- /dev/null +++ b/eos/db/migrations/upgrade4.py @@ -0,0 +1,141 @@ +""" +Migration 4 + +- Converts modules based on Proteus Module Tiericide + Some modules have been unpublished (and unpublished module attributes are removed + from database), which causes pyfa to crash. We therefore replace these + modules with their new replacements + + Based on http://community.eveonline.com/news/patch-notes/patch-notes-for-proteus/ + and output of itemDiff.py +""" + + +CONVERSIONS = { + 506: ( # 'Basic' Capacitor Power Relay + 8205, # Alpha Reactor Control: Capacitor Power Relay + 8209, # Marked Generator Refitting: Capacitor Power Relay + 8203, # Partial Power Plant Manager: Capacity Power Relay + 8207, # Type-E Power Core Modification: Capacitor Power Relay + ), + 8177: ( # Mark I Compact Capacitor Power Relay + 8173, # Beta Reactor Control: Capacitor Power Relay I + ), + 8175: ( # Type-D Restrained Capacitor Power Relay + 8171, # Local Power Plant Manager: Capacity Power Relay I + ), + + 421: ( # 'Basic' Capacitor Recharger + 4425, # AGM Capacitor Charge Array, + 4421, # F-a10 Buffer Capacitor Regenerator + 4423, # Industrial Capacitor Recharger + 4427, # Secondary Parallel Link-Capacitor + ), + 4435: ( # Eutectic Compact Cap Recharger + 4433, # Barton Reactor Capacitor Recharger I + 4431, # F-b10 Nominal Capacitor Regenerator + 4437, # Fixed Parallel Link-Capacitor I + ), + + 1315: ( # 'Basic' Expanded Cargohold + 5483, # Alpha Hull Mod Expanded Cargo + 5479, # Marked Modified SS Expanded Cargo + 5481, # Partial Hull Conversion Expanded Cargo + 5485, # Type-E Altered SS Expanded Cargo + ), + 5493: ( # Type-D Restrained Expanded Cargo + 5491, # Beta Hull Mod Expanded Cargo + 5489, # Local Hull Conversion Expanded Cargo I + 5487, # Mark I Modified SS Expanded Cargo + ), + + 1401: ( # 'Basic' Inertial Stabilizers + 5523, # Alpha Hull Mod Inertial Stabilizers + 5521, # Partial Hull Conversion Inertial Stabilizers + 5525, # Type-E Altered SS Inertial Stabilizers + ), + 5533: ( # Type-D Restrained Inertial Stabilizers + 5531, # Beta Hull Mod Inertial Stabilizers + 5529, # Local Hull Conversion Inertial Stabilizers I + 5527, # Mark I Modified SS Inertial Stabilizers + 5519, # Marked Modified SS Inertial Stabilizers + ), + + 5239: ( # EP-S Gaussian Scoped Mining Laser + 5241, # Dual Diode Mining Laser I + ), + 5233: ( # Single Diode Basic Mining Laser + 5231, # EP-R Argon Ion Basic Excavation Pulse + 5237, # Rubin Basic Particle Bore Stream + 5235, # Xenon Basic Drilling Beam + ), + 5245: ( # Particle Bore Compact Mining Laser + 5243, # XeCl Drilling Beam I + ), + + 22619: ( # Frigoris Restrained Ice Harvester Upgrade + 22617, # Crisium Ice Harvester Upgrade + ), + 22611: ( # Elara Restrained Mining Laser Upgrade + 22609, # Erin Mining Laser Upgrade + ), + + 1242: ( # 'Basic' Nanofiber Internal Structure + 5591, # Alpha Hull Mod Nanofiber Structure + 5595, # Marked Modified SS Nanofiber Structure + 5559, # Partial Hull Conversion Nanofiber Structure + 5593, # Type-E Altered SS Nanofiber Structure + ), + 5599: ( # Type-D Restrained Nanofiber Structure + 5597, # Beta Hull Mod Nanofiber Structure + 5561, # Local Hull Conversion Nanofiber Structure I + 5601, # Mark I Modified SS Nanofiber Structure + ), + + 1192: ( # 'Basic' Overdrive Injector System + 5613, # Alpha Hull Mod Overdrive Injector + 5617, # Marked Modified SS Overdrive Injector + 5611, # Partial Hull Conversion Overdrive Injector + 5615, # Type-E Altered SS Overdrive Injector + ), + 5631: ( # Type-D Restrained Overdrive Injector + 5629, # Beta Hull Mod Overdrive Injector + 5627, # Local Hull Conversion Overdrive Injector I + 5633, # Mark I Modified SS Overdrive Injector + ), + + 1537: ( # 'Basic' Power Diagnostic System + 8213, # Alpha Reactor Control: Diagnostic System + 8217, # Marked Generator Refitting: Diagnostic System + 8211, # Partial Power Plant Manager: Diagnostic System + 8215, # Type-E Power Core Modification: Diagnostic System + 8255, # Type-E Power Core Modification: Reaction Control + ), + 8225: ( # Mark I Compact Power Diagnostic System + 8221, # Beta Reactor Control: Diagnostic System I + 8219, # Local Power Plant Manager: Diagnostic System I + 8223, # Type-D Power Core Modification: Diagnostic System + ), + + 1240: ( # 'Basic' Reinforced Bulkheads + 5677, # Alpha Hull Mod Reinforced Bulkheads + 5681, # Marked Modified SS Reinforced Bulkheads + 5675, # Partial Hull Conversion Reinforced Bulkheads + 5679, # Type-E Altered SS Reinforced Bulkheads + ), + 5649: ( # Mark I Compact Reinforced Bulkheads + 5645, # Beta Hull Mod Reinforced Bulkheads + ), + 5647: ( # Type-D Restrained Reinforced Bulkheads + 5643, # Local Hull Conversion Reinforced Bulkheads I + ), +} + +def upgrade(saveddata_engine): + + # Convert modules + for replacement_item, list in CONVERSIONS.iteritems(): + for retired_item in list: + saveddata_engine.execute('UPDATE "modules" SET "itemID" = ? WHERE "itemID" = ?', (replacement_item, retired_item)) + saveddata_engine.execute('UPDATE "cargo" SET "itemID" = ? WHERE "itemID" = ?', (replacement_item, retired_item)) + diff --git a/eos/db/migrations/upgrade5.py b/eos/db/migrations/upgrade5.py new file mode 100644 index 000000000..cf6a3385d --- /dev/null +++ b/eos/db/migrations/upgrade5.py @@ -0,0 +1,8 @@ +""" +Migration 5 + +Simply deletes damage profiles with a blank name. See GH issue #256 +""" + +def upgrade(saveddata_engine): + saveddata_engine.execute('DELETE FROM damagePatterns WHERE name LIKE ?', ("",)) diff --git a/eos/db/migrations/upgrade6.py b/eos/db/migrations/upgrade6.py new file mode 100644 index 000000000..ee8a091e6 --- /dev/null +++ b/eos/db/migrations/upgrade6.py @@ -0,0 +1,9 @@ +""" +Migration 6 + +Overwrites damage profile 0 to reset bad uniform values (bad values set with bug) +""" + +def upgrade(saveddata_engine): + saveddata_engine.execute('DELETE FROM damagePatterns WHERE name LIKE ? OR ID LIKE ?', ("Uniform", "1")) + saveddata_engine.execute('INSERT INTO damagePatterns VALUES (?, ?, ?, ?, ?, ?, ?)', (1, "Uniform", 25, 25, 25, 25, None)) diff --git a/eos/db/saveddata/queries.py b/eos/db/saveddata/queries.py index 9fee22561..be7c078fc 100644 --- a/eos/db/saveddata/queries.py +++ b/eos/db/saveddata/queries.py @@ -267,6 +267,11 @@ def getBoosterFits(ownerID=None, where=None, eager=None): fits = saveddata_session.query(Fit).options(*eager).filter(filter).all() return fits +def countAllFits(): + with sd_lock: + count = saveddata_session.query(Fit).count() + return count + def countFitsWithShip(shipID, ownerID=None, where=None, eager=None): """ Get all the fits using a certain ship. diff --git a/eos/effects/agilitymultipliereffect.py b/eos/effects/agilitymultipliereffect.py index 9478201f3..11306be36 100644 --- a/eos/effects/agilitymultipliereffect.py +++ b/eos/effects/agilitymultipliereffect.py @@ -1,9 +1,9 @@ # agilityMultiplierEffect # # Used by: -# Modules from group: Inertia Stabilizer (12 of 12) -# Modules from group: Nanofiber Internal Structure (14 of 14) -# Modules from group: Reinforced Bulkhead (12 of 12) +# Modules from group: Inertial Stabilizer (7 of 7) +# Modules from group: Nanofiber Internal Structure (7 of 7) +# Modules from group: Reinforced Bulkhead (8 of 8) type = "passive" def handler(fit, module, context): fit.ship.boostItemAttr("agility", diff --git a/eos/effects/capacitorcapacitymultiply.py b/eos/effects/capacitorcapacitymultiply.py index d761c502c..17e9d1da4 100644 --- a/eos/effects/capacitorcapacitymultiply.py +++ b/eos/effects/capacitorcapacitymultiply.py @@ -2,8 +2,8 @@ # # Used by: # Modules from group: Capacitor Flux Coil (6 of 6) -# Modules from group: Capacitor Power Relay (26 of 26) -# Modules from group: Power Diagnostic System (31 of 31) +# Modules from group: Capacitor Power Relay (20 of 20) +# Modules from group: Power Diagnostic System (23 of 23) # Modules from group: Propulsion Module (107 of 107) # Modules from group: Reactor Control Unit (22 of 22) # Modules from group: Shield Flux Coil (11 of 11) diff --git a/eos/effects/cargocapacitymultiply.py b/eos/effects/cargocapacitymultiply.py index c98c31387..c476f9b79 100644 --- a/eos/effects/cargocapacitymultiply.py +++ b/eos/effects/cargocapacitymultiply.py @@ -1,9 +1,9 @@ # cargoCapacityMultiply # # Used by: -# Modules from group: Expanded Cargohold (13 of 13) -# Modules from group: Overdrive Injector System (14 of 14) -# Modules from group: Reinforced Bulkhead (12 of 12) +# Modules from group: Expanded Cargohold (7 of 7) +# Modules from group: Overdrive Injector System (7 of 7) +# Modules from group: Reinforced Bulkhead (8 of 8) type = "passive" def handler(fit, module, context): fit.ship.multiplyItemAttr("capacity", module.getModifiedItemAttr("cargoCapacityMultiplier")) diff --git a/eos/effects/commandbonustdmultiplywithcommandbonushidden.py b/eos/effects/commandbonustdmultiplywithcommandbonushidden.py index 6b0ea92f7..05825349c 100644 --- a/eos/effects/commandbonustdmultiplywithcommandbonushidden.py +++ b/eos/effects/commandbonustdmultiplywithcommandbonushidden.py @@ -6,6 +6,7 @@ gangBonus = "commandBonusTD" gangBoost = "ewarStrTD" type = "active", "gang" def handler(fit, module, context): + if "gang" not in context: return for bonus in ("maxRangeBonus", "falloffBonus", "trackingSpeedBonus"): fit.modules.filteredItemBoost(lambda mod: lambda mod: mod.item.requiresSkill("Weapon Disruption"), bonus, module.getModifiedItemAttr("commandBonusTD")) diff --git a/eos/effects/covertopscloakcpupercentbonuspiratefaction.py b/eos/effects/covertopscloakcpupercentbonuspiratefaction.py index 0e6fe99e3..fa7faffc3 100644 --- a/eos/effects/covertopscloakcpupercentbonuspiratefaction.py +++ b/eos/effects/covertopscloakcpupercentbonuspiratefaction.py @@ -3,6 +3,7 @@ # Used by: # Ship: Astero # Ship: Prospect +# Ship: Victorieux Luxury Yacht type = "passive" runTime = "early" def handler(fit, ship, context): diff --git a/eos/effects/elitereconbonusassaultlauncherrof1.py b/eos/effects/elitereconbonusassaultlauncherrof1.py deleted file mode 100644 index b4237469e..000000000 --- a/eos/effects/elitereconbonusassaultlauncherrof1.py +++ /dev/null @@ -1,10 +0,0 @@ -# eliteReconBonusAssaultLauncherROF1 -# -# Used by: -# Ship: Huginn -# Ship: Lachesis -type = "passive" -def handler(fit, ship, context): - level = fit.character.getSkill("Recon Ships").level - fit.modules.filteredItemBoost(lambda mod: mod.item.group.name == "Missile Launcher Rapid Light", - "speed", ship.getModifiedItemAttr("eliteBonusReconShip1") * level) diff --git a/eos/effects/elitereconbonusheavyassaultlauncherrof1.py b/eos/effects/elitereconbonusheavyassaultlauncherrof1.py deleted file mode 100644 index 15c7c8e29..000000000 --- a/eos/effects/elitereconbonusheavyassaultlauncherrof1.py +++ /dev/null @@ -1,9 +0,0 @@ -# eliteReconBonusHeavyAssaultLauncherROF1 -# -# Used by: -# Ship: Huginn -type = "passive" -def handler(fit, ship, context): - level = fit.character.getSkill("Recon Ships").level - fit.modules.filteredItemBoost(lambda mod: mod.item.group.name == "Missile Launcher Heavy Assault", - "speed", ship.getModifiedItemAttr("eliteBonusReconShip1") * level) diff --git a/eos/effects/elitereconbonusheavylauncherrof1.py b/eos/effects/elitereconbonusheavylauncherrof1.py deleted file mode 100644 index bbce42793..000000000 --- a/eos/effects/elitereconbonusheavylauncherrof1.py +++ /dev/null @@ -1,10 +0,0 @@ -# eliteReconBonusHeavyLauncherROF1 -# -# Used by: -# Ship: Huginn -# Ship: Lachesis -type = "passive" -def handler(fit, ship, context): - level = fit.character.getSkill("Recon Ships").level - fit.modules.filteredItemBoost(lambda mod: mod.item.group.name == "Missile Launcher Heavy", - "speed", ship.getModifiedItemAttr("eliteBonusReconShip1") * level) diff --git a/eos/effects/elitereconbonusmhtoptimalrange1.py b/eos/effects/elitereconbonusmhtoptimalrange1.py new file mode 100644 index 000000000..4f9ad6048 --- /dev/null +++ b/eos/effects/elitereconbonusmhtoptimalrange1.py @@ -0,0 +1,9 @@ +# eliteReconBonusMHTOptimalRange1 +# +# Used by: +# Ship: Lachesis +type = "passive" +def handler(fit, ship, context): + level = fit.character.getSkill("Recon Ships").level + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Medium Hybrid Turret"), + "maxRange", ship.getModifiedItemAttr("eliteBonusReconShip1") * level) diff --git a/eos/effects/elitereconbonusmptdamage1.py b/eos/effects/elitereconbonusmptdamage1.py new file mode 100644 index 000000000..1a8b12924 --- /dev/null +++ b/eos/effects/elitereconbonusmptdamage1.py @@ -0,0 +1,9 @@ +# eliteReconBonusMPTdamage1 +# +# Used by: +# Ship: Huginn +type = "passive" +def handler(fit, ship, context): + level = fit.character.getSkill("Recon Ships").level + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Medium Projectile Turret"), + "damageMultiplier", ship.getModifiedItemAttr("eliteBonusReconShip1") * level) diff --git a/eos/effects/elitereconbonusneutrange3.py b/eos/effects/elitereconbonusneutrange3.py new file mode 100644 index 000000000..88b6ecb03 --- /dev/null +++ b/eos/effects/elitereconbonusneutrange3.py @@ -0,0 +1,9 @@ +# eliteReconBonusNeutRange3 +# +# Used by: +# Ship: Pilgrim +type = "passive" +def handler(fit, ship, context): + level = fit.character.getSkill("Recon Ships").level + fit.modules.filteredItemBoost(lambda mod: mod.item.group.name == "Energy Destabilizer", + "energyDestabilizationRange", ship.getModifiedItemAttr("eliteBonusReconShip3") * level) diff --git a/eos/effects/elitereconbonusvamprange3.py b/eos/effects/elitereconbonusvamprange3.py new file mode 100644 index 000000000..dfafdd3a3 --- /dev/null +++ b/eos/effects/elitereconbonusvamprange3.py @@ -0,0 +1,9 @@ +# eliteReconBonusVampRange3 +# +# Used by: +# Ship: Pilgrim +type = "passive" +def handler(fit, ship, context): + level = fit.character.getSkill("Recon Ships").level + fit.modules.filteredItemBoost(lambda mod: mod.item.group.name == "Energy Vampire", + "powerTransferRange", ship.getModifiedItemAttr("eliteBonusReconShip3") * level) diff --git a/eos/effects/iceharvestcycletimemodulesrequiringiceharvestingonline.py b/eos/effects/iceharvestcycletimemodulesrequiringiceharvestingonline.py index 501ab9bd4..b495ccaaf 100644 --- a/eos/effects/iceharvestcycletimemodulesrequiringiceharvestingonline.py +++ b/eos/effects/iceharvestcycletimemodulesrequiringiceharvestingonline.py @@ -1,7 +1,7 @@ # iceHarvestCycleTimeModulesRequiringIceHarvestingOnline # # Used by: -# Variations of module: Ice Harvester Upgrade I (6 of 6) +# Variations of module: Ice Harvester Upgrade I (5 of 5) type = "passive" def handler(fit, module, context): fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Ice Harvesting"), diff --git a/eos/effects/iceminercpuusagepercent.py b/eos/effects/iceminercpuusagepercent.py index d14d89589..9a3f04694 100644 --- a/eos/effects/iceminercpuusagepercent.py +++ b/eos/effects/iceminercpuusagepercent.py @@ -1,7 +1,7 @@ # iceMinerCpuUsagePercent # # Used by: -# Variations of module: Ice Harvester Upgrade I (6 of 6) +# Variations of module: Ice Harvester Upgrade I (5 of 5) type = "passive" def handler(fit, module, context): fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Ice Harvesting"), diff --git a/eos/effects/increasesignatureradiusonline.py b/eos/effects/increasesignatureradiusonline.py index a4bd284b4..a67dc074f 100644 --- a/eos/effects/increasesignatureradiusonline.py +++ b/eos/effects/increasesignatureradiusonline.py @@ -1,7 +1,7 @@ # increaseSignatureRadiusOnline # # Used by: -# Modules from group: Inertia Stabilizer (12 of 12) +# Modules from group: Inertial Stabilizer (7 of 7) type = "passive" def handler(fit, module, context): fit.ship.boostItemAttr("signatureRadius", module.getModifiedItemAttr("signatureRadiusBonus")) \ No newline at end of file diff --git a/eos/effects/minercpuusagemultiplypercent2.py b/eos/effects/minercpuusagemultiplypercent2.py index 6f1b9aa33..f76b5323b 100644 --- a/eos/effects/minercpuusagemultiplypercent2.py +++ b/eos/effects/minercpuusagemultiplypercent2.py @@ -1,7 +1,7 @@ # minerCpuUsageMultiplyPercent2 # # Used by: -# Variations of module: Mining Laser Upgrade I (6 of 6) +# Variations of module: Mining Laser Upgrade I (5 of 5) type = "passive" def handler(fit, module, context): fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Mining"), diff --git a/eos/effects/mininglaser.py b/eos/effects/mininglaser.py index a691775fa..a4095f4ed 100644 --- a/eos/effects/mininglaser.py +++ b/eos/effects/mininglaser.py @@ -2,7 +2,7 @@ # # Used by: # Modules from group: Frequency Mining Laser (3 of 3) -# Modules from group: Mining Laser (17 of 17) +# Modules from group: Mining Laser (12 of 12) # Modules from group: Strip Miner (5 of 5) type = 'active' def handler(fit, module, context): diff --git a/eos/effects/miningyieldmultiplypercent.py b/eos/effects/miningyieldmultiplypercent.py index 0ca493d0b..d00198ab4 100644 --- a/eos/effects/miningyieldmultiplypercent.py +++ b/eos/effects/miningyieldmultiplypercent.py @@ -1,7 +1,7 @@ # miningYieldMultiplyPercent # # Used by: -# Variations of module: Mining Laser Upgrade I (6 of 6) +# Variations of module: Mining Laser Upgrade I (5 of 5) type = "passive" def handler(fit, module, context): fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Mining"), diff --git a/eos/effects/modeagilitypostdiv.py b/eos/effects/modeagilitypostdiv.py index 022951098..d57571078 100644 --- a/eos/effects/modeagilitypostdiv.py +++ b/eos/effects/modeagilitypostdiv.py @@ -1,8 +1,12 @@ # modeAgilityPostDiv # # Used by: -# Module: Amarr Tactical Destroyer Propulsion Mode +# Modules named like: Propulsion Mode (2 of 2) type = "passive" def handler(fit, module, context): - fit.ship.multiplyItemAttr("agility", 1/module.getModifiedItemAttr("modeAgilityPostDiv"), - stackingPenalties = True, penaltyGroup="postDiv") + fit.ship.multiplyItemAttr( + "agility", + 1 / module.getModifiedItemAttr("modeAgilityPostDiv"), + stackingPenalties=True, + penaltyGroup="postDiv" + ) diff --git a/eos/effects/modearmorresonancepostdiv.py b/eos/effects/modearmorresonancepostdiv.py index af767b63b..b24e6b14e 100644 --- a/eos/effects/modearmorresonancepostdiv.py +++ b/eos/effects/modearmorresonancepostdiv.py @@ -1,15 +1,18 @@ # modeArmorResonancePostDiv # # Used by: -# Module: Amarr Tactical Destroyer Defense Mode +# Modules named like: Defense Mode (2 of 2) type = "passive" def handler(fit, module, context): - for resType in ("Em", "Explosive", "Kinetic"): - fit.ship.multiplyItemAttr("armor{0}DamageResonance".format(resType), - 1/module.getModifiedItemAttr("mode{0}ResistancePostDiv".format(resType)), - stackingPenalties = True, penaltyGroup="postDiv") - - # Thermal != Thermic - fit.ship.multiplyItemAttr("armorThermalDamageResonance", - 1/module.getModifiedItemAttr("modeThermicResistancePostDiv"), - stackingPenalties = True, penaltyGroup="postDiv") + for srcResType, tgtResType in ( + ("Em", "Em"), + ("Explosive", "Explosive"), + ("Kinetic", "Kinetic"), + ("Thermic", "Thermal") + ): + fit.ship.multiplyItemAttr( + "armor{0}DamageResonance".format(tgtResType), + 1 / module.getModifiedItemAttr("mode{0}ResistancePostDiv".format(srcResType)), + stackingPenalties=True, + penaltyGroup="postDiv" + ) diff --git a/eos/effects/modemwdsigradiuspostdiv.py b/eos/effects/modemwdsigradiuspostdiv.py new file mode 100644 index 000000000..01421c82e --- /dev/null +++ b/eos/effects/modemwdsigradiuspostdiv.py @@ -0,0 +1,13 @@ +# modeMWDSigRadiusPostDiv +# +# Used by: +# Module: Svipul Defense Mode +type = "passive" +def handler(fit, module, context): + fit.modules.filteredItemMultiply( + lambda mod: mod.item.requiresSkill("High Speed Maneuvering"), + "signatureRadiusBonus", + 1 / module.getModifiedItemAttr("modeMWDSigPenaltyPostDiv"), + stackingPenalties=True, + penaltyGroup="postDiv" + ) diff --git a/eos/effects/modeshieldresonancepostdiv.py b/eos/effects/modeshieldresonancepostdiv.py new file mode 100644 index 000000000..a40c3c78a --- /dev/null +++ b/eos/effects/modeshieldresonancepostdiv.py @@ -0,0 +1,18 @@ +# modeShieldResonancePostDiv +# +# Used by: +# Module: Svipul Defense Mode +type = "passive" +def handler(fit, module, context): + for srcResType, tgtResType in ( + ("Em", "Em"), + ("Explosive", "Explosive"), + ("Kinetic", "Kinetic"), + ("Thermic", "Thermal") + ): + fit.ship.multiplyItemAttr( + "shield{0}DamageResonance".format(tgtResType), + 1 / module.getModifiedItemAttr("mode{0}ResistancePostDiv".format(srcResType)), + stackingPenalties=True, + penaltyGroup="postDiv" + ) diff --git a/eos/effects/modesigradiuspostdiv.py b/eos/effects/modesigradiuspostdiv.py index 72e955f73..7522b2aaf 100644 --- a/eos/effects/modesigradiuspostdiv.py +++ b/eos/effects/modesigradiuspostdiv.py @@ -1,9 +1,8 @@ # modeSigRadiusPostDiv # # Used by: -# Module: Amarr Tactical Destroyer Defense Mode +# Module: Confessor Defense Mode type = "passive" def handler(fit, module, context): - level = fit.character.getSkill("Minmatar Destroyer").level fit.ship.multiplyItemAttr("signatureRadius", 1/module.getModifiedItemAttr("modeSignatureRadiusPostDiv"), stackingPenalties = True, penaltyGroup="postDiv") diff --git a/eos/effects/modevelocitypostdiv.py b/eos/effects/modevelocitypostdiv.py index a38c9ddb8..14a4a5271 100644 --- a/eos/effects/modevelocitypostdiv.py +++ b/eos/effects/modevelocitypostdiv.py @@ -1,8 +1,12 @@ # modeVelocityPostDiv # # Used by: -# Module: Amarr Tactical Destroyer Propulsion Mode +# Modules named like: Propulsion Mode (2 of 2) type = "passive" def handler(fit, module, context): - fit.ship.multiplyItemAttr("maxVelocity", 1/module.getModifiedItemAttr("modeVelocityPostDiv"), - stackingPenalties = True, penaltyGroup="postDiv") + fit.ship.multiplyItemAttr( + "maxVelocity", + 1 / module.getModifiedItemAttr("modeVelocityPostDiv"), + stackingPenalties=True, + penaltyGroup="postDiv" + ) diff --git a/eos/effects/modifymaxvelocityofshippassive.py b/eos/effects/modifymaxvelocityofshippassive.py index 3c134f937..62670476a 100644 --- a/eos/effects/modifymaxvelocityofshippassive.py +++ b/eos/effects/modifymaxvelocityofshippassive.py @@ -1,7 +1,7 @@ # modifyMaxVelocityOfShipPassive # # Used by: -# Modules from group: Expanded Cargohold (13 of 13) +# Modules from group: Expanded Cargohold (7 of 7) type = "passive" def handler(fit, module, context): fit.ship.multiplyItemAttr("maxVelocity", module.getModifiedItemAttr("maxVelocityBonus"), diff --git a/eos/effects/modifypowerrechargerate.py b/eos/effects/modifypowerrechargerate.py index 9dcea33b5..4f1e35a4b 100644 --- a/eos/effects/modifypowerrechargerate.py +++ b/eos/effects/modifypowerrechargerate.py @@ -2,9 +2,9 @@ # # Used by: # Modules from group: Capacitor Flux Coil (6 of 6) -# Modules from group: Capacitor Power Relay (26 of 26) -# Modules from group: Capacitor Recharger (25 of 25) -# Modules from group: Power Diagnostic System (31 of 31) +# Modules from group: Capacitor Power Relay (20 of 20) +# Modules from group: Capacitor Recharger (18 of 18) +# Modules from group: Power Diagnostic System (23 of 23) # Modules from group: Reactor Control Unit (22 of 22) # Modules from group: Shield Flux Coil (11 of 11) # Modules from group: Shield Power Relay (11 of 11) diff --git a/eos/effects/modifyshieldrechargerate.py b/eos/effects/modifyshieldrechargerate.py index 1e1dbc192..1986cbb09 100644 --- a/eos/effects/modifyshieldrechargerate.py +++ b/eos/effects/modifyshieldrechargerate.py @@ -2,8 +2,8 @@ # # Used by: # Modules from group: Capacitor Flux Coil (6 of 6) -# Modules from group: Capacitor Power Relay (26 of 26) -# Modules from group: Power Diagnostic System (31 of 31) +# Modules from group: Capacitor Power Relay (20 of 20) +# Modules from group: Power Diagnostic System (23 of 23) # Modules from group: Reactor Control Unit (22 of 22) # Modules from group: Shield Flux Coil (11 of 11) # Modules from group: Shield Recharger (6 of 6) diff --git a/eos/effects/mwdsignatureradiusrolebonus.py b/eos/effects/mwdsignatureradiusrolebonus.py index b160c5b28..92f757399 100644 --- a/eos/effects/mwdsignatureradiusrolebonus.py +++ b/eos/effects/mwdsignatureradiusrolebonus.py @@ -2,7 +2,7 @@ # # Used by: # Ships from group: Assault Frigate (8 of 12) -# Ships from group: Heavy Assault Cruiser (8 of 11) +# Ships from group: Heavy Assault Cruiser (10 of 13) type = "passive" def handler(fit, ship, context): fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("High Speed Maneuvering"), diff --git a/eos/effects/overloadrofbonus.py b/eos/effects/overloadrofbonus.py index 5382e5f2c..4cfc38d2f 100644 --- a/eos/effects/overloadrofbonus.py +++ b/eos/effects/overloadrofbonus.py @@ -1,7 +1,7 @@ # overloadRofBonus # # Used by: -# Modules from group: Energy Weapon (100 of 186) +# 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) diff --git a/eos/effects/overloadselfdamagebonus.py b/eos/effects/overloadselfdamagebonus.py index 0e43c84c1..2e46fe1ec 100644 --- a/eos/effects/overloadselfdamagebonus.py +++ b/eos/effects/overloadselfdamagebonus.py @@ -1,7 +1,7 @@ # overloadSelfDamageBonus # # Used by: -# Modules from group: Energy Weapon (86 of 186) +# Modules from group: Energy Weapon (86 of 187) # Modules from group: Hybrid Weapon (92 of 202) # Modules from group: Projectile Weapon (86 of 146) type = "overheat" diff --git a/eos/effects/poweroutputmultiply.py b/eos/effects/poweroutputmultiply.py index e4f988ff8..e0ac4fe57 100644 --- a/eos/effects/poweroutputmultiply.py +++ b/eos/effects/poweroutputmultiply.py @@ -2,8 +2,8 @@ # # Used by: # Modules from group: Capacitor Flux Coil (6 of 6) -# Modules from group: Capacitor Power Relay (26 of 26) -# Modules from group: Power Diagnostic System (31 of 31) +# Modules from group: Capacitor Power Relay (20 of 20) +# Modules from group: Power Diagnostic System (23 of 23) # Modules from group: Reactor Control Unit (22 of 22) # Modules from group: Shield Flux Coil (11 of 11) # Modules from group: Shield Power Relay (11 of 11) diff --git a/eos/effects/probelaunchercpupercentbonustacticaldestroyer.py b/eos/effects/probelaunchercpupercentbonustacticaldestroyer.py index 1efb4913c..808c13098 100644 --- a/eos/effects/probelaunchercpupercentbonustacticaldestroyer.py +++ b/eos/effects/probelaunchercpupercentbonustacticaldestroyer.py @@ -1,7 +1,7 @@ # probeLauncherCPUPercentBonusTacticalDestroyer # # Used by: -# Ship: Confessor +# Ships from group: Tactical Destroyer (2 of 2) type = "passive" def handler(fit, ship, context): fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Astrometrics"), diff --git a/eos/effects/energytransferpowerneedbonuseffect.py b/eos/effects/remotecapacitortransmitterpowerneedbonuseffect.py similarity index 86% rename from eos/effects/energytransferpowerneedbonuseffect.py rename to eos/effects/remotecapacitortransmitterpowerneedbonuseffect.py index e40ba2002..b55a1c8b1 100644 --- a/eos/effects/energytransferpowerneedbonuseffect.py +++ b/eos/effects/remotecapacitortransmitterpowerneedbonuseffect.py @@ -1,4 +1,4 @@ -# energyTransferPowerNeedBonusEffect +# remoteCapacitorTransmitterPowerNeedBonusEffect # # Used by: # Ships from group: Logistics (3 of 5) diff --git a/eos/effects/scanstrengthbonuspercentactivate.py b/eos/effects/scanstrengthbonuspercentactivate.py index 46f606c35..7a652b614 100644 --- a/eos/effects/scanstrengthbonuspercentactivate.py +++ b/eos/effects/scanstrengthbonuspercentactivate.py @@ -5,7 +5,9 @@ # Module: QA ECCM type = "active" def handler(fit, module, context): - for type in ("Gravimetric", "Magnetometric", "Radar", "Ladar"): - fit.ship.boostItemAttr("scan%sStrength" % type, - module.getModifiedItemAttr("scan%sStrengthPercent" % type), - stackingPenalties = True) \ No newline at end of file + for scanType in ("Gravimetric", "Magnetometric", "Radar", "Ladar"): + fit.ship.boostItemAttr( + "scan{}Strength".format(scanType), + module.getModifiedItemAttr("scan{}StrengthPercent".format(scanType)), + stackingPenalties=True + ) diff --git a/eos/effects/shieldboostamplifier.py b/eos/effects/shieldboostamplifier.py index 164c39319..137df0af1 100644 --- a/eos/effects/shieldboostamplifier.py +++ b/eos/effects/shieldboostamplifier.py @@ -1,7 +1,7 @@ # shieldBoostAmplifier # # Used by: -# Modules from group: Capacitor Power Relay (26 of 26) +# Modules from group: Capacitor Power Relay (20 of 20) # Modules from group: Shield Boost Amplifier (25 of 25) type = "passive" def handler(fit, module, context): diff --git a/eos/effects/shieldcapacitymultiply.py b/eos/effects/shieldcapacitymultiply.py index 4f536da11..9cf482cc7 100644 --- a/eos/effects/shieldcapacitymultiply.py +++ b/eos/effects/shieldcapacitymultiply.py @@ -2,8 +2,8 @@ # # Used by: # Modules from group: Capacitor Flux Coil (6 of 6) -# Modules from group: Capacitor Power Relay (26 of 26) -# Modules from group: Power Diagnostic System (31 of 31) +# Modules from group: Capacitor Power Relay (20 of 20) +# Modules from group: Power Diagnostic System (23 of 23) # Modules from group: Reactor Control Unit (22 of 22) # Modules from group: Shield Flux Coil (11 of 11) # Modules from group: Shield Power Relay (11 of 11) diff --git a/eos/effects/shipbonusdronedamagemultipliergb2.py b/eos/effects/shipbonusdronedamagemultipliergb2.py index c65feca5a..80fe20844 100644 --- a/eos/effects/shipbonusdronedamagemultipliergb2.py +++ b/eos/effects/shipbonusdronedamagemultipliergb2.py @@ -2,6 +2,7 @@ # # Used by: # Variations of ship: Dominix (3 of 3) +# Ship: Dominix Quafe Edition # Ship: Nestor type = "passive" def handler(fit, ship, context): diff --git a/eos/effects/shipbonusdronedamagemultipliergc2.py b/eos/effects/shipbonusdronedamagemultipliergc2.py index 8c3aa4af0..dc87ee023 100644 --- a/eos/effects/shipbonusdronedamagemultipliergc2.py +++ b/eos/effects/shipbonusdronedamagemultipliergc2.py @@ -2,7 +2,7 @@ # # Used by: # Ships named like: Stratios (2 of 2) -# Variations of ship: Vexor (3 of 4) +# Ships named like: Vexor (3 of 4) type = "passive" def handler(fit, ship, context): level = fit.character.getSkill("Gallente Cruiser").level diff --git a/eos/effects/shipbonusdronehitpointsgb2.py b/eos/effects/shipbonusdronehitpointsgb2.py index 0a526d7e1..aa6c3958a 100644 --- a/eos/effects/shipbonusdronehitpointsgb2.py +++ b/eos/effects/shipbonusdronehitpointsgb2.py @@ -2,6 +2,7 @@ # # Used by: # Variations of ship: Dominix (3 of 3) +# Ship: Dominix Quafe Edition # Ship: Nestor type = "passive" def handler(fit, ship, context): diff --git a/eos/effects/shipbonusdronehitpointsgc2.py b/eos/effects/shipbonusdronehitpointsgc2.py index 5e36004ae..369566d00 100644 --- a/eos/effects/shipbonusdronehitpointsgc2.py +++ b/eos/effects/shipbonusdronehitpointsgc2.py @@ -2,7 +2,7 @@ # # Used by: # Ships named like: Stratios (2 of 2) -# Variations of ship: Vexor (3 of 4) +# Ships named like: Vexor (3 of 4) type = "passive" def handler(fit, ship, context): level = fit.character.getSkill("Gallente Cruiser").level diff --git a/eos/effects/shipbonusdronehitpointsgf.py b/eos/effects/shipbonusdronehitpointsgf.py index d1892d7c8..b5d838c4b 100644 --- a/eos/effects/shipbonusdronehitpointsgf.py +++ b/eos/effects/shipbonusdronehitpointsgf.py @@ -1,8 +1,8 @@ # shipBonusDroneHitpointsGF # # Used by: +# Ships named like: Tristan (2 of 2) # Ship: Astero -# Ship: Tristan type = "passive" def handler(fit, ship, context): level = fit.character.getSkill("Gallente Frigate").level diff --git a/eos/effects/shipbonusdroneminingamountgc2.py b/eos/effects/shipbonusdroneminingamountgc2.py index 60a66e282..643e7f522 100644 --- a/eos/effects/shipbonusdroneminingamountgc2.py +++ b/eos/effects/shipbonusdroneminingamountgc2.py @@ -1,8 +1,7 @@ # shipBonusDroneMiningAmountGC2 # # Used by: -# Ship: Vexor -# Ship: Vexor Navy Issue +# Ships named like: Vexor (3 of 4) type = "passive" def handler(fit, ship, context): level = fit.character.getSkill("Gallente Cruiser").level diff --git a/eos/effects/shipbonusdroneoptimalrangegb.py b/eos/effects/shipbonusdroneoptimalrangegb.py index 746b74c2a..c8e8f2346 100644 --- a/eos/effects/shipbonusdroneoptimalrangegb.py +++ b/eos/effects/shipbonusdroneoptimalrangegb.py @@ -2,6 +2,7 @@ # # Used by: # Ship: Dominix +# Ship: Dominix Quafe Edition type = "passive" def handler(fit, ship, context): level = fit.character.getSkill("Gallente Battleship").level diff --git a/eos/effects/shipbonusdronetrackinggb.py b/eos/effects/shipbonusdronetrackinggb.py index 192608c97..553479ae0 100644 --- a/eos/effects/shipbonusdronetrackinggb.py +++ b/eos/effects/shipbonusdronetrackinggb.py @@ -2,6 +2,7 @@ # # Used by: # Ship: Dominix +# Ship: Dominix Quafe Edition type = "passive" def handler(fit, ship, context): level = fit.character.getSkill("Gallente Battleship").level diff --git a/eos/effects/shipbonusdronetrackinggf.py b/eos/effects/shipbonusdronetrackinggf.py index 9f666dfe4..8e172b68b 100644 --- a/eos/effects/shipbonusdronetrackinggf.py +++ b/eos/effects/shipbonusdronetrackinggf.py @@ -1,7 +1,7 @@ # shipBonusDroneTrackingGF # # Used by: -# Ship: Tristan +# Ships named like: Tristan (2 of 2) type = "passive" def handler(fit, ship, context): level = fit.character.getSkill("Gallente Frigate").level diff --git a/eos/effects/shipbonusheavyassaultlauncherrateoffirecc2.py b/eos/effects/shipbonusheavyassaultlauncherrateoffirecc2.py deleted file mode 100644 index 7edf68e60..000000000 --- a/eos/effects/shipbonusheavyassaultlauncherrateoffirecc2.py +++ /dev/null @@ -1,9 +0,0 @@ -# shipBonusHeavyAssaultLauncherRateOfFireCC2 -# -# Used by: -# Ship: Rook -type = "passive" -def handler(fit, ship, context): - level = fit.character.getSkill("Caldari Cruiser").level - fit.modules.filteredItemBoost(lambda mod: mod.item.group.name == "Missile Launcher Heavy Assault", - "speed", ship.getModifiedItemAttr("shipBonusCC2") * level) diff --git a/eos/effects/shipbonusheavydronearmorhpgc2.py b/eos/effects/shipbonusheavydronearmorhpgc2.py new file mode 100644 index 000000000..55a3a9339 --- /dev/null +++ b/eos/effects/shipbonusheavydronearmorhpgc2.py @@ -0,0 +1,9 @@ +# shipBonusHeavyDroneArmorHPGC2 +# +# Used by: +# Ship: Ishtar +type = "passive" +def handler(fit, ship, context): + level = fit.character.getSkill("Gallente Cruiser").level + fit.drones.filteredItemBoost(lambda drone: drone.item.requiresSkill("Heavy Drone Operation"), + "armorHP", ship.getModifiedItemAttr("shipBonusGC2") * level) diff --git a/eos/effects/shipbonusheavydronedamagemultipliergc2.py b/eos/effects/shipbonusheavydronedamagemultipliergc2.py new file mode 100644 index 000000000..ac7e9ec08 --- /dev/null +++ b/eos/effects/shipbonusheavydronedamagemultipliergc2.py @@ -0,0 +1,9 @@ +# shipBonusHeavyDroneDamageMultiplierGC2 +# +# Used by: +# Ship: Ishtar +type = "passive" +def handler(fit, ship, context): + level = fit.character.getSkill("Gallente Cruiser").level + fit.drones.filteredItemBoost(lambda drone: drone.item.requiresSkill("Heavy Drone Operation"), + "damageMultiplier", ship.getModifiedItemAttr("shipBonusGC2") * level) diff --git a/eos/effects/shipbonusheavydronehpgc2.py b/eos/effects/shipbonusheavydronehpgc2.py new file mode 100644 index 000000000..6e5a858eb --- /dev/null +++ b/eos/effects/shipbonusheavydronehpgc2.py @@ -0,0 +1,9 @@ +# shipBonusHeavyDroneHPGC2 +# +# Used by: +# Ship: Ishtar +type = "passive" +def handler(fit, ship, context): + level = fit.character.getSkill("Gallente Cruiser").level + fit.drones.filteredItemBoost(lambda drone: drone.item.requiresSkill("Heavy Drone Operation"), + "hp", ship.getModifiedItemAttr("shipBonusGC2") * level) diff --git a/eos/effects/shipbonusheavydroneshieldhpgc2.py b/eos/effects/shipbonusheavydroneshieldhpgc2.py new file mode 100644 index 000000000..66e33b8a9 --- /dev/null +++ b/eos/effects/shipbonusheavydroneshieldhpgc2.py @@ -0,0 +1,9 @@ +# shipBonusHeavyDroneShieldHPGC2 +# +# Used by: +# Ship: Ishtar +type = "passive" +def handler(fit, ship, context): + level = fit.character.getSkill("Gallente Cruiser").level + fit.drones.filteredItemBoost(lambda drone: drone.item.requiresSkill("Heavy Drone Operation"), + "shieldCapacity", ship.getModifiedItemAttr("shipBonusGC2") * level) diff --git a/eos/effects/shipbonusheavylauncherrateoffirecc2.py b/eos/effects/shipbonusheavylauncherrateoffirecc2.py deleted file mode 100644 index 5ca8c9393..000000000 --- a/eos/effects/shipbonusheavylauncherrateoffirecc2.py +++ /dev/null @@ -1,9 +0,0 @@ -# shipBonusHeavyLauncherRateOfFireCC2 -# -# Used by: -# Ship: Rook -type = "passive" -def handler(fit, ship, context): - level = fit.character.getSkill("Caldari Cruiser").level - fit.modules.filteredItemBoost(lambda mod: mod.item.group.name == "Missile Launcher Heavy", - "speed", ship.getModifiedItemAttr("shipBonusCC2") * level) diff --git a/eos/effects/shipbonushybridtrackinggf2.py b/eos/effects/shipbonushybridtrackinggf2.py index e0aabdeba..d50ab59b4 100644 --- a/eos/effects/shipbonushybridtrackinggf2.py +++ b/eos/effects/shipbonushybridtrackinggf2.py @@ -1,10 +1,10 @@ # shipBonusHybridTrackingGF2 # # Used by: +# Ships named like: Tristan (2 of 2) # Ship: Ares # Ship: Federation Navy Comet # Ship: Police Pursuit Comet -# Ship: Tristan type = "passive" def handler(fit, ship, context): level = fit.character.getSkill("Gallente Frigate").level diff --git a/eos/effects/shipbonuslightdronearmorhpgc2.py b/eos/effects/shipbonuslightdronearmorhpgc2.py new file mode 100644 index 000000000..99c1aa07f --- /dev/null +++ b/eos/effects/shipbonuslightdronearmorhpgc2.py @@ -0,0 +1,9 @@ +# shipBonusLightDroneArmorHPGC2 +# +# Used by: +# Ship: Ishtar +type = "passive" +def handler(fit, ship, context): + level = fit.character.getSkill("Gallente Cruiser").level + fit.drones.filteredItemBoost(lambda drone: drone.item.requiresSkill("Light Drone Operation"), + "armorHP", ship.getModifiedItemAttr("shipBonusGC2") * level) \ No newline at end of file diff --git a/eos/effects/shipbonuslightdronedamagemultipliergc2.py b/eos/effects/shipbonuslightdronedamagemultipliergc2.py new file mode 100644 index 000000000..104b7f5a1 --- /dev/null +++ b/eos/effects/shipbonuslightdronedamagemultipliergc2.py @@ -0,0 +1,9 @@ +# shipBonusLightDroneDamageMultiplierGC2 +# +# Used by: +# Ship: Ishtar +type = "passive" +def handler(fit, ship, context): + level = fit.character.getSkill("Gallente Cruiser").level + fit.drones.filteredItemBoost(lambda drone: drone.item.requiresSkill("Light Drone Operation"), + "damageMultiplier", ship.getModifiedItemAttr("shipBonusGC2") * level) diff --git a/eos/effects/shipbonuslightdronehpgc2.py b/eos/effects/shipbonuslightdronehpgc2.py new file mode 100644 index 000000000..7a9328b1e --- /dev/null +++ b/eos/effects/shipbonuslightdronehpgc2.py @@ -0,0 +1,9 @@ +# shipBonusLightDroneHPGC2 +# +# Used by: +# Ship: Ishtar +type = "passive" +def handler(fit, ship, context): + level = fit.character.getSkill("Gallente Cruiser").level + fit.drones.filteredItemBoost(lambda drone: drone.item.requiresSkill("Light Drone Operation"), + "hp", ship.getModifiedItemAttr("shipBonusGC2") * level) diff --git a/eos/effects/shipbonuslightdroneshieldhpgc2.py b/eos/effects/shipbonuslightdroneshieldhpgc2.py new file mode 100644 index 000000000..d6b6dd492 --- /dev/null +++ b/eos/effects/shipbonuslightdroneshieldhpgc2.py @@ -0,0 +1,9 @@ +# shipBonusLightDroneShieldHPGC2 +# +# Used by: +# Ship: Ishtar +type = "passive" +def handler(fit, ship, context): + level = fit.character.getSkill("Gallente Cruiser").level + fit.drones.filteredItemBoost(lambda drone: drone.item.requiresSkill("Light Drone Operation"), + "shieldCapacity", ship.getModifiedItemAttr("shipBonusGC2") * level) diff --git a/eos/effects/shipbonusmediumdronearmorhpgc2.py b/eos/effects/shipbonusmediumdronearmorhpgc2.py new file mode 100644 index 000000000..2439abe96 --- /dev/null +++ b/eos/effects/shipbonusmediumdronearmorhpgc2.py @@ -0,0 +1,9 @@ +# shipBonusMediumDroneArmorHPGC2 +# +# Used by: +# Ship: Ishtar +type = "passive" +def handler(fit, ship, context): + level = fit.character.getSkill("Gallente Cruiser").level + fit.drones.filteredItemBoost(lambda drone: drone.item.requiresSkill("Medium Drone Operation"), + "armorHP", ship.getModifiedItemAttr("shipBonusGC2") * level) diff --git a/eos/effects/shipbonusmediumdronedamagemultipliergc2.py b/eos/effects/shipbonusmediumdronedamagemultipliergc2.py new file mode 100644 index 000000000..b5d2da3bf --- /dev/null +++ b/eos/effects/shipbonusmediumdronedamagemultipliergc2.py @@ -0,0 +1,9 @@ +# shipBonusMediumDroneDamageMultiplierGC2 +# +# Used by: +# Ship: Ishtar +type = "passive" +def handler(fit, ship, context): + level = fit.character.getSkill("Gallente Cruiser").level + fit.drones.filteredItemBoost(lambda drone: drone.item.requiresSkill("Medium Drone Operation"), + "damageMultiplier", ship.getModifiedItemAttr("shipBonusGC2") * level) diff --git a/eos/effects/shipbonusmediumdronehpgc2.py b/eos/effects/shipbonusmediumdronehpgc2.py new file mode 100644 index 000000000..74644acb0 --- /dev/null +++ b/eos/effects/shipbonusmediumdronehpgc2.py @@ -0,0 +1,9 @@ +# shipBonusMediumDroneHPGC2 +# +# Used by: +# Ship: Ishtar +type = "passive" +def handler(fit, ship, context): + level = fit.character.getSkill("Gallente Cruiser").level + fit.drones.filteredItemBoost(lambda drone: drone.item.requiresSkill("Medium Drone Operation"), + "hp", ship.getModifiedItemAttr("shipBonusGC2") * level) diff --git a/eos/effects/shipbonusmediumdroneshieldhpgc2.py b/eos/effects/shipbonusmediumdroneshieldhpgc2.py new file mode 100644 index 000000000..210cc6eb8 --- /dev/null +++ b/eos/effects/shipbonusmediumdroneshieldhpgc2.py @@ -0,0 +1,9 @@ +# shipBonusMediumDroneShieldHPGC2 +# +# Used by: +# Ship: Ishtar +type = "passive" +def handler(fit, ship, context): + level = fit.character.getSkill("Gallente Cruiser").level + fit.drones.filteredItemBoost(lambda drone: drone.item.requiresSkill("Medium Drone Operation"), + "shieldCapacity", ship.getModifiedItemAttr("shipBonusGC2") * level) diff --git a/eos/effects/shipbonussentryarmorhpgc3.py b/eos/effects/shipbonussentryarmorhpgc3.py new file mode 100644 index 000000000..80dc34d01 --- /dev/null +++ b/eos/effects/shipbonussentryarmorhpgc3.py @@ -0,0 +1,9 @@ +# shipBonusSentryArmorHPGC3 +# +# Used by: +# Ship: Ishtar +type = "passive" +def handler(fit, ship, context): + level = fit.character.getSkill("Gallente Cruiser").level + fit.drones.filteredItemBoost(lambda drone: drone.item.requiresSkill("Sentry Drone Interfacing"), + "armorHP", ship.getModifiedItemAttr("shipBonusGC3") * level) diff --git a/eos/effects/shipbonussentrydamagemultipliergc3.py b/eos/effects/shipbonussentrydamagemultipliergc3.py new file mode 100644 index 000000000..73987a70b --- /dev/null +++ b/eos/effects/shipbonussentrydamagemultipliergc3.py @@ -0,0 +1,9 @@ +# shipBonusSentryDamageMultiplierGC3 +# +# Used by: +# Ship: Ishtar +type = "passive" +def handler(fit, ship, context): + level = fit.character.getSkill("Gallente Cruiser").level + fit.drones.filteredItemBoost(lambda drone: drone.item.requiresSkill("Sentry Drone Interfacing"), + "damageMultiplier", ship.getModifiedItemAttr("shipBonusGC3") * level) diff --git a/eos/effects/shipbonussentryhpgc3.py b/eos/effects/shipbonussentryhpgc3.py new file mode 100644 index 000000000..633c8267e --- /dev/null +++ b/eos/effects/shipbonussentryhpgc3.py @@ -0,0 +1,9 @@ +# shipBonusSentryHPGC3 +# +# Used by: +# Ship: Ishtar +type = "passive" +def handler(fit, ship, context): + level = fit.character.getSkill("Gallente Cruiser").level + fit.drones.filteredItemBoost(lambda drone: drone.item.requiresSkill("Sentry Drone Interfacing"), + "hp", ship.getModifiedItemAttr("shipBonusGC3") * level) diff --git a/eos/effects/shipbonussentryshieldhpgc3.py b/eos/effects/shipbonussentryshieldhpgc3.py new file mode 100644 index 000000000..64bb46455 --- /dev/null +++ b/eos/effects/shipbonussentryshieldhpgc3.py @@ -0,0 +1,9 @@ +# shipBonusSentryShieldHPGC3 +# +# Used by: +# Ship: Ishtar +type = "passive" +def handler(fit, ship, context): + level = fit.character.getSkill("Gallente Cruiser").level + fit.drones.filteredItemBoost(lambda drone: drone.item.requiresSkill("Sentry Drone Interfacing"), + "shieldCapacity", ship.getModifiedItemAttr("shipBonusGC3") * level) diff --git a/eos/effects/shipbonusthermalmissiledamagegc2.py b/eos/effects/shipbonusthermalmissiledamagegc2.py index 05e602e20..19fefc9c7 100644 --- a/eos/effects/shipbonusthermalmissiledamagegc2.py +++ b/eos/effects/shipbonusthermalmissiledamagegc2.py @@ -3,6 +3,7 @@ # Used by: # Ship: Chameleon # Ship: Gila + type = "passive" def handler(fit, ship, context): level = fit.character.getSkill("Gallente Cruiser").level diff --git a/eos/effects/shipheatdamageminmatartacticaldestroyer3.py b/eos/effects/shipheatdamageminmatartacticaldestroyer3.py new file mode 100644 index 000000000..13607c1fa --- /dev/null +++ b/eos/effects/shipheatdamageminmatartacticaldestroyer3.py @@ -0,0 +1,9 @@ +# shipHeatDamageMinmatarTacticalDestroyer3 +# +# Used by: +# Ship: Svipul +type = "passive" +def handler(fit, ship, context): + level = fit.character.getSkill("Minmatar Tactical Destroyer").level + fit.modules.filteredItemBoost(lambda mod: True, "heatDamage", + ship.getModifiedItemAttr("shipBonusTacticalDestroyerMinmatar3") * level) diff --git a/eos/effects/shiphtdmgbonusfixedgc.py b/eos/effects/shiphtdmgbonusfixedgc.py index c0fac0f09..33ad961e3 100644 --- a/eos/effects/shiphtdmgbonusfixedgc.py +++ b/eos/effects/shiphtdmgbonusfixedgc.py @@ -2,13 +2,11 @@ # # Used by: # Ships named like: Thorax (3 of 3) +# Ships named like: Vexor (3 of 4) # Ship: Adrestia # Ship: Arazu # Ship: Deimos # Ship: Exequror Navy Issue -# Ship: Guardian-Vexor -# Ship: Lachesis -# Ship: Vexor type = "passive" def handler(fit, ship, context): level = fit.character.getSkill("Gallente Cruiser").level diff --git a/eos/effects/shiphybridtrackinggc.py b/eos/effects/shiphybridtrackinggc.py index f99cea0b0..02215246a 100644 --- a/eos/effects/shiphybridtrackinggc.py +++ b/eos/effects/shiphybridtrackinggc.py @@ -1,6 +1,7 @@ # shipHybridTrackingGC # # Used by: +# Ship: Lachesis # Ship: Phobos type = "passive" def handler(fit, ship, context): diff --git a/eos/effects/shipmissilebonusemdmgmc.py b/eos/effects/shipmissilebonusemdmgmc.py new file mode 100644 index 000000000..1230c3f94 --- /dev/null +++ b/eos/effects/shipmissilebonusemdmgmc.py @@ -0,0 +1,9 @@ +# shipMissileBonusEMdmgMC +# +# Used by: +# Ship: Rapier +type = "passive" +def handler(fit, ship, context): + level = fit.character.getSkill("Minmatar Cruiser").level + fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Missile Launcher Operation"), + "emDamage", ship.getModifiedItemAttr("shipBonusMC") * level) diff --git a/eos/effects/shipmissilebonusexpdmgmc.py b/eos/effects/shipmissilebonusexpdmgmc.py new file mode 100644 index 000000000..cdaa2637d --- /dev/null +++ b/eos/effects/shipmissilebonusexpdmgmc.py @@ -0,0 +1,9 @@ +# shipMissileBonusExpdmgMC +# +# Used by: +# Ship: Rapier +type = "passive" +def handler(fit, ship, context): + level = fit.character.getSkill("Minmatar Cruiser").level + fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Missile Launcher Operation"), + "explosiveDamage", ship.getModifiedItemAttr("shipBonusMC") * level) diff --git a/eos/effects/shipmissilebonuskindmgmc.py b/eos/effects/shipmissilebonuskindmgmc.py new file mode 100644 index 000000000..c4173ca36 --- /dev/null +++ b/eos/effects/shipmissilebonuskindmgmc.py @@ -0,0 +1,9 @@ +# shipMissileBonusKindmgMC +# +# Used by: +# Ship: Rapier +type = "passive" +def handler(fit, ship, context): + level = fit.character.getSkill("Minmatar Cruiser").level + fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Missile Launcher Operation"), + "kineticDamage", ship.getModifiedItemAttr("shipBonusMC") * level) diff --git a/eos/effects/shipmissilebonusthermdmgmc.py b/eos/effects/shipmissilebonusthermdmgmc.py new file mode 100644 index 000000000..90a8c3daa --- /dev/null +++ b/eos/effects/shipmissilebonusthermdmgmc.py @@ -0,0 +1,9 @@ +# shipMissileBonusThermdmgMC +# +# Used by: +# Ship: Rapier +type = "passive" +def handler(fit, ship, context): + level = fit.character.getSkill("Minmatar Cruiser").level + fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Missile Launcher Operation"), + "thermalDamage", ship.getModifiedItemAttr("shipBonusMC") * level) diff --git a/eos/effects/shipmissilekindamagecc2.py b/eos/effects/shipmissilekindamagecc2.py index eee63477c..97ff60cc1 100644 --- a/eos/effects/shipmissilekindamagecc2.py +++ b/eos/effects/shipmissilekindamagecc2.py @@ -2,6 +2,7 @@ # # Used by: # Ship: Osprey Navy Issue +# Ship: Rook type = "passive" def handler(fit, ship, context): level = fit.character.getSkill("Caldari Cruiser").level diff --git a/eos/effects/shipmodemaxtargetrangepostdiv.py b/eos/effects/shipmodemaxtargetrangepostdiv.py index d9cb50254..573574fe7 100644 --- a/eos/effects/shipmodemaxtargetrangepostdiv.py +++ b/eos/effects/shipmodemaxtargetrangepostdiv.py @@ -1,8 +1,12 @@ # shipModeMaxTargetRangePostDiv # # Used by: -# Module: Amarr Tactical Destroyer Sharpshooter Mode +# Modules named like: Sharpshooter Mode (2 of 2) type = "passive" def handler(fit, module, context): - fit.ship.multiplyItemAttr("maxTargetRange", 1/module.getModifiedItemAttr("modeMaxTargetRangePostDiv"), - stackingPenalties = True, penaltyGroup="postDiv") + fit.ship.multiplyItemAttr( + "maxTargetRange", + 1 / module.getModifiedItemAttr("modeMaxTargetRangePostDiv"), + stackingPenalties=True, + penaltyGroup="postDiv" + ) diff --git a/eos/effects/shipmodescanrespostdiv.py b/eos/effects/shipmodescanrespostdiv.py index 07db84ad5..f418fa328 100644 --- a/eos/effects/shipmodescanrespostdiv.py +++ b/eos/effects/shipmodescanrespostdiv.py @@ -1,8 +1,12 @@ # shipModeScanResPostDiv # # Used by: -# Module: Amarr Tactical Destroyer Sharpshooter Mode +# Modules named like: Sharpshooter Mode (2 of 2) type = "passive" def handler(fit, module, context): - fit.ship.multiplyItemAttr("scanResolution", 1/module.getModifiedItemAttr("modeScanResPostDiv"), - stackingPenalties = True, penaltyGroup="postDiv") + fit.ship.multiplyItemAttr( + "scanResolution", + 1 / module.getModifiedItemAttr("modeScanResPostDiv"), + stackingPenalties=True, + penaltyGroup="postDiv" + ) diff --git a/eos/effects/shipmodescanstrengthpostdiv.py b/eos/effects/shipmodescanstrengthpostdiv.py index cdf2b20f3..e42d5f69c 100644 --- a/eos/effects/shipmodescanstrengthpostdiv.py +++ b/eos/effects/shipmodescanstrengthpostdiv.py @@ -1,8 +1,13 @@ # shipModeScanStrengthPostDiv # # Used by: -# Module: Amarr Tactical Destroyer Sharpshooter Mode +# Modules named like: Sharpshooter Mode (2 of 2) type = "passive" def handler(fit, module, context): - fit.ship.multiplyItemAttr("scanRadarStrength", 1/module.getModifiedItemAttr("modeRadarStrengthPostDiv"), - stackingPenalties = True, penaltyGroup="postDiv") + for scanType in ("Gravimetric", "Magnetometric", "Radar", "Ladar"): + fit.ship.multiplyItemAttr( + "scan{}Strength".format(scanType), + 1 / (module.getModifiedItemAttr("mode{}StrengthPostDiv".format(scanType)) or 1), + stackingPenalties=True, + penaltyGroup="postDiv" + ) diff --git a/eos/effects/shipmodesetoptimalrangepostdiv.py b/eos/effects/shipmodesetoptimalrangepostdiv.py index bafceea86..a4aadbee8 100644 --- a/eos/effects/shipmodesetoptimalrangepostdiv.py +++ b/eos/effects/shipmodesetoptimalrangepostdiv.py @@ -1,9 +1,13 @@ # shipModeSETOptimalRangePostDiv # # Used by: -# Module: Amarr Tactical Destroyer Sharpshooter Mode +# Module: Confessor Sharpshooter Mode type = "passive" def handler(fit, module, context): - fit.modules.filteredItemMultiply(lambda mod: mod.item.requiresSkill("Small Energy Turret"), - "maxRange", 1/module.getModifiedItemAttr("modeMaxRangePostDiv"), - stackingPenalties=True, penaltyGroup="postDiv") + fit.modules.filteredItemMultiply( + lambda mod: mod.item.requiresSkill("Small Energy Turret"), + "maxRange", + 1 / module.getModifiedItemAttr("modeMaxRangePostDiv"), + stackingPenalties=True, + penaltyGroup="postDiv" + ) diff --git a/eos/effects/shipmodespttrackingpostdiv.py b/eos/effects/shipmodespttrackingpostdiv.py new file mode 100644 index 000000000..40c5cdaeb --- /dev/null +++ b/eos/effects/shipmodespttrackingpostdiv.py @@ -0,0 +1,13 @@ +# shipModeSPTTrackingPostDiv +# +# Used by: +# Module: Svipul Sharpshooter Mode +type = "passive" +def handler(fit, module, context): + fit.modules.filteredItemMultiply( + lambda mod: mod.item.requiresSkill("Small Projectile Turret"), + "trackingSpeed", + 1 / module.getModifiedItemAttr("modeTrackingPostDiv"), + stackingPenalties=True, + penaltyGroup="postDiv" + ) diff --git a/eos/effects/shippturretfalloffbonusgb.py b/eos/effects/shippturretfalloffbonusgb.py index 7088999a4..4286e1bd6 100644 --- a/eos/effects/shippturretfalloffbonusgb.py +++ b/eos/effects/shippturretfalloffbonusgb.py @@ -6,4 +6,4 @@ type = "passive" def handler(fit, ship, context): level = fit.character.getSkill("Gallente Battleship").level fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Large Projectile Turret"), - "falloff", ship.getModifiedItemAttr("shipBonusGB") * level) \ No newline at end of file + "falloff", ship.getModifiedItemAttr("shipBonusGB") * level) diff --git a/eos/effects/shippturretspeedbonusmc.py b/eos/effects/shippturretspeedbonusmc.py index 6a5ad4d5b..c561afc47 100644 --- a/eos/effects/shippturretspeedbonusmc.py +++ b/eos/effects/shippturretspeedbonusmc.py @@ -5,7 +5,6 @@ # Variations of ship: Rupture (3 of 3) # Variations of ship: Stabber (3 of 3) # Ship: Huginn -# Ship: Rapier # Ship: Scythe Fleet Issue type = "passive" def handler(fit, ship, context): diff --git a/eos/effects/shipsptdamageminmatartacticaldestroyer1.py b/eos/effects/shipsptdamageminmatartacticaldestroyer1.py new file mode 100644 index 000000000..349767adf --- /dev/null +++ b/eos/effects/shipsptdamageminmatartacticaldestroyer1.py @@ -0,0 +1,9 @@ +# shipSPTDamageMinmatarTacticalDestroyer1 +# +# Used by: +# Ship: Svipul +type = "passive" +def handler(fit, ship, context): + level = fit.character.getSkill("Minmatar Tactical Destroyer").level + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Small Projectile Turret"), + "damageMultiplier", ship.getModifiedItemAttr("shipBonusTacticalDestroyerMinmatar1") * level) diff --git a/eos/effects/shipsptoptimalminmatartacticaldestroyer2.py b/eos/effects/shipsptoptimalminmatartacticaldestroyer2.py new file mode 100644 index 000000000..da0ff3d12 --- /dev/null +++ b/eos/effects/shipsptoptimalminmatartacticaldestroyer2.py @@ -0,0 +1,9 @@ +# shipSPTOptimalMinmatarTacticalDestroyer2 +# +# Used by: +# Ship: Svipul +type = "passive" +def handler(fit, ship, context): + level = fit.character.getSkill("Minmatar Tactical Destroyer").level + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Small Projectile Turret"), + "maxRange", ship.getModifiedItemAttr("shipBonusTacticalDestroyerMinmatar2") * level) diff --git a/eos/effects/structurehpmultiply.py b/eos/effects/structurehpmultiply.py index 502d67636..aa7d43c7c 100644 --- a/eos/effects/structurehpmultiply.py +++ b/eos/effects/structurehpmultiply.py @@ -1,8 +1,8 @@ # structureHPMultiply # # Used by: -# Modules from group: Nanofiber Internal Structure (14 of 14) -# Modules from group: Reinforced Bulkhead (12 of 12) +# Modules from group: Nanofiber Internal Structure (7 of 7) +# Modules from group: Reinforced Bulkhead (8 of 8) # Modules named like: QA Multiship Module Players (4 of 4) type = "passive" def handler(fit, module, context): diff --git a/eos/effects/structurehpmultiplypassive.py b/eos/effects/structurehpmultiplypassive.py index 60159c104..89ab600df 100644 --- a/eos/effects/structurehpmultiplypassive.py +++ b/eos/effects/structurehpmultiplypassive.py @@ -1,7 +1,7 @@ # structureHPMultiplyPassive # # Used by: -# Modules from group: Expanded Cargohold (13 of 13) +# Modules from group: Expanded Cargohold (7 of 7) type = "passive" def handler(fit, module, context): fit.ship.multiplyItemAttr("hp", module.getModifiedItemAttr("structureHPMultiplier")) \ No newline at end of file diff --git a/eos/effects/subsystembonuscaldaridefensiveshieldrechargerate.py b/eos/effects/subsystembonuscaldaridefensiveshieldrechargerate.py new file mode 100644 index 000000000..7c63b3a27 --- /dev/null +++ b/eos/effects/subsystembonuscaldaridefensiveshieldrechargerate.py @@ -0,0 +1,8 @@ +# subsystemBonusCaldariDefensiveShieldRechargeRate +# +# Used by: +# Subsystem: Tengu Defensive - Supplemental Screening +type = "passive" +def handler(fit, module, context): + level = fit.character.getSkill("Caldari Defensive Systems").level + fit.ship.boostItemAttr("shieldRechargeRate", module.getModifiedItemAttr("subsystemBonusCaldariDefensive2") * level) diff --git a/eos/effects/targetattack.py b/eos/effects/targetattack.py index 3403c880b..3fafbf2fa 100644 --- a/eos/effects/targetattack.py +++ b/eos/effects/targetattack.py @@ -3,7 +3,7 @@ # Used by: # Drones from group: Combat Drone (74 of 74) # Drones from group: Fighter Drone (4 of 4) -# Modules from group: Energy Weapon (186 of 186) +# Modules from group: Energy Weapon (186 of 187) type = 'active' def handler(fit, module, context): # Set reload time to 1 second diff --git a/eos/effects/velocitybonusonline.py b/eos/effects/velocitybonusonline.py index ef6a5e458..1af6d4411 100644 --- a/eos/effects/velocitybonusonline.py +++ b/eos/effects/velocitybonusonline.py @@ -1,8 +1,8 @@ # velocityBonusOnline # # Used by: -# Modules from group: Nanofiber Internal Structure (14 of 14) -# Modules from group: Overdrive Injector System (14 of 14) +# Modules from group: Nanofiber Internal Structure (7 of 7) +# Modules from group: Overdrive Injector System (7 of 7) type = "passive" def handler(fit, module, context): fit.ship.boostItemAttr("maxVelocity", module.getModifiedItemAttr("implantBonusVelocity"), diff --git a/eos/gamedata.py b/eos/gamedata.py index 8c1fc1df2..d5691da46 100644 --- a/eos/gamedata.py +++ b/eos/gamedata.py @@ -120,7 +120,12 @@ class Effect(EqBase): ''' try: self.__effectModule = effectModule = __import__('eos.effects.' + self.handlerName, fromlist=True) - self.__handler = getattr(effectModule, "handler") + try: + self.__handler = getattr(effectModule, "handler") + except AttributeError: + print "effect {} exists, but no handler".format(self.handlerName) + raise + try: self.__runTime = getattr(effectModule, "runTime") or "normal" except AttributeError: @@ -133,7 +138,7 @@ class Effect(EqBase): t = t if isinstance(t, tuple) or t is None else (t,) self.__type = t - except ImportError as e: + except (ImportError, AttributeError) as e: self.__handler = effectDummy self.__runTime = "normal" self.__type = None diff --git a/eos/saveddata/fit.py b/eos/saveddata/fit.py index 484e314fe..f49c1f60e 100644 --- a/eos/saveddata/fit.py +++ b/eos/saveddata/fit.py @@ -406,12 +406,14 @@ class Fit(object): (effect.isType("active") and thing.state >= State.ACTIVE): # Run effect, and get proper bonuses applied try: + self.register(thing) effect.handler(self, thing, context) except: pass else: # Run effect, and get proper bonuses applied try: + self.register(thing) effect.handler(self, thing, context) except: pass @@ -735,7 +737,7 @@ class Fit(object): capAdded = 0 for mod in self.modules: if mod.state >= State.ACTIVE: - if mod.getModifiedItemAttr("capacitorNeed") != 0: + if (mod.getModifiedItemAttr("capacitorNeed") or 0) != 0: cycleTime = mod.rawCycleTime or 0 reactivationTime = mod.getModifiedItemAttr("moduleReactivationDelay") or 0 fullCycleTime = cycleTime + reactivationTime diff --git a/gpl.txt b/gpl.txt index 5737cfa27..94a9ed024 100644 --- a/gpl.txt +++ b/gpl.txt @@ -549,14 +549,14 @@ to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. - 13. Use with the GNU General Public License. + 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed -under version 3 of the GNU General Public License into a single +under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, -but the special requirements of the GNU General Public License, +but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. diff --git a/gui/builtinContextMenus/damagePattern.py b/gui/builtinContextMenus/damagePattern.py index 352340204..29a029389 100644 --- a/gui/builtinContextMenus/damagePattern.py +++ b/gui/builtinContextMenus/damagePattern.py @@ -24,7 +24,7 @@ class DamagePattern(ContextMenu): self.fit = sFit.getFit(fitID) self.patterns = sDP.getDamagePatternList() - self.patterns.sort(key=lambda p: (p.name not in ["Uniform","Selected Ammo"], p.name)) + self.patterns.sort(key=lambda p: (p.name not in ["Uniform", "Selected Ammo"], p.name)) self.patternIds = {} self.subMenus = OrderedDict() @@ -71,7 +71,6 @@ class DamagePattern(ContextMenu): def getSubMenu(self, context, selection, rootMenu, i, pitem): msw = True if "wxMSW" in wx.PlatformInfo else False - rootMenu.Bind(wx.EVT_MENU, self.handlePatternSwitch) # this bit is required for some reason if self.m[i] not in self.subMenus: # if we're trying to get submenu to something that shouldn't have one, @@ -79,10 +78,11 @@ class DamagePattern(ContextMenu): # our patternIds mapping, then return None for no submenu id = pitem.GetId() self.patternIds[id] = self.singles[i] + rootMenu.Bind(wx.EVT_MENU, self.handlePatternSwitch, pitem) if self.patternIds[id] == self.fit.damagePattern: bitmap = bitmapLoader.getBitmap("state_active_small", "icons") pitem.SetBitmap(bitmap) - return None + return False sub = wx.Menu() diff --git a/gui/builtinPreferenceViews/pyfaGeneralPreferences.py b/gui/builtinPreferenceViews/pyfaGeneralPreferences.py index 98190fcde..60468ec9a 100644 --- a/gui/builtinPreferenceViews/pyfaGeneralPreferences.py +++ b/gui/builtinPreferenceViews/pyfaGeneralPreferences.py @@ -53,6 +53,9 @@ class PFGeneralPref ( PreferenceView): labelSizer.Add( self.cbRackLabels, 0, wx.ALL|wx.EXPAND, 5 ) mainSizer.Add( labelSizer, 0, wx.LEFT|wx.EXPAND, 30 ) + self.cbShowTooltip = wx.CheckBox( panel, wx.ID_ANY, u"Show tab tooltips", wx.DefaultPosition, wx.DefaultSize, 0 ) + mainSizer.Add( self.cbShowTooltip, 0, wx.ALL|wx.EXPAND, 5 ) + defCharSizer = wx.BoxSizer( wx.HORIZONTAL ) self.sFit = service.Fit.getInstance() @@ -65,6 +68,7 @@ class PFGeneralPref ( PreferenceView): self.cbRackLabels.SetValue(self.sFit.serviceFittingOptions["rackLabels"] or False) self.cbCompactSkills.SetValue(self.sFit.serviceFittingOptions["compactSkills"] or False) self.cbReopenFits.SetValue(self.openFitsSettings["enabled"]) + self.cbShowTooltip.SetValue(self.sFit.serviceFittingOptions["showTooltip"] or False) self.cbGlobalChar.Bind(wx.EVT_CHECKBOX, self.OnCBGlobalCharStateChange) self.cbGlobalDmgPattern.Bind(wx.EVT_CHECKBOX, self.OnCBGlobalDmgPatternStateChange) @@ -74,6 +78,7 @@ class PFGeneralPref ( PreferenceView): self.cbRackLabels.Bind(wx.EVT_CHECKBOX, self.onCBGlobalRackLabels) self.cbCompactSkills.Bind(wx.EVT_CHECKBOX, self.onCBCompactSkills) self.cbReopenFits.Bind(wx.EVT_CHECKBOX, self.onCBReopenFits) + self.cbShowTooltip.Bind(wx.EVT_CHECKBOX, self.onCBShowTooltip) self.cbRackLabels.Enable(self.sFit.serviceFittingOptions["rackSlots"] or False) @@ -127,6 +132,9 @@ class PFGeneralPref ( PreferenceView): def onCBReopenFits(self, event): self.openFitsSettings["enabled"] = self.cbReopenFits.GetValue() + def onCBShowTooltip(self, event): + self.sFit.serviceFittingOptions["showTooltip"] = self.cbShowTooltip.GetValue() + def getImage(self): return bitmapLoader.getBitmap("prefs_settings", "icons") diff --git a/gui/builtinStatsViews/firepowerViewFull.py b/gui/builtinStatsViews/firepowerViewFull.py index e6e1df75a..a7180252e 100644 --- a/gui/builtinStatsViews/firepowerViewFull.py +++ b/gui/builtinStatsViews/firepowerViewFull.py @@ -43,12 +43,10 @@ class FirepowerViewFull(StatsView): parent = self.panel = contentPanel self.headerPanel = headerPanel - headerContentSizer = wx.BoxSizer(wx.HORIZONTAL) - hsizer = headerPanel.GetSizer() - hsizer.Add(headerContentSizer, 0, 0, 0) - self.stEff = wx.StaticText(headerPanel, wx.ID_ANY, "( Effective )") - headerContentSizer.Add(self.stEff) - headerPanel.GetParent().AddToggleItem(self.stEff) + hsizer = self.headerPanel.GetSizer() + self.stEff = wx.StaticText(self.headerPanel, wx.ID_ANY, "( Effective )") + hsizer.Add(self.stEff) + self.headerPanel.GetParent().AddToggleItem(self.stEff) panel = "full" @@ -59,7 +57,7 @@ class FirepowerViewFull(StatsView): counter = 0 - for damageType, image in (("weapon", "turret") , ("drone", "droneDPS")): + for damageType, image in (("weapon", "turret"), ("drone", "droneDPS")): baseBox = wx.BoxSizer(wx.HORIZONTAL) sizerFirepower.Add(baseBox, 1, wx.ALIGN_LEFT if counter == 0 else wx.ALIGN_CENTER_HORIZONTAL) @@ -124,6 +122,12 @@ class FirepowerViewFull(StatsView): # And no longer display us self.panel.GetSizer().Clear(True) self.panel.GetSizer().Layout() + + # Remove effective label + hsizer = self.headerPanel.GetSizer() + hsizer.Remove(self.stEff) + self.stEff.Destroy() + # Get the new view view = StatsView.getView("miningyieldViewFull")(self.parent) view.populatePanel(self.panel, self.headerPanel) diff --git a/gui/builtinViewColumns/ammo.py b/gui/builtinViewColumns/ammo.py index cb3234ccc..fe50c6fbd 100644 --- a/gui/builtinViewColumns/ammo.py +++ b/gui/builtinViewColumns/ammo.py @@ -42,7 +42,6 @@ class Ammo(ViewColumn): return text - def getImageId(self, mod): return -1 diff --git a/gui/builtinViewColumns/ammoIcon.py b/gui/builtinViewColumns/ammoIcon.py index b712ec435..19d55364e 100644 --- a/gui/builtinViewColumns/ammoIcon.py +++ b/gui/builtinViewColumns/ammoIcon.py @@ -48,4 +48,8 @@ class AmmoIcon(ViewColumn): else: return -1 + def getToolTip(self, mod): + if isinstance(mod, Module) and mod.charge is not None: + return mod.charge.name + AmmoIcon.register() diff --git a/gui/builtinViewColumns/attributeDisplay.py b/gui/builtinViewColumns/attributeDisplay.py index a55a50407..86966574b 100644 --- a/gui/builtinViewColumns/attributeDisplay.py +++ b/gui/builtinViewColumns/attributeDisplay.py @@ -89,6 +89,12 @@ class AttributeDisplay(ViewColumn): def getImageId(self, mod): return -1 + def getToolTip(self, stuff): + if self.info.name == "cpu": + return "CPU" + else: + return self.info.name.title() + @staticmethod def getParameters(): return (("attribute", str, None), diff --git a/gui/builtinViewColumns/capacitorUse.py b/gui/builtinViewColumns/capacitorUse.py index 9e4916f2b..497869a66 100644 --- a/gui/builtinViewColumns/capacitorUse.py +++ b/gui/builtinViewColumns/capacitorUse.py @@ -34,9 +34,8 @@ class CapacitorUse(ViewColumn): sAttr = service.Attribute.getInstance() info = sAttr.getAttributeInfo("capacitorNeed") - self.imageId = fittingView.imageList.GetImageIndex(info.icon.iconFile, "pack") - self.bitmap = bitmapLoader.getBitmap(info.icon.iconFile, "pack") - + self.imageId = fittingView.imageList.GetImageIndex("capacitorRecharge_small", "icons") + self.bitmap = bitmapLoader.getBitmap("capacitorRecharge_small", "icons") def getText(self, mod): if isinstance(mod, Mode): @@ -51,4 +50,7 @@ class CapacitorUse(ViewColumn): def getImageId(self, mod): return -1 + def getToolTip(self, mod): + return self.name + CapacitorUse.register() diff --git a/gui/builtinViewColumns/maxRange.py b/gui/builtinViewColumns/maxRange.py index be6be2a86..17d27ef5d 100644 --- a/gui/builtinViewColumns/maxRange.py +++ b/gui/builtinViewColumns/maxRange.py @@ -74,4 +74,7 @@ class MaxRange(ViewColumn): return (("displayName", bool, False), ("showIcon", bool, True)) + def getToolTip(self, mod): + return "Optimal + Falloff" + MaxRange.register() diff --git a/gui/builtinViewColumns/price.py b/gui/builtinViewColumns/price.py index 0afcb22c0..5fe6ef954 100644 --- a/gui/builtinViewColumns/price.py +++ b/gui/builtinViewColumns/price.py @@ -60,4 +60,7 @@ class Price(ViewColumn): def getImageId(self, mod): return -1 + def getToolTip(self, mod): + return self.name + Price.register() diff --git a/gui/builtinViewColumns/state.py b/gui/builtinViewColumns/state.py index 01e93e4f6..d26c46443 100644 --- a/gui/builtinViewColumns/state.py +++ b/gui/builtinViewColumns/state.py @@ -44,6 +44,10 @@ class State(ViewColumn): def getText(self, mod): return "" + def getToolTip(self, mod): + if isinstance(mod, Module) and not mod.isEmpty: + return State_.getName(mod.state).title() + def getImageId(self, stuff): if isinstance(stuff, Drone): return self.checkedId if stuff.amountActive > 0 else self.uncheckedId diff --git a/gui/builtinViews/fittingView.py b/gui/builtinViews/fittingView.py index 455e1e06b..76c291cdd 100644 --- a/gui/builtinViews/fittingView.py +++ b/gui/builtinViews/fittingView.py @@ -141,6 +141,7 @@ class FittingView(d.Display): self.Bind(wx.EVT_KEY_UP, self.kbEvent) self.Bind(wx.EVT_LEFT_DOWN, self.click) self.Bind(wx.EVT_RIGHT_DOWN, self.click) + self.Bind(wx.EVT_MIDDLE_DOWN, self.click) self.Bind(wx.EVT_SHOW, self.OnShow) self.Bind(wx.EVT_MOTION, self.OnMouseMove) self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow) @@ -162,12 +163,9 @@ class FittingView(d.Display): self.hoveredColumn = col if row != -1 and row not in self.blanks and col != -1 and col < len(self.DEFAULT_COLS): mod = self.mods[self.GetItemData(row)] - if self.DEFAULT_COLS[col] == "Miscellanea": - tooltip = self.activeColumns[col].getToolTip(mod) - if tooltip is not None: - self.SetToolTipString(tooltip) - else: - self.SetToolTip(None) + tooltip = self.activeColumns[col].getToolTip(mod) + if tooltip is not None: + self.SetToolTipString(tooltip) else: self.SetToolTip(None) else: @@ -522,16 +520,21 @@ class FittingView(d.Display): sFit = service.Fit.getInstance() fitID = self.mainFrame.getActiveFit() - ctrl = wx.GetMouseState().CmdDown() + ctrl = wx.GetMouseState().CmdDown() or wx.GetMouseState().MiddleDown() click = "ctrl" if ctrl is True else "right" if event.Button == 3 else "left" sFit.toggleModulesState(fitID, self.mods[self.GetItemData(row)], mods, click) + + # update state tooltip + tooltip = self.activeColumns[col].getToolTip(self.mods[self.GetItemData(row)]) + self.SetToolTipString(tooltip) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.mainFrame.getActiveFit())) else: event.Skip() - slotColourMap = {1: wx.Colour(250, 235, 204), # yellow = low slots - 2: wx.Colour(188,215,241), # blue = mid slots - 3: wx.Colour(235,204,209), # red = high slots + slotColourMap = {1: wx.Colour(250, 235, 204), # yellow = low slots + 2: wx.Colour(188, 215, 241), # blue = mid slots + 3: wx.Colour(235, 204, 209), # red = high slots 4: '', 5: ''} diff --git a/gui/chromeTabs.py b/gui/chromeTabs.py index d9563acb7..15c1141e1 100644 --- a/gui/chromeTabs.py +++ b/gui/chromeTabs.py @@ -25,6 +25,8 @@ import gui.utils.fonts as fonts from gui import bitmapLoader import gui.utils.fonts as fonts +import service + _PageChanging, EVT_NOTEBOOK_PAGE_CHANGING = wx.lib.newevent.NewEvent() _PageChanged, EVT_NOTEBOOK_PAGE_CHANGED = wx.lib.newevent.NewEvent() _PageAdding, EVT_NOTEBOOK_PAGE_ADDING = wx.lib.newevent.NewEvent() @@ -680,6 +682,7 @@ class PFTabsContainer(wx.Panel): self.containerHeight = height self.startDrag = False self.dragging = False + self.sFit = service.Fit.getInstance() self.inclination = 7 if canAdd: @@ -1013,6 +1016,9 @@ class PFTabsContainer(wx.Panel): Checks to see if we have a tab preview and sets up the timer for it to display """ + if not self.sFit.serviceFittingOptions["showTooltip"] or False: + return + if self.previewTimer: if self.previewTimer.IsRunning(): if self.previewWnd: diff --git a/gui/contextMenu.py b/gui/contextMenu.py index 41bbca392..4ed09f9c1 100644 --- a/gui/contextMenu.py +++ b/gui/contextMenu.py @@ -73,18 +73,25 @@ class ContextMenu(object): rootMenu.info[id] = (m, fullContext, it) sub = m.getSubMenu(srcContext, selection, rootMenu, it, rootItem) + if sub is None: # if there is no sub menu, bind the handler to the rootItem rootMenu.Bind(wx.EVT_MENU, cls.handler, rootItem) - else: + elif sub: + # If sub exists and is not False, set submenu. + # Sub might return False when we have a mix of + # single menu items and submenus (see: damage profile + # context menu) + # # If there is a submenu, it is expected that the sub - # logic take care of it's own binding. No binding is - # done here + # logic take care of it's own bindings, including for + # any single root items. No binding is done here # # It is important to remember that when binding sub - # menu items, bind them to the rootMenu for proper - # event handling, eg: - # rootMenu.Bind(wx.EVE_MENU, self.handle, menuItem) + # menu items, the menu to bind to depends on platform. + # Windows should bind to rootMenu, and all other + # platforms should bind to sub menu. See existing + # implementations for examples. rootItem.SetSubMenu(sub) if bitmap is not None: diff --git a/gui/itemStats.py b/gui/itemStats.py index c727c170b..a26406af5 100644 --- a/gui/itemStats.py +++ b/gui/itemStats.py @@ -523,10 +523,24 @@ class ItemEffects (wx.Panel): self.Layout() def OnClick(self, event): + """ + Debug use: open effect file with default application. + If effect file does not exist, create it + """ + import os - file = os.path.join(config.pyfaPath,"eos","effects","%s.py"%event.GetText().lower()) + file = os.path.join(config.pyfaPath, "eos", "effects", "%s.py"%event.GetText().lower()) + + if not os.path.isfile(file): + open(file, 'a').close() + if 'wxMSW' in wx.PlatformInfo: os.startfile(file) + elif 'wxMac' in wx.PlatformInfo: + os.system("open "+file) + else: + import subprocess + subprocess.call(["xdg-open", file]) ########################################################################### diff --git a/gui/mainFrame.py b/gui/mainFrame.py index 2d71da48a..634a22f01 100644 --- a/gui/mainFrame.py +++ b/gui/mainFrame.py @@ -42,7 +42,7 @@ from gui.additionsPane import AdditionsPane from gui.marketBrowser import MarketBrowser from gui.multiSwitch import MultiSwitch from gui.statsPane import StatsPane -from gui.shipBrowser import ShipBrowser, FitSelected +from gui.shipBrowser import ShipBrowser, FitSelected, ImportSelected, Stage3Selected from gui.characterEditor import CharacterEditor from gui.characterSelection import CharacterSelection from gui.patternEditor import DmgPatternEditorDlg @@ -54,6 +54,9 @@ from gui.utils.clipboard import toClipboard, fromClipboard from gui.fleetBrowser import FleetBrowser from gui.updateDialog import UpdateDialog from gui.builtinViews import * + +from time import gmtime, strftime + import locale locale.setlocale(locale.LC_ALL, '') @@ -201,9 +204,18 @@ class MainFrame(wx.Frame): dlg.Destroy() def LoadPreviousOpenFits(self): + sFit = service.Fit.getInstance() + self.prevOpenFits = service.SettingsProvider.getInstance().getSettings("pyfaPrevOpenFits", {"enabled": False, "pyfaOpenFits": []}) fits = self.prevOpenFits['pyfaOpenFits'] + # Remove any fits that cause exception when fetching (non-existent fits) + for id in fits[:]: + try: + sFit.getFit(id) + except: + fits.remove(id) + if not self.prevOpenFits['enabled'] or len(fits) is 0: # add blank page if there are no fits to be loaded self.fitMultiSwitch.AddPage() @@ -327,47 +339,21 @@ class MainFrame(wx.Frame): dlg.ShowModal() dlg.Destroy() - def showImportDialog(self, event): - fits = [] - sFit = service.Fit.getInstance() - dlg=wx.FileDialog( - self, - "Open One Or More Fitting Files", - wildcard = "EFT text fitting files (*.cfg)|*.cfg|" \ - "EVE XML fitting files (*.xml)|*.xml|" \ - "All Files (*)|*", - style = wx.FD_OPEN | wx.FD_FILE_MUST_EXIST | wx.FD_MULTIPLE) - if (dlg.ShowModal() == wx.ID_OK): - self.waitDialog = animUtils.WaitDialog(self, title = "Importing") - sFit.importFitsThreaded(dlg.GetPaths(), self.importCallback) - dlg.Destroy() - self.waitDialog.ShowModal() - - def importCallback(self, fits): - self.waitDialog.Destroy() - sFit = service.Fit.getInstance() - IDs = sFit.saveImportedFits(fits) - self._openAfterImport(len(fits), IDs) - - def _openAfterImport(self, importCount, fitIDs): - if importCount == 1: - wx.PostEvent(self, FitSelected(fitID=fitIDs[0])) - - self.shipBrowser.RefreshContent() - def showExportDialog(self, event): - dlg=wx.FileDialog( - self, - "Save Fitting As...", - wildcard = "EVE XML fitting files (*.xml)|*.xml", - style = wx.FD_SAVE) - if (dlg.ShowModal() == wx.ID_OK): - sFit = service.Fit.getInstance() + """ Export active fit """ + sFit = service.Fit.getInstance() + fit = sFit.getFit(self.getActiveFit()) + defaultFile = "%s - %s.xml"%(fit.ship.item.name, fit.name) if fit else None + + dlg = wx.FileDialog(self, "Save Fitting As...", + wildcard = "EVE XML fitting files (*.xml)|*.xml", + style = wx.FD_SAVE, + defaultFile=defaultFile) + if dlg.ShowModal() == wx.ID_OK: format = dlg.GetFilterIndex() - output = "" path = dlg.GetPath() - if (format == 0): - output = sFit.exportXml(self.getActiveFit()) + if format == 0: + output = sFit.exportXml(None, self.getActiveFit()) if '.' not in os.path.basename(path): path += ".xml" else: @@ -406,7 +392,7 @@ class MainFrame(wx.Frame): # Target Resists editor self.Bind(wx.EVT_MENU, self.showTargetResistsEditor, id=menuBar.targetResistsEditorId) # Import dialog - self.Bind(wx.EVT_MENU, self.showImportDialog, id=wx.ID_OPEN) + self.Bind(wx.EVT_MENU, self.fileImportDialog, id=wx.ID_OPEN) # Export dialog self.Bind(wx.EVT_MENU, self.showExportDialog, id=wx.ID_SAVEAS) # Import from Clipboard @@ -545,17 +531,16 @@ class MainFrame(wx.Frame): def clipboardXml(self): sFit = service.Fit.getInstance() - toClipboard(sFit.exportXml(self.getActiveFit())) + toClipboard(sFit.exportXml(None, self.getActiveFit())) def importFromClipboard(self, event): sFit = service.Fit.getInstance() try: fits = sFit.importFitFromBuffer(fromClipboard(), self.getActiveFit()) - IDs = sFit.saveImportedFits(fits) - self._openAfterImport(len(fits), IDs) except: pass - + else: + self._openAfterImport(fits) def exportToClipboard(self, event): CopySelectDict = {CopySelectDialog.copyFormatEft: self.clipboardEft, @@ -571,44 +556,109 @@ class MainFrame(wx.Frame): pass dlg.Destroy() - def backupToXml(self, event): + def fileImportDialog(self, event): + """Handles importing single/multiple EVE XML / EFT cfg fit files""" sFit = service.Fit.getInstance() - saveDialog = wx.FileDialog( - self, - "Save Backup As...", - wildcard = "EVE XML fitting file (*.xml)|*.xml", - style = wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT) - if (saveDialog.ShowModal() == wx.ID_OK): + dlg = wx.FileDialog(self, "Open One Or More Fitting Files", + wildcard = "EVE XML fitting files (*.xml)|*.xml|" \ + "EFT text fitting files (*.cfg)|*.cfg|" \ + "All Files (*)|*", + style = wx.FD_OPEN | wx.FD_FILE_MUST_EXIST | wx.FD_MULTIPLE) + if (dlg.ShowModal() == wx.ID_OK): + self.progressDialog = wx.ProgressDialog( + "Importing fits", + " "*100, # set some arbitrary spacing to create wifth in window + parent=self, style = wx.PD_APP_MODAL | wx.PD_ELAPSED_TIME) + self.progressDialog.message = None + sFit.importFitsThreaded(dlg.GetPaths(), self.fileImportCallback) + self.progressDialog.ShowModal() + dlg.Destroy() + + def fileImportCallback(self, info, fits=None): + """ + While importing fits from file, the logic calls back to this function to + update progress bar to show activity. XML files can contain multiple + ships with multiple fits, whereas EFT cfg files contain many fits of + a single ship. When iterating through the files, we update the message + when we start a new file, and then Pulse the progress bar with every fit + that is processed. + """ + + if info == -1: + # Done processing + self.progressDialog.Hide() + self._openAfterImport(fits) + elif info != self.progressDialog.message and info is not None: + # New message, overwrite cached message and update + self.progressDialog.message = info + self.progressDialog.Pulse(info) + else: + # Simply Pulse() if we don't have anything else to do + self.progressDialog.Pulse() + + def _openAfterImport(self, fits): + if len(fits) > 0: + if len(fits) == 1: + fit = fits[0] + wx.PostEvent(self, FitSelected(fitID=fit.ID)) + wx.PostEvent(self.shipBrowser, Stage3Selected(shipID=fit.shipID, back=True)) + else: + wx.PostEvent(self.shipBrowser, ImportSelected(fits=fits, back=True)) + + def backupToXml(self, event): + """ Back up all fits to EVE XML file """ + defaultFile = "pyfa-fits-%s.xml"%strftime("%Y%m%d_%H%M%S", gmtime()) + + saveDialog = wx.FileDialog(self, "Save Backup As...", + wildcard = "EVE XML fitting file (*.xml)|*.xml", + style = wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT, + defaultFile=defaultFile) + + if saveDialog.ShowModal() == wx.ID_OK: filePath = saveDialog.GetPath() if '.' not in os.path.basename(filePath): filePath += ".xml" - self.waitDialog = animUtils.WaitDialog(self) - sFit.backupFits(filePath, self.closeWaitDialog) - self.waitDialog.ShowModal() - saveDialog.Destroy() + sFit = service.Fit.getInstance() + max = sFit.countAllFits() + + self.progressDialog = wx.ProgressDialog("Backup fits", + "Backing up %d fits to: %s"%(max, filePath), + maximum=max, parent=self, + style=wx.PD_APP_MODAL | wx.PD_ELAPSED_TIME) + + sFit.backupFits(filePath, self.backupCallback) + self.progressDialog.ShowModal() + + def backupCallback(self, info): + if info == -1: + self.progressDialog.Hide() + else: + self.progressDialog.Update(info) def exportSkillsNeeded(self, event): + """ Exports skills needed for active fit and active character """ sCharacter = service.Character.getInstance() - saveDialog = wx.FileDialog( - self, - "Export Skills Needed As...", - wildcard = "EVEMon skills training file (*.emp)|*.emp|" \ - "EVEMon skills training XML file (*.xml)|*.xml|" \ - "Text skills training file (*.txt)|*.txt", - style = wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT) - if (saveDialog.ShowModal() == wx.ID_OK): + saveDialog = wx.FileDialog(self, "Export Skills Needed As...", + wildcard = "EVEMon skills training file (*.emp)|*.emp|" \ + "EVEMon skills training XML file (*.xml)|*.xml|" \ + "Text skills training file (*.txt)|*.txt", + style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT) + + if saveDialog.ShowModal() == wx.ID_OK: saveFmtInt = saveDialog.GetFilterIndex() - saveFmt = "" + if saveFmtInt == 0: # Per ordering of wildcards above saveFmt = "emp" elif saveFmtInt == 1: saveFmt = "xml" else: saveFmt = "txt" + filePath = saveDialog.GetPath() if '.' not in os.path.basename(filePath): filePath += ".{0}".format(saveFmt) + self.waitDialog = animUtils.WaitDialog(self) sCharacter.backupSkills(filePath, saveFmt, self.getActiveFit(), self.closeWaitDialog) self.waitDialog.ShowModal() @@ -616,29 +666,38 @@ class MainFrame(wx.Frame): saveDialog.Destroy() def importCharacter(self, event): - sCharacter = service.Character.getInstance() - dlg=wx.FileDialog( - self, - "Open One Or More Character Files", - wildcard = "EVE CCP API XML character files (*.xml)|*.xml|" \ - "All Files (*)|*", - style = wx.FD_OPEN | wx.FD_FILE_MUST_EXIST | wx.FD_MULTIPLE) - if (dlg.ShowModal() == wx.ID_OK): - self.waitDialog = animUtils.WaitDialog(self, title = "Importing Character") + """ Imports character XML file from EVE API """ + dlg = wx.FileDialog(self, "Open One Or More Character Files", + wildcard="EVE API XML character files (*.xml)|*.xml|" \ + "All Files (*)|*", + style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST | wx.FD_MULTIPLE) + + if dlg.ShowModal() == wx.ID_OK: + self.waitDialog = animUtils.WaitDialog(self, title="Importing Character") + sCharacter = service.Character.getInstance() sCharacter.importCharacter(dlg.GetPaths(), self.importCharacterCallback) dlg.Destroy() self.waitDialog.ShowModal() - def exportHtml(self, event): - from gui.utils.exportHtml import exportHtml - self.waitDialog = animUtils.WaitDialog(self) - exportHtml.getInstance().refreshFittingHtml(True, self.closeWaitDialog) - self.waitDialog.ShowModal() - def importCharacterCallback(self): self.waitDialog.Destroy() wx.PostEvent(self, GE.CharListUpdated()) + def exportHtml(self, event): + from gui.utils.exportHtml import exportHtml + sFit = service.Fit.getInstance() + settings = service.settings.HTMLExportSettings.getInstance() + + max = sFit.countAllFits() + path = settings.getPath() + self.progressDialog = wx.ProgressDialog("Backup fits", + "Generating HTML file at: %s"%path, + maximum=max, parent=self, + style=wx.PD_APP_MODAL | wx.PD_ELAPSED_TIME) + + exportHtml.getInstance().refreshFittingHtml(True, self.backupCallback) + self.progressDialog.ShowModal() + def closeWaitDialog(self): self.waitDialog.Destroy() @@ -650,7 +709,7 @@ class MainFrame(wx.Frame): else: self.graphFrame.SetFocus() - def openWXInspectTool(self,event): + def openWXInspectTool(self, event): from wx.lib.inspection import InspectionTool if not InspectionTool().initialized: InspectionTool().Init() diff --git a/gui/patternEditor.py b/gui/patternEditor.py index f3b8da855..8bcdde295 100644 --- a/gui/patternEditor.py +++ b/gui/patternEditor.py @@ -28,11 +28,11 @@ from service.damagePattern import ImportError ## Class DmgPatternEditorDlg ########################################################################### -class DmgPatternEditorDlg (wx.Dialog): +class DmgPatternEditorDlg(wx.Dialog): DAMAGE_TYPES = ("em", "thermal", "kinetic", "explosive") def __init__(self, parent): - wx.Dialog.__init__ (self, parent, id = wx.ID_ANY, title = u"Damage Pattern Editor", size = wx.Size( 400,240 )) + wx.Dialog.__init__(self, parent, id = wx.ID_ANY, title = u"Damage Pattern Editor", size = wx.Size( 400,240 )) self.block = False self.SetSizeHintsSz(wx.DefaultSize, wx.DefaultSize) @@ -125,7 +125,7 @@ class DmgPatternEditorDlg (wx.Dialog): editObj.Bind(wx.EVT_TEXT, self.ValuesUpdated) editObj.SetLimited(True) editObj.SetMin(0) - editObj.SetMax(99999) + editObj.SetMax(2000000) contentSizer.Add(dmgeditSizer, 1, wx.EXPAND | wx.ALL, 5) self.slfooter = wx.StaticLine(self) @@ -244,23 +244,22 @@ class DmgPatternEditorDlg (wx.Dialog): self.block = False self.ValuesUpdated() - def newPattern(self,event): - sDP = service.DamagePattern.getInstance() - p = sDP.newPattern() - self.choices.append(p) - id = self.ccDmgPattern.Append(p.name) - self.ccDmgPattern.SetSelection(id) - + def newPattern(self, event): self.restrict() + + self.block = True # reset values for type in self.DAMAGE_TYPES: editObj = getattr(self, "%sEdit"%type) editObj.SetValue(0) + self.block = False + self.btnSave.SetLabel("Create") + self.Refresh() self.renamePattern() - def renamePattern(self,event=None): + def renamePattern(self, event=None): if event is not None: self.btnSave.SetLabel("Rename") @@ -268,7 +267,12 @@ class DmgPatternEditorDlg (wx.Dialog): self.namePicker.Show() self.headerSizer.Replace(self.ccDmgPattern, self.namePicker) self.namePicker.SetFocus() - self.namePicker.SetValue(self.getActivePattern().name) + + if event is not None: # Rename mode + self.btnSave.SetLabel("Rename") + self.namePicker.SetValue(self.getActivePattern().name) + else: # Create mode + self.namePicker.SetValue("") for btn in (self.new, self.rename, self.delete, self.copy): btn.Hide() @@ -284,19 +288,25 @@ class DmgPatternEditorDlg (wx.Dialog): newName = self.namePicker.GetLineText(0) self.stNotice.SetLabel("") - p = self.getActivePattern() - for pattern in self.choices: - if pattern.name == newName and p != pattern: - self.stNotice.SetLabel("Name already used, please choose another") - return - if newName == "": self.stNotice.SetLabel("Invalid name.") return sDP = service.DamagePattern.getInstance() + if self.btnSave.Label == "Create": + p = sDP.newPattern() + else: + # we are renaming, so get the current selection + p = self.getActivePattern() + + for pattern in self.choices: + if pattern.name == newName and p != pattern: + self.stNotice.SetLabel("Name already used, please choose another") + return + sDP.renamePattern(p, newName) + self.updateChoices(newName) self.headerSizer.Replace(self.namePicker, self.ccDmgPattern) self.ccDmgPattern.Show() self.namePicker.Hide() @@ -335,7 +345,7 @@ class DmgPatternEditorDlg (wx.Dialog): def __del__( self ): pass - def updateChoices(self): + def updateChoices(self, select=None): "Gathers list of patterns and updates choice selections" sDP = service.DamagePattern.getInstance() self.choices = sDP.getDamagePatternList() @@ -348,10 +358,14 @@ class DmgPatternEditorDlg (wx.Dialog): self.choices.sort(key=lambda p: p.name) self.ccDmgPattern.Clear() - for choice in map(lambda p: p.name, self.choices): + for i, choice in enumerate(map(lambda p: p.name, self.choices)): self.ccDmgPattern.Append(choice) - self.ccDmgPattern.SetSelection(0) + if select is not None and choice == select: + self.ccDmgPattern.SetSelection(i) + + if select is None: + self.ccDmgPattern.SetSelection(0) self.patternChanged() def importPatterns(self, event): diff --git a/gui/resistsEditor.py b/gui/resistsEditor.py index a5764a74a..0d26be5da 100644 --- a/gui/resistsEditor.py +++ b/gui/resistsEditor.py @@ -23,12 +23,12 @@ import service from gui.utils.clipboard import toClipboard, fromClipboard from service.targetResists import ImportError -class ResistsEditorDlg (wx.Dialog): +class ResistsEditorDlg(wx.Dialog): DAMAGE_TYPES = ("em", "thermal", "kinetic", "explosive") def __init__(self, parent): - wx.Dialog.__init__ (self, parent, id = wx.ID_ANY, title = u"Target Resists Editor", size = wx.Size( 350,240 )) + wx.Dialog.__init__(self, parent, id = wx.ID_ANY, title = u"Target Resists Editor", size = wx.Size( 350,240 )) self.block = False self.SetSizeHintsSz(wx.DefaultSize, wx.DefaultSize) @@ -301,7 +301,7 @@ class ResistsEditorDlg (wx.Dialog): return sTR = service.TargetResists.getInstance() - if event.EventObject.Label == "Create": + if self.btnSave.Label == "Create": p = sTR.newPattern() else: # we are renaming, so get the current selection diff --git a/gui/sfBrowserItem.py b/gui/sfBrowserItem.py index 0a2da9090..4067707c3 100644 --- a/gui/sfBrowserItem.py +++ b/gui/sfBrowserItem.py @@ -413,4 +413,4 @@ class SFBrowserItem(wx.Window): self.bkBitmap.state = state self.bkBitmap.sFactor = sFactor self.bkBitmap.eFactor = eFactor - self.bkBitmap.mFactor = mFactor \ No newline at end of file + self.bkBitmap.mFactor = mFactor diff --git a/gui/shipBrowser.py b/gui/shipBrowser.py index 659c2fe23..7e916181c 100644 --- a/gui/shipBrowser.py +++ b/gui/shipBrowser.py @@ -30,6 +30,7 @@ Stage1Selected, EVT_SB_STAGE1_SEL = wx.lib.newevent.NewEvent() Stage2Selected, EVT_SB_STAGE2_SEL = wx.lib.newevent.NewEvent() Stage3Selected, EVT_SB_STAGE3_SEL = wx.lib.newevent.NewEvent() SearchSelected, EVT_SB_SEARCH_SEL = wx.lib.newevent.NewEvent() +ImportSelected, EVT_SB_IMPORT_SEL = wx.lib.newevent.NewEvent() class PFWidgetsContainer(PFListPane): def __init__(self,parent): @@ -324,7 +325,7 @@ class RaceSelector(wx.Window): event.Skip() class NavigationPanel(SFItem.SFBrowserItem): - def __init__(self,parent, size = (-1,24)): + def __init__(self,parent, size = (-1, 24)): SFItem.SFBrowserItem.__init__(self,parent,size = size) self.rewBmpH = bitmapLoader.getBitmap("frewind_small","icons") @@ -352,7 +353,7 @@ class NavigationPanel(SFItem.SFBrowserItem): self.padding = 4 self.lastSearch = "" - self.recentSearches = [] + self.recentSearches = [] # not used? self.inSearch = False self.fontSmall = wx.Font(fonts.SMALL, wx.SWISS, wx.NORMAL, wx.NORMAL) @@ -371,23 +372,14 @@ class NavigationPanel(SFItem.SFBrowserItem): self.Bind(wx.EVT_SIZE, self.OnResize) - def OnScheduleSearch(self, event): search = self.BrowserSearchBox.GetValue() # Make sure we do not count wildcard as search symbol realsearch = search.replace("*", "") - if len(realsearch) < 3 and len(realsearch) >= 0: - if self.inSearch == True: - self.inSearch = False - if len(self.shipBrowser.browseHist) > 0: - stage,data = self.shipBrowser.browseHist.pop() - self.gotoStage(stage,data) - else: - if search: - wx.PostEvent(self.shipBrowser,SearchSelected(text=search, back = False)) - self.inSearch = True - else: - self.inSearch = False + if len(realsearch) >= 3: + self.lastSearch = search + wx.PostEvent(self.shipBrowser,SearchSelected(text=search, back = False)) + def ToggleSearchBox(self): if self.BrowserSearchBox.IsShown(): @@ -401,8 +393,6 @@ class NavigationPanel(SFItem.SFBrowserItem): self.OnBrowserSearchBoxLostFocus(None) def OnBrowserSearchBoxLostFocus(self, event): - self.lastSearch = self.BrowserSearchBox.GetValue() - self.BrowserSearchBox.ChangeValue("") self.BrowserSearchBox.Show(False) def OnBrowserSearchBoxEsc(self, event): @@ -411,7 +401,6 @@ class NavigationPanel(SFItem.SFBrowserItem): else: event.Skip() - def OnResize(self, event): self.Refresh() @@ -449,7 +438,7 @@ class NavigationPanel(SFItem.SFBrowserItem): sFit = service.Fit.getInstance() fitID = sFit.newFit(shipID, "%s fit" %shipName) self.shipBrowser.fitIDMustEditName = fitID - wx.PostEvent(self.Parent,Stage3Selected(shipID=shipID, back = True)) + wx.PostEvent(self.Parent,Stage3Selected(shipID=shipID)) wx.PostEvent(self.mainFrame, FitSelected(fitID=fitID)) def OnHistoryReset(self): @@ -460,11 +449,11 @@ class NavigationPanel(SFItem.SFBrowserItem): def OnHistoryBack(self): if len(self.shipBrowser.browseHist) > 0: stage,data = self.shipBrowser.browseHist.pop() - self.gotoStage(stage,data) + self.gotoStage(stage, data) def AdjustChannels(self, bitmap): img = wx.ImageFromBitmap(bitmap) - img = img.AdjustChannels(1.05,1.05,1.05,1) + img = img.AdjustChannels(1.05, 1.05, 1.05, 1) return wx.BitmapFromImage(img) def UpdateElementsPos(self, mdc): @@ -536,20 +525,20 @@ class NavigationPanel(SFItem.SFBrowserItem): self.bkBitmap.mFactor = mFactor - def gotoStage(self,stage, data = None): + def gotoStage(self, stage, data=None): if stage == 1: - wx.PostEvent(self.Parent,Stage1Selected()) + wx.PostEvent(self.Parent, Stage1Selected()) elif stage == 2: - wx.PostEvent(self.Parent,Stage2Selected(categoryID=data, back = True)) + wx.PostEvent(self.Parent, Stage2Selected(categoryID=data, back=True)) elif stage == 3: - wx.PostEvent(self.Parent,Stage3Selected(shipID=data, back = 1)) + wx.PostEvent(self.Parent, Stage3Selected(shipID=data)) elif stage == 4: self.shipBrowser._activeStage = 4 - self.stStatus.SetLabel("Search: %s" % data.capitalize()) - self.Layout() - wx.PostEvent(self.Parent,SearchSelected(text=data, back = True)) + wx.PostEvent(self.Parent, SearchSelected(text=data, back=True)) + elif stage == 5: + wx.PostEvent(self.Parent, ImportSelected(fits=data)) else: - wx.PostEvent(self.Parent,Stage1Selected()) + wx.PostEvent(self.Parent, Stage1Selected()) class ShipBrowser(wx.Panel): @@ -610,6 +599,7 @@ class ShipBrowser(wx.Panel): self.Bind(EVT_SB_STAGE1_SEL, self.stage1) self.Bind(EVT_SB_STAGE3_SEL, self.stage3) self.Bind(EVT_SB_SEARCH_SEL, self.searchStage) + self.Bind(EVT_SB_IMPORT_SEL, self.importStage) self.mainFrame.Bind(GE.FIT_CHANGED, self.RefreshList) @@ -654,6 +644,8 @@ class ShipBrowser(wx.Panel): return self._stage2Data if stage == 3: return self._stage3Data + if stage == 4: + return self.navpanel.lastSearch return -1 def GetStage3ShipName(self): @@ -809,13 +801,15 @@ class ShipBrowser(wx.Panel): self.lpane.ShowLoading(False) - if event.back == 0: - self.browseHist.append( (2,self._stage2Data) ) - elif event.back == -1: - if len(self.navpanel.recentSearches)>0: + # If back is False, do not append to history. This could be us calling + # the stage from previous history, creating / copying fit, etc. + # We also have to use conditional for search stage since it's last data + # is kept elsewhere + if getattr(event, "back", False): + if self._activeStage == 4 and self.navpanel.lastSearch != "": self.browseHist.append((4, self.navpanel.lastSearch)) - elif event.back > 0: - self.browseHist.append( (2,event.back) ) + else: + self.browseHist.append((self._activeStage, self.lastdata)) shipID = event.shipID self.lastdata = shipID @@ -868,11 +862,11 @@ class ShipBrowser(wx.Panel): self.navpanel.ShowSwitchEmptyGroupsButton(False) if not event.back: - if self._activeStage !=4: - if len(self.browseHist) >0: - self.browseHist.append( (self._activeStage, self.lastdata) ) + if self._activeStage != 4: + if len(self.browseHist) > 0: + self.browseHist.append((self._activeStage, self.lastdata)) else: - self.browseHist.append((1,0)) + self.browseHist.append((1, 0)) self._lastStage = self._activeStage self._activeStage = 4 @@ -903,6 +897,46 @@ class ShipBrowser(wx.Panel): self.raceselect.Show(False) self.Layout() + def importStage(self, event): + self.lpane.ShowLoading(False) + + self.navpanel.ShowNewFitButton(False) + self.navpanel.ShowSwitchEmptyGroupsButton(False) + + if getattr(event, "back", False): + self.browseHist.append((self._activeStage, self.lastdata)) + + self._lastStage = self._activeStage + self._activeStage = 5 + + fits = event.fits + + # sort by ship name, then fit name + fits.sort(key=lambda fit: (fit.ship.item.name, fit.name)) + + self.lastdata = fits + self.lpane.Freeze() + self.lpane.RemoveAllChildren() + + if fits: + for fit in fits: + self.lpane.AddWidget(FitItem( + self.lpane, + fit.ID, ( + fit.ship.item.name, + fit.name, + fit.booster, + fit.timestamp), + fit.ship.item.ID)) + self.lpane.RefreshList(doFocus=False) + self.lpane.Thaw() + + self.raceselect.RebuildRaces(self.RACE_ORDER) + + if self.showRacesFilterInStage2Only: + self.raceselect.Show(False) + self.Layout() + class PFStaticText(wx.Panel): def __init__(self, parent, label=wx.EmptyString): wx.Panel.__init__ (self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size = parent.GetSize()) @@ -1165,7 +1199,7 @@ class ShipItem(SFItem.SFBrowserItem): else: shipName, fittings = self.shipFittingInfo if fittings > 0: - wx.PostEvent(self.shipBrowser,Stage3Selected(shipID=self.shipID, back = -1 if self.shipBrowser.GetActiveStage() == 4 else 0)) + wx.PostEvent(self.shipBrowser, Stage3Selected(shipID=self.shipID, back=True)) else: self.newBtnCB() @@ -1577,7 +1611,7 @@ class FitItem(SFItem.SFBrowserItem): sFit = service.Fit.getInstance() fitID = sFit.copyFit(self.fitID) self.shipBrowser.fitIDMustEditName = fitID - wx.PostEvent(self.shipBrowser,Stage3Selected(shipID=self.shipID, back=True)) + wx.PostEvent(self.shipBrowser,Stage3Selected(shipID=self.shipID)) wx.PostEvent(self.mainFrame, FitSelected(fitID=fitID)) def renameBtnCB(self): @@ -1620,18 +1654,22 @@ class FitItem(SFItem.SFBrowserItem): self.deleted = True sFit = service.Fit.getInstance() + fit = sFit.getFit(self.fitID) sFit.deleteFit(self.fitID) - if self.shipBrowser.GetActiveStage() == 4: - wx.PostEvent(self.shipBrowser,SearchSelected(text=self.shipBrowser.navpanel.lastSearch,back=True)) + if self.shipBrowser.GetActiveStage() == 5: + if fit in self.shipBrowser.lastdata: # remove fit from import cache + self.shipBrowser.lastdata.remove(fit) + wx.PostEvent(self.shipBrowser, ImportSelected(fits=self.shipBrowser.lastdata)) + elif self.shipBrowser.GetActiveStage() == 4: + wx.PostEvent(self.shipBrowser, SearchSelected(text=self.shipBrowser.navpanel.lastSearch, back=True)) else: - wx.PostEvent(self.shipBrowser,Stage3Selected(shipID=self.shipID, back=True)) + wx.PostEvent(self.shipBrowser, Stage3Selected(shipID=self.shipID)) wx.PostEvent(self.mainFrame, FitRemoved(fitID=self.fitID)) def MouseLeftUp(self, event): - if self.dragging and self.dragged: self.dragging = False self.dragged = False diff --git a/gui/utils/exportHtml.py b/gui/utils/exportHtml.py index c61c2444a..726bec265 100644 --- a/gui/utils/exportHtml.py +++ b/gui/utils/exportHtml.py @@ -7,7 +7,7 @@ class exportHtml(): _instance = None @classmethod def getInstance(cls): - if cls._instance == None: + if cls._instance is None: cls._instance = exportHtml() return cls._instance @@ -15,17 +15,17 @@ class exportHtml(): def __init__(self): self.thread = exportHtmlThread() - def refreshFittingHtml(self, force = False, callback = False): + def refreshFittingHtml(self, force=False, callback=False): settings = service.settings.HTMLExportSettings.getInstance() - if (force or settings.getEnabled()): + if force or settings.getEnabled(): self.thread.stop() self.thread = exportHtmlThread(callback) self.thread.start() class exportHtmlThread(threading.Thread): - def __init__(self, callback = False): + def __init__(self, callback=False): threading.Thread.__init__(self) self.callback = callback self.stopRunning = False @@ -40,7 +40,7 @@ class exportHtmlThread(threading.Thread): return sMkt = service.Market.getInstance() - sFit = service.Fit.getInstance() + sFit = service.Fit.getInstance() settings = service.settings.HTMLExportSettings.getInstance() timestamp = time.localtime(time.time()) @@ -135,6 +135,9 @@ class exportHtmlThread(threading.Thread): HTML += ' \n' ' \n') + if groupFits > 0: # Market group header HTML += ( @@ -197,5 +214,5 @@ class exportHtmlThread(threading.Thread): pass if self.callback: - wx.CallAfter(self.callback) + wx.CallAfter(self.callback, -1) diff --git a/gui/viewColumn.py b/gui/viewColumn.py index 948d09074..c2ffff612 100644 --- a/gui/viewColumn.py +++ b/gui/viewColumn.py @@ -50,7 +50,7 @@ class ViewColumn(object): return "" def getToolTip(self, mod): - return "" + return None def getImageId(self, mod): return -1 diff --git a/icons/capacitorRecharge_small.png b/icons/capacitorRecharge_small.png new file mode 100644 index 000000000..d1c662dd8 Binary files /dev/null and b/icons/capacitorRecharge_small.png differ diff --git a/scripts/conversion.py b/scripts/conversion.py new file mode 100644 index 000000000..5120791d4 --- /dev/null +++ b/scripts/conversion.py @@ -0,0 +1,65 @@ +# Developed for module tiericide, this script will quickly print out a market +# conversion map based on database conversions / renamed modules between two +# eve databases. Correct database conversions must be implemented in upgrade +# script in eos.db.migrations + +import argparse +import os.path +import sqlite3 +import sys + +# Add eos root path to sys.path so we can import ourselves +path = os.path.dirname(unicode(__file__, sys.getfilesystemencoding())) +sys.path.append(os.path.realpath(os.path.join(path, ".."))) + +# change to correct conversion +from eos.db.migrations.upgrade4 import CONVERSIONS + +def main(old, new): + # Open both databases and get their cursors + old_db = sqlite3.connect(os.path.expanduser(old)) + old_cursor = old_db.cursor() + new_db = sqlite3.connect(os.path.expanduser(new)) + new_cursor = new_db.cursor() + + print "# Renamed items" + + # find renames (stolen from itemDiff) + old_namedata = {} + new_namedata = {} + + for cursor, dictionary in ((old_cursor, old_namedata), (new_cursor, new_namedata)): + cursor.execute("SELECT typeID, typeName FROM invtypes") + for row in cursor: + id = row[0] + name = row[1] + dictionary[id] = name + + for id in set(old_namedata.keys()).intersection(new_namedata.keys()): + oldname = old_namedata[id] + newname = new_namedata[id] + if oldname != newname: + print '"%s": "%s",' % (oldname.encode('utf-8'), newname.encode('utf-8')) + + # Convert modules + print "\n# Converted items" + for replacement_item, list in CONVERSIONS.iteritems(): + new_cursor.execute('SELECT "typeName" FROM "invtypes" WHERE "typeID" = ?', (replacement_item,)) + for row in new_cursor: + new_item = row[0] + break + + for retired_item in list: + old_cursor.execute('SELECT "typeName" FROM "invtypes" WHERE "typeID" = ?', (retired_item,)) + for row in old_cursor: + old_item = row[0] + break + print '"%s": "%s",' % (old_item, new_item) + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("-o", "--old", type=str) + parser.add_argument("-n", "--new", type=str) + args = parser.parse_args() + + main(args.old, args.new) diff --git a/scripts/effectUsedBy.py b/scripts/effectUsedBy.py index 7f186b634..b9ee818b9 100755 --- a/scripts/effectUsedBy.py +++ b/scripts/effectUsedBy.py @@ -92,6 +92,7 @@ TYPENAMECOMBS_WEIGHT = 1.0 # If score drops below this value, remaining items will be listed # without any grouping LOWEST_SCORE = 0.7 + # Adjust scoring formulae def calc_innerscore(affected_decribed, affected_undescribed, total, pereffect_totalaffected, weight=1.0): @@ -109,6 +110,7 @@ def calc_innerscore(affected_decribed, affected_undescribed, total, innerscore = (coverage_total ** 0.23) * coverage_additionalfactor * \ affected_total_factor * weight return innerscore + def calc_outerscore(innerscore_dict, pereffect_totalaffected, weight): """Outer score calculation formula""" # Return just max of the inner scores, including weight factor @@ -118,18 +120,27 @@ def calc_outerscore(innerscore_dict, pereffect_totalaffected, weight): return outerscore else: return 0.0 +def validate_string(s): + try: + s.encode('ascii') + except KeyboardInterrupt: + raise + except Exception: + return False + else: + return True + # Connect to database and set up cursor db = sqlite3.connect(os.path.expanduser(options.database)) cursor = db.cursor() # Force some of the items to make them published -FORCEPUB_TYPES = ("Ibis", "Impairor", "Velator", "Reaper", - "Amarr Tactical Destroyer Propulsion Mode", - "Amarr Tactical Destroyer Sharpshooter Mode", - "Amarr Tactical Destroyer Defense Mode") +FORCEPUB_TYPES = ("Ibis", "Impairor", "Velator", "Reaper") OVERRIDES_TYPEPUB = 'UPDATE invtypes SET published = 1 WHERE typeName = ?' for typename in FORCEPUB_TYPES: cursor.execute(OVERRIDES_TYPEPUB, (typename,)) +# Publish t3 Dessy Modes +cursor.execute("UPDATE invtypes SET published = 1 WHERE groupID = ?", (1306,)) # Queries to get raw data QUERY_ALLEFFECTS = 'SELECT effectID, effectName FROM dgmeffects' @@ -968,8 +979,9 @@ inner score: {5:.3})" # Append line for printing to list catname = type[2] typename = type[1] - printstr = "# {0}: {1}" - printing_typelines.append(printstr.format(catname, typename)) + printstr = "# {0}: {1}".format(catname, typename) + if validate_string(printstr): + printing_typelines.append(printstr) # Do the same for groups printing_grouplines = [] printing_groups = sorted(printing_groups, key=lambda tuple: tuple[1]) @@ -979,9 +991,9 @@ inner score: {5:.3})" groupname = group[1] described = len(effectmap_groupid_typeid[group[0]][0]) total = len(globalmap_groupid_typeid[group[0]]) - printstr = "# {0}s from group: {1} ({2} of {3})" - printing_grouplines.append(printstr.format(catname, groupname, - described, total)) + printstr = "# {0}s from group: {1} ({2} of {3})".format(catname, groupname, described, total) + if validate_string(printstr): + printing_grouplines.append(printstr) # Process categories printing_categorylines = [] printing_categories = sorted(printing_categories, @@ -990,9 +1002,9 @@ inner score: {5:.3})" catname = category[1] described = len(effectmap_categoryid_typeid[category[0]][0]) total = len(globalmap_categoryid_typeid[category[0]]) - printstr = "# Items from category: {0} ({1} of {2})" - printing_categorylines.append(printstr.format(catname, described, - total)) + printstr = "# Items from category: {0} ({1} of {2})".format(catname, described, total) + if validate_string(printstr): + printing_categorylines.append(printstr) # Process variations printing_basetypelines = [] printing_basetypes = sorted(printing_basetypes, @@ -1004,9 +1016,9 @@ inner score: {5:.3})" basename = basetype[1] described = len(effectmap_basetypeid_typeid[basetype[0]][0]) total = len(globalmap_basetypeid_typeid[basetype[0]]) - printstr = "# Variations of {0}: {1} ({2} of {3})" - printing_basetypelines.append(printstr.format(catname, basename, - described, total)) + printstr = "# Variations of {0}: {1} ({2} of {3})".format(catname, basename, described, total) + if validate_string(printstr): + printing_basetypelines.append(printstr) # Process market groups with variations printing_marketgroupwithvarslines = [] printing_marketgroupswithvars = sorted(printing_marketgroupswithvars, @@ -1017,9 +1029,9 @@ inner score: {5:.3})" [marketgroup[0]][0]) total = len(globalmap_marketgroupid_typeidwithvariations [marketgroup[0]]) - printstr = "# Items from market group: {0} ({1} of {2})" - printing_marketgroupwithvarslines.append(printstr. - format(marketgroupname, described, total)) + printstr = "# Items from market group: {0} ({1} of {2})".format(marketgroupname, described, total) + if validate_string(printstr): + printing_marketgroupwithvarslines.append(printstr) # Process type name combinations printing_typenamecombtuplelines = [] printing_typenamecombtuples = sorted(printing_typenamecombtuples, @@ -1032,9 +1044,9 @@ inner score: {5:.3})" described = len(effectmap_typenamecombtuple_typeid [typenamecomb[0]][0]) total = len(globalmap_typenamecombtuple_typeid[typenamecomb[0]]) - printstr = "# {0}s named like: {1} ({2} of {3})" - printing_typenamecombtuplelines.append(printstr.format(catname, - namedlike, described, total)) + printstr = "# {0}s named like: {1} ({2} of {3})".format(catname, namedlike, described, total) + if validate_string(printstr): + printing_typenamecombtuplelines.append(printstr) # Compose single list of lines using custom sorting commentlines = printing_categorylines + printing_grouplines + \ diff --git a/scripts/prep_data.py b/scripts/prep_data.py index df98489d9..900c9a9c4 100644 --- a/scripts/prep_data.py +++ b/scripts/prep_data.py @@ -11,6 +11,7 @@ import argparse parser = argparse.ArgumentParser() parser.add_argument("-e", "--eve", dest="eve_path", help="Location of EVE directory", required=True) parser.add_argument("-c", "--cache", dest="cache_path", help="Location of EVE cache directory. If not specified, an attempt will be make to automatically determine path.") +parser.add_argument("-r", "--res", dest="res_path", help="Location of EVE shared resource cache", required=True) parser.add_argument("-d", "--dump", dest="dump_path", help="Location of Phobos JSON dump directory", required=True) parser.add_argument("-p", "--phobos", dest="phb_path", help="Location of Phobos, defaults to path noted in script", default=phb_path) parser.add_argument("-s", "--singularity", action="store_true", help="Singularity build") @@ -19,6 +20,7 @@ parser.add_argument("-j", "--nojson", dest="nojson", action="store_true", help=" args = parser.parse_args() eve_path = os.path.expanduser(unicode(args.eve_path, sys.getfilesystemencoding())) cache_path = os.path.expanduser(unicode(args.cache_path, sys.getfilesystemencoding())) if args.cache_path else None +path_res = os.path.expanduser(unicode(args.res_path, sys.getfilesystemencoding())) dump_path = os.path.expanduser(unicode(args.dump_path, sys.getfilesystemencoding())) script_path = os.path.dirname(unicode(__file__, sys.getfilesystemencoding())) @@ -44,10 +46,10 @@ if not args.nojson: from translator import Translator from writer import * - rvr = reverence.blue.EVE(eve_path, cachepath=args.cache_path, server="singularity" if args.singularity else "tranquility") + rvr = reverence.blue.EVE(eve_path, cachepath=args.cache_path, respath=path_res, server="singularity" if args.singularity else "tranquility") - spickle_miner = StuffedPickleMiner(rvr) - trans = Translator(spickle_miner) + pickle_miner = ResourcePickleMiner(rvr) + trans = Translator(pickle_miner) bulkdata_miner = BulkdataMiner(rvr, trans) miners = ( @@ -56,7 +58,7 @@ if not args.nojson: TraitMiner(bulkdata_miner, trans), SqliteMiner(eve_path, trans), CachedCallsMiner(rvr, trans), - spickle_miner + pickle_miner ) writers = ( diff --git a/scripts/pyfa-setup.iss b/scripts/pyfa-setup.iss index 96a719355..588add45a 100644 --- a/scripts/pyfa-setup.iss +++ b/scripts/pyfa-setup.iss @@ -73,6 +73,10 @@ Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\{#MyAppName}"; Fil [Run] Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent +[InstallDelete] +Type: files; Name: "{app}\sqlalchemy.cprocessors.pyd" +Type: files; Name: "{app}\sqlalchemy.cresultproxy.pyd" + [Code] function IsAppRunning(const FileName : string): Boolean; diff --git a/service/character.py b/service/character.py index e78ec990d..af4b43106 100644 --- a/service/character.py +++ b/service/character.py @@ -44,12 +44,14 @@ class CharacterImportThread(threading.Thread): paths = self.paths sCharacter = Character.getInstance() for path in paths: - with open(path, mode='r') as charFile: - sheet = service.ParseXML(charFile) - charID = sCharacter.new() - sCharacter.rename(charID, sheet.name+" (imported)") - sCharacter.apiUpdateCharSheet(charID, sheet) - + try: + with open(path, mode='r') as charFile: + sheet = service.ParseXML(charFile) + charID = sCharacter.new() + sCharacter.rename(charID, sheet.name+" (imported)") + sCharacter.apiUpdateCharSheet(charID, sheet) + except: + continue wx.CallAfter(self.callback) class SkillBackupThread(threading.Thread): diff --git a/service/conversions/releaseProteus.py b/service/conversions/releaseProteus.py new file mode 100644 index 000000000..9a964cb94 --- /dev/null +++ b/service/conversions/releaseProteus.py @@ -0,0 +1,104 @@ +""" +Conversion pack for Proteus Module Tiericide +""" + +CONVERSIONS = { + # Renamed items + "Basic Capacitor Recharger": "'Basic' Capacitor Recharger", + "Basic Capacitor Power Relay": "'Basic' Capacitor Power Relay", + "Basic Overdrive Injector System": "'Basic' Overdrive Injector System", + "Basic Reinforced Bulkheads": "'Basic' Reinforced Bulkheads", + "Basic Nanofiber Internal Structure": "'Basic' Nanofiber Internal Structure", + "Basic Expanded Cargohold": "'Basic' Expanded Cargohold", + "Basic Inertia Stabilizers": "'Basic' Inertial Stabilizers", + "Inertia Stabilizers I": "Inertial Stabilizers I", + "Inertia Stabilizers II": "Inertial Stabilizers II", + "Basic Power Diagnostic System": "'Basic' Power Diagnostic System", + "Eutectic Capacitor Charge Array": "Eutectic Compact Cap Recharger", + "Cu Vapor Particle Bore Stream I": "Particle Bore Compact Mining Laser", + "Type-D Altered SS Expanded Cargo": "Type-D Restrained Expanded Cargo", + "Type-D Altered SS Inertial Stabilizers": "Type-D Restrained Inertial Stabilizers", + "Type-D Altered SS Nanofiber Structure": "Type-D Restrained Nanofiber Structure", + "Type-D Altered SS Overdrive Injector": "Type-D Restrained Overdrive Injector", + "Type-D Altered SS Reinforced Bulkheads": "Type-D Restrained Reinforced Bulkheads", + "Mark I Modified SS Reinforced Bulkheads": "Mark I Compact Reinforced Bulkheads", + "Type-D Power Core Modification: Capacitor Power Relay": "Type-D Restrained Capacitor Power Relay", + "Mark I Generator Refitting: Capacitor Power Relay": "Mark I Compact Capacitor Power Relay", + "Mark I Generator Refitting: Diagnostic System": "Mark I Compact Power Diagnostic System", + "Synthetic Hull Conversion Overdrive Injector I": "Synthetic Hull Conversion Overdrive Injector", + "Synthetic Hull Conversion Reinforced Bulkheads I": "Synthetic Hull Conversion Reinforced Bulkheads", + "Synthetic Hull Conversion Inertia Stabilizers I": "Synthetic Hull Conversion Inertia Stabilizers", + "Synthetic Hull Conversion Nanofiber Structure I": "Synthetic Hull Conversion Nanofiber Structure", + "Elara Mining Laser Upgrade": "Elara Restrained Mining Laser Upgrade", + "Carpo Mining Laser Upgrade": "'Carpo' Mining Laser Upgrade", + "Aoede Mining Laser Upgrade": "'Aoede' Mining Laser Upgrade", + "Frigoris Ice Harvester Upgrade": "Frigoris Restrained Ice Harvester Upgrade", + "Anguis Ice Harvester Upgrade": "'Anguis' Ice Harvester Upgrade", + "Ingenii Ice Harvester Upgrade": "'Ingenii' Ice Harvester Upgrade", + "Limited Expanded 'Archiver' Cargo I": "Limited Expanded 'Archiver' Cargo", + "EP-S Gaussian Excavation Pulse": "EP-S Gaussian Scoped Mining Laser", + + # Converted items + "Alpha Reactor Control: Diagnostic System": "'Basic' Power Diagnostic System", + "Marked Generator Refitting: Diagnostic System": "'Basic' Power Diagnostic System", + "Partial Power Plant Manager: Diagnostic System": "'Basic' Power Diagnostic System", + "Type-E Power Core Modification: Diagnostic System": "'Basic' Power Diagnostic System", + "Type-E Power Core Modification: Reaction Control": "'Basic' Power Diagnostic System", + "Local Hull Conversion Reinforced Bulkheads I": "Type-D Restrained Reinforced Bulkheads", + "Beta Hull Mod Reinforced Bulkheads": "Mark I Compact Reinforced Bulkheads", + "Beta Hull Mod Inertial Stabilizers": "Type-D Restrained Inertial Stabilizers", + "Local Hull Conversion Inertial Stabilizers I": "Type-D Restrained Inertial Stabilizers", + "Mark I Modified SS Inertial Stabilizers": "Type-D Restrained Inertial Stabilizers", + "Marked Modified SS Inertial Stabilizers": "Type-D Restrained Inertial Stabilizers", + "Beta Reactor Control: Diagnostic System I": "Mark I Compact Power Diagnostic System", + "Local Power Plant Manager: Diagnostic System I": "Mark I Compact Power Diagnostic System", + "Type-D Power Core Modification: Diagnostic System": "Mark I Compact Power Diagnostic System", + "Alpha Hull Mod Expanded Cargo": "'Basic' Expanded Cargohold", + "Marked Modified SS Expanded Cargo": "'Basic' Expanded Cargohold", + "Partial Hull Conversion Expanded Cargo": "'Basic' Expanded Cargohold", + "Type-E Altered SS Expanded Cargo": "'Basic' Expanded Cargohold", + "AGM Capacitor Charge Array": "'Basic' Capacitor Recharger", + "F-a10 Buffer Capacitor Regenerator": "'Basic' Capacitor Recharger", + "Industrial Capacitor Recharger": "'Basic' Capacitor Recharger", + "Secondary Parallel Link-Capacitor": "'Basic' Capacitor Recharger", + "Beta Reactor Control: Capacitor Power Relay I": "Mark I Compact Capacitor Power Relay", + "Alpha Hull Mod Overdrive Injector": "'Basic' Overdrive Injector System", + "Marked Modified SS Overdrive Injector": "'Basic' Overdrive Injector System", + "Partial Hull Conversion Overdrive Injector": "'Basic' Overdrive Injector System", + "Type-E Altered SS Overdrive Injector": "'Basic' Overdrive Injector System", + "Erin Mining Laser Upgrade": "Elara Restrained Mining Laser Upgrade", + "Alpha Hull Mod Reinforced Bulkheads": "'Basic' Reinforced Bulkheads", + "Marked Modified SS Reinforced Bulkheads": "'Basic' Reinforced Bulkheads", + "Partial Hull Conversion Reinforced Bulkheads": "'Basic' Reinforced Bulkheads", + "Type-E Altered SS Reinforced Bulkheads": "'Basic' Reinforced Bulkheads", + "Alpha Hull Mod Nanofiber Structure": "'Basic' Nanofiber Internal Structure", + "Marked Modified SS Nanofiber Structure": "'Basic' Nanofiber Internal Structure", + "Partial Hull Conversion Nanofiber Structure": "'Basic' Nanofiber Internal Structure", + "Type-E Altered SS Nanofiber Structure": "'Basic' Nanofiber Internal Structure", + "Crisium Ice Harvester Upgrade": "Frigoris Restrained Ice Harvester Upgrade", + "Beta Hull Mod Nanofiber Structure": "Type-D Restrained Nanofiber Structure", + "Local Hull Conversion Nanofiber Structure I": "Type-D Restrained Nanofiber Structure", + "Mark I Modified SS Nanofiber Structure": "Type-D Restrained Nanofiber Structure", + "Local Power Plant Manager: Capacity Power Relay I": "Type-D Restrained Capacitor Power Relay", + "EP-R Argon Ion Basic Excavation Pulse": "Single Diode Basic Mining Laser", + "Rubin Basic Particle Bore Stream": "Single Diode Basic Mining Laser", + "Xenon Basic Drilling Beam": "Single Diode Basic Mining Laser", + "Barton Reactor Capacitor Recharger I": "Eutectic Compact Cap Recharger", + "F-b10 Nominal Capacitor Regenerator": "Eutectic Compact Cap Recharger", + "Fixed Parallel Link-Capacitor I": "Eutectic Compact Cap Recharger", + "Beta Hull Mod Expanded Cargo": "Type-D Restrained Expanded Cargo", + "Local Hull Conversion Expanded Cargo I": "Type-D Restrained Expanded Cargo", + "Mark I Modified SS Expanded Cargo": "Type-D Restrained Expanded Cargo", + "Dual Diode Mining Laser I": "EP-S Gaussian Scoped Mining Laser", + "Alpha Hull Mod Inertial Stabilizers": "'Basic' Inertial Stabilizers", + "Partial Hull Conversion Inertial Stabilizers": "'Basic' Inertial Stabilizers", + "Type-E Altered SS Inertial Stabilizers": "'Basic' Inertial Stabilizers", + "Alpha Reactor Control: Capacitor Power Relay": "'Basic' Capacitor Power Relay", + "Marked Generator Refitting: Capacitor Power Relay": "'Basic' Capacitor Power Relay", + "Partial Power Plant Manager: Capacity Power Relay": "'Basic' Capacitor Power Relay", + "Type-E Power Core Modification: Capacitor Power Relay": "'Basic' Capacitor Power Relay", + "XeCl Drilling Beam I": "Particle Bore Compact Mining Laser", + "Beta Hull Mod Overdrive Injector": "Type-D Restrained Overdrive Injector", + "Local Hull Conversion Overdrive Injector I": "Type-D Restrained Overdrive Injector", + "Mark I Modified SS Overdrive Injector": "Type-D Restrained Overdrive Injector", +} diff --git a/service/conversions/releaseTiamat.py b/service/conversions/releaseTiamat.py new file mode 100644 index 000000000..5aed8669b --- /dev/null +++ b/service/conversions/releaseTiamat.py @@ -0,0 +1,17 @@ +""" +Conversion pack for Tiamat Module Tiericide +""" + +CONVERSIONS = { + "Enduring Cargo Scanner": "Type-E Enduring Cargo Scanner", + "Scoped Cargo Scanner": "PL-0 Scoped Cargo Scanner", + "Compact Ship Scanner": "Ta3 Compact Ship Scanner", + "Scoped Survey Scanner": "ML-3 Scoped Survey Scanner", + "Compact Light Missile Launcher": "Arbalest Compact Light Missile Launcher", + "Ample Light Missile Launcher": "TE-2100 Ample Light Missile Launcher", + "Compact Capacitor Flux Coil": "Mark I Compact Capacitor Flux Coil", + "Restrained Capacitor Flux Coil": "Type-D Restrained Capacitor Flux Coil", + "Compact Reactor Control Unit": "Mark I Compact Reactor Control Unit", + "Upgraded Co-Processor": "Photonic Upgraded Co-Processor", + "Compact Micro Auxiliary Power Core": "Vigor Compact Micro Auxiliary Power Core" +} diff --git a/service/conversions/skinnedShips.py b/service/conversions/skinnedShips.py index 2b170dcc7..d2e0a8d85 100644 --- a/service/conversions/skinnedShips.py +++ b/service/conversions/skinnedShips.py @@ -21,20 +21,24 @@ CONVERSIONS = { "Coercer Blood Raiders Edition": "Coercer", "Cormorant Guristas Edition": "Cormorant", "Cyclone Thukker Tribe Edition": "Cyclone", + "Dominix Quafe Edition": "Dominix", "Ferox Guristas Edition": "Ferox", "Golem Guristas Edition": "Golem", "Golem Kaalakiota Edition": "Golem", "Golem Nugoeihuvi Edition": "Golem", "Hyperion Aliastra Edition": "Hyperion", "Hyperion Innerzone Shipping Edition": "Hyperion", + "Hyperion Inner Zone Shipping Edition": "Hyperion", "Incursus Aliastra Edition": "Incursus", "Incursus Innerzone Shipping Edition": "Incursus", + "Incursus Inner Zone Shipping Edition": "Incursus", "Inner Zone Shipping Catalyst": "Catalyst", "Inner Zone Shipping Imicus": "Imicus", "Intaki Syndicate Catalyst": "Catalyst", "InterBus Catalyst": "Catalyst", "Iteron Inner Zone Shipping Edition": "Iteron Mark V", "Kronos Innerzone Shipping Edition": "Kronos", + "Kronos Inner Zone Shipping Edition": "Kronos", "Kronos Police Edition": "Kronos", "Kronos Quafe Edition": "Kronos", "Mackinaw ORE Development Edition": "Mackinaw", @@ -42,6 +46,7 @@ CONVERSIONS = { "Maelstrom Nefantar Edition": "Maelstrom", "Mammoth Nefantar Edition": "Mammoth", "Megathron Innerzone Shipping Edition": "Megathron", + "Megathron Inner Zone Shipping Edition": "Megathron", "Megathron Police Edition": "Megathron", "Megathron Quafe Edition": "Megathron", "Merlin Nugoeihuvi Edition": "Merlin", @@ -84,9 +89,12 @@ CONVERSIONS = { "Tempest Nefantar Edition": "Tempest", "Thorax Aliastra Edition": "Thorax", "Thorax Innerzone Shipping Edition": "Thorax", + "Thorax Inner Zone Shipping Edition": "Thorax", "Thrasher Thukker Tribe Edition": "Thrasher", + "Tristan Quafe Edition": "Tristan", "Vargur Justice Edition": "Vargur", "Vargur Krusual Edition": "Vargur", "Vargur Nefantar Edition": "Vargur", + "Vexor Quafe Edition": "Vexor", "Vherokior Probe": "Probe" } diff --git a/service/fit.py b/service/fit.py index e731c3edf..fac02bb5c 100644 --- a/service/fit.py +++ b/service/fit.py @@ -17,7 +17,6 @@ # along with pyfa. If not, see . #=============================================================================== -import os.path import locale import copy import threading @@ -47,11 +46,13 @@ class FitBackupThread(threading.Thread): path = self.path sFit = Fit.getInstance() allFits = map(lambda x: x[0], sFit.getAllFits()) - backedUpFits = sFit.exportXml(*allFits) + backedUpFits = sFit.exportXml(self.callback, *allFits) backupFile = open(path, "w", encoding="utf-8") backupFile.write(backedUpFits) backupFile.close() - wx.CallAfter(self.callback) + + # Send done signal to GUI + wx.CallAfter(self.callback, -1) class FitImportThread(threading.Thread): @@ -61,14 +62,11 @@ class FitImportThread(threading.Thread): self.callback = callback def run(self): - importedFits = [] - paths = self.paths sFit = Fit.getInstance() - for path in paths: - pathImported = sFit.importFit(path) - if pathImported is not None: - importedFits += pathImported - wx.CallAfter(self.callback, importedFits) + fits = sFit.importFitFromFiles(self.paths, self.callback) + + # Send done signal to GUI + wx.CallAfter(self.callback, -1, fits) class Fit(object): @@ -96,7 +94,8 @@ class Fit(object): "colorFitBySlot": False, "rackSlots": True, "rackLabels": True, - "compactSkills": True} + "compactSkills": True, + "showTooltip": True} self.serviceFittingOptions = SettingsProvider.getInstance().getSettings( "pyfaServiceFittingOptions", serviceFittingDefaultOptions) @@ -127,6 +126,9 @@ class Fit(object): return names + def countAllFits(self): + return eos.db.countAllFits() + def countFitsWithShip(self, shipID): count = eos.db.countFitsWithShip(shipID) return count @@ -741,7 +743,7 @@ class Fit(object): fit = eos.db.getFit(fitID) for attr in ("em", "thermal", "kinetic", "explosive"): - setattr(dp, "%sAmount" % attr, ammo.getAttribute("%sDamage" % attr)) + setattr(dp, "%sAmount" % attr, ammo.getAttribute("%sDamage" % attr) or 0) fit.damagePattern = dp self.recalc(fit) @@ -758,9 +760,9 @@ class Fit(object): fit = eos.db.getFit(fitID) return Port.exportDna(fit) - def exportXml(self, *fitIDs): + def exportXml(self, callback=None, *fitIDs): fits = map(lambda fitID: eos.db.getFit(fitID), fitIDs) - return Port.exportXml(*fits) + return Port.exportXml(callback, *fits) def backupFits(self, path, callback): thread = FitBackupThread(path, callback) @@ -770,26 +772,50 @@ class Fit(object): thread = FitImportThread(paths, callback) thread.start() - def importFit(self, path): - filename = os.path.split(path)[1] + def importFitFromFiles(self, paths, callback=None): + """ + Imports fits from file(s). First processes all provided paths and stores + assembled fits into a list. This allows us to call back to the GUI as + fits are processed as well as when fits are being saved. + returns + """ defcodepage = locale.getpreferredencoding() - file = open(path, "r") - srcString = file.read() - # If file had ANSI encoding, convert it to unicode using system - # default codepage, or use fallback cp1252 on any encoding errors - if isinstance(srcString, str): - try: - srcString = unicode(srcString, defcodepage) - except UnicodeDecodeError: - srcString = unicode(srcString, "cp1252") + fits = [] + for path in paths: + if callback: # Pulse + wx.CallAfter(callback, "Processing file:\n%s"%path) - _, fits = Port.importAuto(srcString, filename) - for fit in fits: + file = open(path, "r") + srcString = file.read() + # If file had ANSI encoding, convert it to unicode using system + # default codepage, or use fallback cp1252 on any encoding errors + if isinstance(srcString, str): + try: + srcString = unicode(srcString, defcodepage) + except UnicodeDecodeError: + srcString = unicode(srcString, "cp1252") + + _, fitsImport = Port.importAuto(srcString, path, callback=callback) + fits += fitsImport + + IDs = [] + numFits = len(fits) + for i, fit in enumerate(fits): + # Set some more fit attributes and save fit.character = self.character fit.damagePattern = self.pattern fit.targetResists = self.targetResists + eos.db.save(fit) + IDs.append(fit.ID) + if callback: # Pulse + wx.CallAfter( + callback, + "Processing complete, saving fits to database\n(%d/%d)" % + (i+1, numFits) + ) + return fits def importFitFromBuffer(self, bufferStr, activeFit=None): @@ -798,15 +824,8 @@ class Fit(object): fit.character = self.character fit.damagePattern = self.pattern fit.targetResists = self.targetResists - return fits - - def saveImportedFits(self, fits): - IDs = [] - for fit in fits: eos.db.save(fit) - IDs.append(fit.ID) - - return IDs + return fits def checkStates(self, fit, base): changed = False diff --git a/service/market.py b/service/market.py index fdde3c598..541e8cd8d 100644 --- a/service/market.py +++ b/service/market.py @@ -23,6 +23,7 @@ import wx import Queue +import config import eos.db import eos.types from service.settings import SettingsProvider, NetworkSettings @@ -189,10 +190,12 @@ class Market(): "Stratios Emergency Responder": self.les_grp, # Issued for Somer Blink lottery "Scorpion Ishukone Watch": self.les_grp, # Prize for offline events - fanfest PVP and poker tourneys "Miasmos Quafe Ultra Edition": self.les_grp, # Gift to people who purchased FF HD stream - "Interbus Shuttle": self.les_grp, + "InterBus Shuttle": self.les_grp, "Leopard": self.les_grp, # 2013 new year gift "Whiptail": self.les_grp, # AT12 prize - "Chameleon": self.les_grp } # AT12 prize + "Chameleon": self.les_grp, # AT12 prize + "Victorieux Luxury Yacht": self.les_grp # Worlds Collide prize \o/ chinese getting owned + } self.ITEMS_FORCEGROUP_R = self.__makeRevDict(self.ITEMS_FORCEGROUP) self.les_grp.addItems = list(self.getItem(itmn) for itmn in self.ITEMS_FORCEGROUP_R[self.les_grp]) @@ -214,13 +217,35 @@ class Market(): "Goru's Shuttle": False, "Guristas Shuttle": False, "Mobile Decoy Unit": False, # Seems to be left over test mod for deployables - "Tournament Micro Jump Unit": False} # Normally seen only on tournament arenas - + "Tournament Micro Jump Unit": False, # Normally seen only on tournament arenas + u"\u4e07\u738b\u5b9d\u5ea7\u7ea7YC117\u5e74\u7279\u522b\u7248": False, # Proteus added shitton of chinese-specific ships + u"\u4e4c\u9e26\u7ea7YC117\u5e74\u7279\u522b\u7248": False, + u"\u54cd\u5c3e\u86c7\u7ea7YC117\u5e74\u7279\u522b\u7248": False, + u"\u5730\u72f1\u5929\u4f7f\u7ea7YC117\u5e74\u7279\u522b\u7248": False, + u"\u591a\u7c73\u5c3c\u514b\u65af\u7ea7YC117\u5e74\u7279\u522b\u7248": False, + u"\u672b\u65e5\u6c99\u573a\u7ea7YC117\u5e74\u7279\u522b\u7248": False, + u"\u707e\u96be\u7ea7YC117\u5e74\u7279\u522b\u7248": False, + u"\u9a6c\u514b\u745e\u7ea7YC117\u5e74\u7279\u522b\u7248": False, + u"\u5e7c\u9f99\u7ea7YC117\u5e74\u7279\u522b\u7248": False, + u"\u6bd2\u8725\u7ea7YC117\u5e74\u7279\u522b\u7248": False, + u"\u4f0a\u4ec0\u5854\u7ea7YC117\u5e74\u7279\u522b\u7248": False, + u"\u94f6\u9e70\u7ea7YC117\u5e74\u7279\u522b\u7248": False, + "Council Diplomatic Shuttle": False, # Not sure yet + } # do not publish ships that we convert for name in conversions.packs['skinnedShips']: self.ITEMS_FORCEPUBLISHED[name] = False + if config.debug: + # Publish Tactical Dessy Modes if in debug + # Cannot use GROUPS_FORCEPUBLISHED as this does not force items + # within group to be published, but rather for the group itself + # to show up on ship list + group = self.getGroup("Ship Modifiers", eager="items") + for item in group.items: + self.ITEMS_FORCEPUBLISHED[item.name] = True + # List of groups which are forcibly published self.GROUPS_FORCEPUBLISHED = { "Prototype Exploration Ship": False } # We moved the only ship from this group to other group anyway diff --git a/service/port.py b/service/port.py index b69a69007..e3bfe9dd7 100644 --- a/service/port.py +++ b/service/port.py @@ -18,11 +18,12 @@ #=============================================================================== import re +import os import xml.dom -import json from eos.types import State, Slot, Module, Cargo, Fit, Ship, Drone, Implant, Booster import service +import wx try: from collections import OrderedDict @@ -35,20 +36,21 @@ class Port(object): """Service which houses all import/export format functions""" @classmethod - def importAuto(cls, string, sourceFileName=None, activeFit=None): + def importAuto(cls, string, path=None, activeFit=None, callback=None): # Get first line and strip space symbols of it to avoid possible detection errors firstLine = re.split("[\n\r]+", string.strip(), maxsplit=1)[0] firstLine = firstLine.strip() # If XML-style start of tag encountered, detect as XML if re.match("<", firstLine): - return "XML", cls.importXml(string) + return "XML", cls.importXml(string, callback) # If we've got source file name which is used to describe ship name # and first line contains something like [setup name], detect as eft config file - if re.match("\[.*\]", firstLine) and sourceFileName is not None: - shipName = sourceFileName.rsplit('.')[0] - return "EFT Config", cls.importEftCfg(shipName, string) + if re.match("\[.*\]", firstLine) and path is not None: + filename = os.path.split(path)[1] + shipName = filename.rsplit('.')[0] + return "EFT Config", cls.importEftCfg(shipName, string, callback) # If no file is specified and there's comma between brackets, # consider that we have [ship, setup name] and detect like eft export format @@ -200,7 +202,7 @@ class Port(object): return fit @staticmethod - def importEftCfg(shipname, contents): + def importEftCfg(shipname, contents, callback=None): """Handle import from EFT config store file""" # Check if we have such ship in database, bail if we don't @@ -208,7 +210,7 @@ class Port(object): try: sMkt.getItem(shipname) except: - return + return [] # empty list is expected # If client didn't take care of encoding file contents into Unicode, # do it using fallback encoding ourselves @@ -346,6 +348,9 @@ class Port(object): f.modules.append(m) # Append fit to list of fits fits.append(f) + + if callback: + wx.CallAfter(callback, None) # Skip fit silently if we get an exception except Exception: pass @@ -353,14 +358,15 @@ class Port(object): return fits @staticmethod - def importXml(text): + def importXml(text, callback=None): sMkt = service.Market.getInstance() doc = xml.dom.minidom.parseString(text.encode("utf-8")) fittings = doc.getElementsByTagName("fittings").item(0) fittings = fittings.getElementsByTagName("fitting") fits = [] - for fitting in fittings: + + for i, fitting in enumerate(fittings): f = Fit() f.name = fitting.getAttribute("name") # Maelstrom @@ -402,6 +408,8 @@ class Port(object): except KeyboardInterrupt: continue fits.append(f) + if callback: + wx.CallAfter(callback, None) return fits @@ -503,11 +511,11 @@ class Port(object): return dna + "::" @classmethod - def exportXml(cls, *fits): + def exportXml(cls, callback=None, *fits): doc = xml.dom.minidom.Document() fittings = doc.createElement("fittings") doc.appendChild(fittings) - for fit in fits: + for i, fit in enumerate(fits): try: fitting = doc.createElement("fitting") fitting.setAttribute("name", fit.name) @@ -571,5 +579,8 @@ class Port(object): except: print "Failed on fitID: %d"%fit.ID continue + finally: + if callback: + wx.CallAfter(callback, i) return doc.toprettyxml() diff --git a/service/price.py b/service/price.py index fafdf3297..aefd1b14f 100644 --- a/service/price.py +++ b/service/price.py @@ -63,7 +63,7 @@ class Price(): data = [] # Base request URL - baseurl = "https://api.eve-central.com/api/marketstat" + baseurl = "https://eve-central.com/api/marketstat" data.append(("usesystem", 30000142)) # Use Jita for market for typeID in toRequest: # Add all typeID arguments diff --git a/staticdata/eve.db b/staticdata/eve.db index e52adba6a..c48497192 100644 Binary files a/staticdata/eve.db and b/staticdata/eve.db differ diff --git a/staticdata/icons/ships/34562.png b/staticdata/icons/ships/34562.png new file mode 100644 index 000000000..56b777b71 Binary files /dev/null and b/staticdata/icons/ships/34562.png differ diff --git a/staticdata/icons/ships/34590.png b/staticdata/icons/ships/34590.png new file mode 100644 index 000000000..a42c9df37 Binary files /dev/null and b/staticdata/icons/ships/34590.png differ