From 0de950862b89cc4d28580d100d65f6941ec46ac0 Mon Sep 17 00:00:00 2001 From: Maru Maru Date: Sun, 11 Mar 2018 03:28:48 -0400 Subject: [PATCH 01/32] Added a crude data exporter for effs Known to be quite buggy and needs formating adjustments. In order to export fit data it first requires data to be exported with pyfas minimal html exporter. The resulting pyfaFits.html file should be placed in the project directory before running effs_stat_export.py. --- effs_stat_export.py | 474 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 474 insertions(+) create mode 100755 effs_stat_export.py diff --git a/effs_stat_export.py b/effs_stat_export.py new file mode 100755 index 000000000..604cc250e --- /dev/null +++ b/effs_stat_export.py @@ -0,0 +1,474 @@ +import inspect +import os +import platform +import re +import sys +import traceback +from optparse import AmbiguousOptionError, BadOptionError, OptionParser + +from logbook import CRITICAL, DEBUG, ERROR, FingersCrossedHandler, INFO, Logger, NestedSetup, NullHandler, StreamHandler, TimedRotatingFileHandler, WARNING, \ + __version__ as logbook_version + +import config + +try: + import wxversion +except ImportError: + wxversion = None + +try: + import sqlalchemy +except ImportError: + sqlalchemy = None + +pyfalog = Logger(__name__) + +class PassThroughOptionParser(OptionParser): + + def _process_args(self, largs, rargs, values): + while rargs: + try: + OptionParser._process_args(self, largs, rargs, values) + except (BadOptionError, AmbiguousOptionError) as e: + pyfalog.error("Bad startup option passed.") + largs.append(e.opt_str) + +usage = "usage: %prog [--root]" +parser = PassThroughOptionParser(usage=usage) +parser.add_option("-r", "--root", action="store_true", dest="rootsavedata", help="if you want pyfa to store its data in root folder, use this option", default=False) +parser.add_option("-w", "--wx28", action="store_true", dest="force28", help="Force usage of wxPython 2.8", default=False) +parser.add_option("-d", "--debug", action="store_true", dest="debug", help="Set logger to debug level.", default=False) +parser.add_option("-t", "--title", action="store", dest="title", help="Set Window Title", default=None) +parser.add_option("-s", "--savepath", action="store", dest="savepath", help="Set the folder for savedata", default=None) +parser.add_option("-l", "--logginglevel", action="store", dest="logginglevel", help="Set desired logging level [Critical|Error|Warning|Info|Debug]", default="Error") + +(options, args) = parser.parse_args() + +if options.rootsavedata is True: + config.saveInRoot = True + +# set title if it wasn't supplied by argument +if options.title is None: + options.title = "pyfa %s%s - Python Fitting Assistant" % (config.version, "" if config.tag.lower() != 'git' else " (git)") + +config.debug = options.debug + +# convert to unicode if it is set +if options.savepath is not None: + options.savepath = unicode(options.savepath) +config.defPaths(options.savepath) + +try: + # noinspection PyPackageRequirements + import wx +except: + exit_message = "Cannot import wxPython. You can download wxPython (2.8+) from http://www.wxpython.org/" + raise PreCheckException(exit_message) + +try: + import requests + config.requestsVersion = requests.__version__ +except ImportError: + raise PreCheckException("Cannot import requests. You can download requests from https://pypi.python.org/pypi/requests.") + +import eos.db + +#if config.saVersion[0] > 0 or config.saVersion[1] >= 7: + # <0.7 doesn't have support for events ;_; (mac-deprecated) +config.sa_events = True +import eos.events + + # noinspection PyUnresolvedReferences +import service.prefetch # noqa: F401 + + # Make sure the saveddata db exists +if not os.path.exists(config.savePath): + os.mkdir(config.savePath) + +eos.db.saveddata_meta.create_all() + + +armorLinkShip = eos.db.searchFits('armor links')[0] +infoLinkShip = eos.db.searchFits('information links')[0] +shieldLinkShip = eos.db.searchFits('shield links')[0] +skirmishLinkShip = eos.db.searchFits('skirmish links')[0] +import json + +def processExportedHtml(fileLocation): + output = open('./jsonShipStatExport.js', 'w') + output.write('let shipJSON = JSON.stringify([') + outputBaseline = open('./jsonShipBaseStatExport.js', 'w') + outputBaseline.write('let shipBaseJSON = JSON.stringify([') + shipCata = eos.db.getItemsByCategory('Ship') + #shipCata = eos.db.getItem(638) + #shipCata = eos.db.getMetaGroup(638) + #shipCata = eos.db.getAttributeInfo(638) + #shipCata = eos.db.getItemsByCategory('Traits') + #shipCata = eos.db.getGroup('invtraits') + #shipCata = eos.db.getCategory('Traits') + from sqlalchemy import Column, String, Integer, ForeignKey, Boolean, Table + from sqlalchemy.orm import relation, mapper, synonym, deferred + from eos.db import gamedata_session + from eos.db import gamedata_meta + from eos.db.gamedata.metaGroup import metatypes_table, items_table + from eos.db.gamedata.group import groups_table + + from eos.gamedata import AlphaClone, Attribute, Category, Group, Item, MarketGroup, \ + MetaGroup, AttributeInfo, MetaData, Effect, ItemEffect, Traits + from eos.db.gamedata.traits import traits_table + #shipCata = traits_table #categories_table + #print shipCata + #print shipCata.columns + #print shipCata.categoryName + #print vars(shipCata) + data = category = gamedata_session.query(Category).all() + #print data + #print iter(data) + eff = gamedata_session.query(Category).get(53) #Bonus (id14) #Effects (id 53) + data = eff; + #print eff + #print vars(eff) + things = []#[Category, MetaGroup, AttributeInfo, MetaData, Item, Attribute, Effect, ItemEffect, Traits]#, Attribute] + if False: + for dataTab in things : + print 'Data for: ' + str(dataTab) + try: + filter = dataTab.typeID == 638 + except: + filter = dataTab.ID == 638 + data = gamedata_session.query(dataTab).options().filter(filter).all() + print data + try: + varDict = vars(data) + print varDict + except: + print 'Not a Dict' + try: + varDict = data.__doc__ + print varDict + except: + print 'No items()' + try: + for varDict in data: + print varDict + print vars(varDict) + except: + print 'Not a list of dicts' + + #print vars(shipCata._sa_instance_state) + baseLimit = 500 + baseN = 0 + for ship in iter(shipCata): + if baseN < baseLimit: + #print ship + #print ship.ID + #print ship.categoryName + #print vars(ship) + dna = str(ship.ID) + stats = setFitFromString(dna, ship.name, ship.groupID) + outputBaseline.write(stats) + outputBaseline.write(',\n') + baseN += 1; + limit = 500 + skipTill = 0 + n = 0 + try: + with open('pyfaFits.html'): + fileLocation = 'pyfaFits.html' + except: + try: + with open('.pyfa/pyfaFits.html'): + fileLocation = '.pyfa/pyfaFits.html' + except: + try: + with open('../.pyfa/pyfaFits.html'): + fileLocation = '../.pyfa/pyfaFits.html' + except: + try: + with open('../../.pyfa/pyfaFits.html'): + fileLocation = '../../.pyfa/pyfaFits.html' + except: + fileLocation = None; + if fileLocation != None: + with open(fileLocation) as f: + for fullLine in f: + if limit == None or n < limit: + n += 1 + startInd = fullLine.find('/dna/') + 5 + line = fullLine[startInd:len(fullLine)] + endInd = line.find('::') + dna = line[0:endInd] + name = line[line.find('>') + 1:line.find('<')] + if n >= skipTill: + print 'name: ' + name + ' DNA: ' + dna + stats = setFitFromString(dna, name, 0) + output.write(stats) + output.write(',\n') + output.write(']);\nexport {shipJSON};') + output.close() + outputBaseline.write(']);\nexport {shipBaseJSON};') + outputBaseline.close() +def parseNeededFitDetails(fit, groupID): + singleRunPrintPreformed = False + weaponSystems = [] + groups = {} + #help(fit.modules) + #help(fit.modules[0]) + for mod in fit.modules: + if mod.dps > 0: + keystr = str(mod.itemID) + '-' + str(mod.chargeID) + if keystr in groups: + groups[keystr][1] += 1 + else: + groups[keystr] = [mod, 1] + for wepGroup in groups: + stats = groups[wepGroup][0] + c = groups[wepGroup][1] + tracking = 0 + maxVelocity = 0 + explosionDelay = 0 + damageReductionFactor = 0 + explosionRadius = 0 + explosionVelocity = 0 + aoeFieldRange = 0 + if stats.hardpoint == 2: + tracking = stats.itemModifiedAttributes['trackingSpeed'] + typeing = 'Turret' + name = stats.item.name + ', ' + stats.charge.name + elif stats.hardpoint == 1: + maxVelocity = stats.chargeModifiedAttributes['maxVelocity'] + explosionDelay = stats.chargeModifiedAttributes['explosionDelay'] + damageReductionFactor = stats.chargeModifiedAttributes['aoeDamageReductionFactor'] + explosionRadius = stats.chargeModifiedAttributes['aoeCloudSize'] + explosionVelocity = stats.chargeModifiedAttributes['aoeVelocity'] + typeing = 'Missile' + name = stats.item.name + ', ' + stats.charge.name + elif stats.hardpoint == 0: + aoeFieldRange = stats.itemModifiedAttributes['empFieldRange'] + typeing = 'SmartBomb' + name = stats.item.name + statDict = {'dps': stats.dps * c, 'capUse': stats.capUse * c, 'falloff': stats.falloff,\ + 'type': typeing, 'name': name, 'optimal': stats.maxRange,\ + 'numCharges': stats.numCharges, 'numShots': stats.numShots, 'reloadTime': stats.reloadTime,\ + 'cycleTime': stats.cycleTime, 'volley': stats.volley * c, 'tracking': tracking,\ + 'maxVelocity': maxVelocity, 'explosionDelay': explosionDelay, 'damageReductionFactor': damageReductionFactor,\ + 'explosionRadius': explosionRadius, 'explosionVelocity': explosionVelocity, 'aoeFieldRange': aoeFieldRange\ + } + weaponSystems.append(statDict) + #if fit.droneDPS > 0: + for drone in fit.drones: + if drone.dps[0] > 0 and drone.amountActive > 0: + newTracking = drone.itemModifiedAttributes['trackingSpeed'] / (drone.itemModifiedAttributes['optimalSigRadius'] / 40000) + statDict = {'dps': drone.dps[0], 'cycleTime': drone.cycleTime, 'type': 'Drone',\ + 'optimal': drone.maxRange, 'name': drone.item.name, 'falloff': drone.falloff,\ + 'maxSpeed': drone.itemModifiedAttributes['maxVelocity'], 'tracking': newTracking,\ + 'volley': drone.dps[1]\ + } + weaponSystems.append(statDict) + for fighter in fit.fighters: + if fighter.dps[0] > 0 and fighter.amountActive > 0: + abilities = [] + #for ability in fighter.abilities: + if 'fighterAbilityAttackMissileDamageEM' in fighter.itemModifiedAttributes: + baseRef = 'fighterAbilityAttackMissile' + baseRefDam = baseRef + 'Damage' + abBaseDamage = fighter.itemModifiedAttributes[baseRefDam + 'EM'] + fighter.itemModifiedAttributes[baseRefDam + 'Therm'] + fighter.itemModifiedAttributes[baseRefDam + 'Exp'] + fighter.itemModifiedAttributes[baseRefDam + 'Kin'] + abDamage = abBaseDamage * fighter.itemModifiedAttributes[baseRefDam + 'Multiplier'] + ability = {'name': 'RegularAttack', 'volley': abDamage * fighter.amountActive, 'explosionRadius': fighter.itemModifiedAttributes[baseRef + 'ExplosionRadius'],\ + 'explosionVelocity': fighter.itemModifiedAttributes[baseRef + 'ExplosionVelocity'], 'optimal': fighter.itemModifiedAttributes[baseRef + 'RangeOptimal'],\ + 'damageReductionFactor': fighter.itemModifiedAttributes[baseRef + 'ReductionFactor'], 'rof': fighter.itemModifiedAttributes[baseRef + 'Duration'],\ + } + abilities.append(ability) + if 'fighterAbilityMissilesDamageEM' in fighter.itemModifiedAttributes: + baseRef = 'fighterAbilityMissiles' + baseRefDam = baseRef + 'Damage' + abBaseDamage = fighter.itemModifiedAttributes[baseRefDam + 'EM'] + fighter.itemModifiedAttributes[baseRefDam + 'Therm'] + fighter.itemModifiedAttributes[baseRefDam + 'Exp'] + fighter.itemModifiedAttributes[baseRefDam + 'Kin'] + abDamage = abBaseDamage * fighter.itemModifiedAttributes[baseRefDam + 'Multiplier'] + ability = {'name': 'MissileAttack', 'volley': abDamage * fighter.amountActive, 'explosionRadius': fighter.itemModifiedAttributes[baseRef + 'ExplosionRadius'],\ + 'explosionVelocity': fighter.itemModifiedAttributes[baseRef + 'ExplosionVelocity'], 'optimal': fighter.itemModifiedAttributes[baseRef + 'Range'],\ + 'damageReductionFactor': fighter.itemModifiedAttributes[baseRefDam + 'ReductionFactor'], 'rof': fighter.itemModifiedAttributes[baseRef + 'Duration'],\ + } + abilities.append(ability) + statDict = {'dps': fighter.dps[0], 'type': 'Fighter', 'name': fighter.item.name,\ + 'maxSpeed': fighter.itemModifiedAttributes['maxVelocity'], 'abilities': abilities, 'ehp': fighter.itemModifiedAttributes['shieldCapacity'] / 0.8875 * fighter.amountActive,\ + 'volley': fighter.dps[1], 'signatureRadius': fighter.itemModifiedAttributes['signatureRadius']\ + } + weaponSystems.append(statDict) + turretSlots = fit.ship.itemModifiedAttributes['turretSlotsLeft'] + launcherSlots = fit.ship.itemModifiedAttributes['launcherSlotsLeft'] + droneBandwidth = fit.ship.itemModifiedAttributes['droneBandwidth'] + if turretSlots == None: + turretSlots = 0 + if launcherSlots == None: + launcherSlots = 0 + if droneBandwidth == None: + droneBandwidth = 0 + effectiveTurretSlots = turretSlots + effectiveLauncherSlots = launcherSlots + effectiveDroneBandwidth = droneBandwidth + from eos.db import gamedata_session + from eos.gamedata import Traits + filter = Traits.typeID == fit.shipID + data = gamedata_session.query(Traits).options().filter(filter).all() + roleBonusMode = False + if len(data) != 0: + print data[0].traitText + for bonusText in data[0].traitText.splitlines(): + bonusText = bonusText.lower() + #print 'bonus text line: ' + bonusText + if 'per skill level' in bonusText: + roleBonusMode = False + if 'role bonus' in bonusText: + roleBonusMode = True + multi = 1 + if 'damage' in bonusText and not 'control' in bonusText: + splitText = bonusText.split('%') + if float(splitText[0]) > 0 == False: + pyfalog.error('damage bonus split did not parse correctly!') + if roleBonusMode: + addedMulti = float(splitText[0]) + else: + addedMulti = float(splitText[0]) * 5 + multi = 1 + (addedMulti / 100) + elif 'rate of fire' in bonusText: + splitText = bonusText.split('%') + if splitText[0] > 0 == False: + pyfalog.error('rate of fire bonus split did not parse correctly!') + if roleBonusMode: + rofMulti = float(splitText[0]) + else: + rofMulti = float(splitText[0]) * 5 + multi = 1 / (1 - (rofMulti / 100)) + if multi > 1: + if 'drone' in bonusText.lower(): + effectiveDroneBandwidth *= multi + elif 'turret' in bonusText.lower(): + effectiveTurretSlots *= multi + elif 'missile' in bonusText.lower(): + effectiveLauncherSlots *= multi + effectiveTurretSlots = round(effectiveTurretSlots, 2); + effectiveLauncherSlots = round(effectiveLauncherSlots, 2); + effectiveDroneBandwidth = round(effectiveDroneBandwidth, 2); + hullResonance = {'exp': fit.ship.itemModifiedAttributes['explosiveDamageResonance'], 'kin': fit.ship.itemModifiedAttributes['kineticDamageResonance'], \ + 'therm': fit.ship.itemModifiedAttributes['thermalDamageResonance'], 'em': fit.ship.itemModifiedAttributes['emDamageResonance']} + armorResonance = {'exp': fit.ship.itemModifiedAttributes['armorExplosiveDamageResonance'], 'kin': fit.ship.itemModifiedAttributes['armorKineticDamageResonance'], \ + 'therm': fit.ship.itemModifiedAttributes['armorThermalDamageResonance'], 'em': fit.ship.itemModifiedAttributes['armorEmDamageResonance']} + shieldResonance = {'exp': fit.ship.itemModifiedAttributes['shieldExplosiveDamageResonance'], 'kin': fit.ship.itemModifiedAttributes['shieldKineticDamageResonance'], \ + 'therm': fit.ship.itemModifiedAttributes['shieldThermalDamageResonance'], 'em': fit.ship.itemModifiedAttributes['shieldEmDamageResonance']} + resonance = {'hull': hullResonance, 'armor': armorResonance, 'shield': shieldResonance} + shipSizes = ['Frigate', 'Destroyer', 'Cruiser', 'Battlecruiser', 'Battleship', 'Capital', 'Industrial', 'Misc'] + if groupID in [25, 31, 237, 324, 830, 831, 834, 893, 1283, 1527]: + shipSize = shipSizes[0] + elif groupID in [420, 541, 1305, 1534]: + shipSize = shipSizes[1] + elif groupID in [26, 358, 832, 833, 894, 906, 963]: + shipSize = shipSizes[2] + elif groupID in [419, 540, 1201]: + shipSize = shipSizes[3] + elif groupID in [27, 381, 898, 900]: + shipSize = shipSizes[4] + elif groupID in [30, 485, 513, 547, 659, 883, 902, 1538]: + shipSize = shipSizes[5] + elif groupID in [28, 380, 1202, 463, 543, 941]: + shipSize = shipSizes[6] + elif groupID in [29, 1022]: + shipSize = shipSizes[7] + else: + shipSize = 'ShipSize not found for ' + fit.name + ' groupID: ' + str(groupID) + print shipSize + try: + parsable = {'name': fit.name, 'ehp': fit.ehp, 'droneDPS': fit.droneDPS, \ + 'droneVolley': fit.droneVolley, 'hp': fit.hp, 'maxTargets': fit.maxTargets, \ + 'maxSpeed': fit.maxSpeed, 'weaponVolley': fit.weaponVolley, 'totalVolley': fit.totalVolley,\ + 'maxTargetRange': fit.maxTargetRange, 'scanStrength': fit.scanStrength,\ + 'weaponDPS': fit.weaponDPS, 'alignTime': fit.alignTime, 'signatureRadius': fit.ship.itemModifiedAttributes['signatureRadius'],\ + 'weapons': weaponSystems, 'scanRes': fit.ship.itemModifiedAttributes['scanResolution'],\ + 'projectedModules': fit.projectedModules, 'capUsed': fit.capUsed, 'capRecharge': fit.capRecharge,\ + 'rigSlots': fit.ship.itemModifiedAttributes['rigSlots'], 'lowSlots': fit.ship.itemModifiedAttributes['lowSlots'],\ + 'midSlots': fit.ship.itemModifiedAttributes['medSlots'], 'highSlots': fit.ship.itemModifiedAttributes['hiSlots'],\ + 'turretSlots': fit.ship.itemModifiedAttributes['turretSlotsLeft'], 'launcherSlots': fit.ship.itemModifiedAttributes['launcherSlotsLeft'],\ + 'powerOutput': fit.ship.itemModifiedAttributes['powerOutput'], 'rigSize': fit.ship.itemModifiedAttributes['rigSize'],\ + 'effectiveTurrets': effectiveTurretSlots, 'effectiveLaunchers': effectiveLauncherSlots, 'effectiveDroneBandwidth': effectiveDroneBandwidth,\ + 'resonance': resonance, 'typeID': fit.shipID, 'groupID': groupID, 'shipSize': shipSize\ + } + except TypeError: + print 'Error parsing fit:' + str(fit) + print TypeError + parsable = {'name': fit.name + 'Fit could not be correctly parsed'} + #print fit.ship.itemModifiedAttributes.items() + #help(fit) + #if len(fit.fighters) > 5: + #print fit.fighters + #help(fit.fighters[0]) + stringified = json.dumps(parsable, skipkeys=True) + return stringified +def setFitFromString(dnaString, fitName, groupID) : + modArray = dnaString.split(':') + fitL = Fit() + print modArray[0] + fitID = fitL.newFit(int(modArray[0]), fitName) + fit = eos.db.getFit(fitID) + ammoArray = [] + n = -1 + for mod in iter(modArray): + n = n + 1 + if n > 0: + #print n + #print mod + modSp = mod.split(';') + if len(modSp) == 2: + k = 0 + while k < int(modSp[1]): + k = k + 1 + itemID = int(modSp[0]) + item = eos.db.getItem(int(modSp[0]), eager=("attributes", "group.category")) + cat = item.category.name + if cat == 'Drone': + fitL.addDrone(fitID, itemID, int(modSp[1]), recalc=False) + k += int(modSp[1]) + if cat == 'Fighter': + fitL.addFighter(fitID, itemID, recalc=False) + #fit.fighters.last.abilities.active = True + k += 100 + if fitL.isAmmo(int(modSp[0])): + k += 100 + ammoArray.append(int(modSp[0])); + fitL.appendModule(fitID, int(modSp[0])) + fit = eos.db.getFit(fitID) + #nonEmptyModules = fit.modules + #while nonEmptyModules.find(None) >= 0: + # print 'ssssssssssssssss' + # nonEmptyModules.remove(None) + for ammo in iter(ammoArray): + fitL.setAmmo(fitID, ammo, fit.modules) + if len(fit.drones) > 0: + fit.drones[0].amountActive = fit.drones[0].amount + eos.db.commit() + for fighter in iter(fit.fighters): + for ability in fighter.abilities: + if ability.effect.handlerName == u'fighterabilityattackm' and ability.active == True: + for abilityAltRef in fighter.abilities: + if abilityAltRef.effect.isImplemented: + abilityAltRef.active = True + fitL.recalc(fit) + fit = eos.db.getFit(fitID) + #print fit.modules + #fit.calculateWeaponStats() + fitL.addCommandFit(fit.ID, armorLinkShip) + fitL.addCommandFit(fit.ID, shieldLinkShip) + fitL.addCommandFit(fit.ID, skirmishLinkShip) + fitL.addCommandFit(fit.ID, infoLinkShip) + #def anonfunc(unusedArg): True + jsonStr = parseNeededFitDetails(fit, groupID) + #print vars(fit.ship._Ship__item) + #help(fit) + Fit.deleteFit(fitID) + return jsonStr +launchUI = False +#launchUI = True +if launchUI == False: + from service.fit import Fit + #setFitFromString(dnaChim, 'moMachsD') + #help(eos.db.getItem) + #ship = es_Ship(eos.db.getItem(27)) + processExportedHtml('../.pyfa/pyfaFits.html') From 4b2a58ca6ff8765f855c2d1ac1be1f3f215536bf Mon Sep 17 00:00:00 2001 From: Maru Maru Date: Sun, 11 Mar 2018 03:51:41 -0400 Subject: [PATCH 02/32] Updated .gitignore to include the generated export files --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index dcee5d692..ec0ef928d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ +#Fit and ship export data generated by effs_stat_export.py +jsonShipBaseStatExport.js +jsonShipStatExport.js + #Python specific *.pyc From ed3083aa77aa00c03f6df964253741a3050364ce Mon Sep 17 00:00:00 2001 From: Maru Maru Date: Mon, 19 Mar 2018 22:56:42 -0400 Subject: [PATCH 03/32] Fixed indentation issues and corrected fighters damage reduction factor to include sensitivity --- effs_stat_export.py | 67 ++++++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 31 deletions(-) diff --git a/effs_stat_export.py b/effs_stat_export.py index 604cc250e..3ce41e9b6 100755 --- a/effs_stat_export.py +++ b/effs_stat_export.py @@ -11,6 +11,8 @@ from logbook import CRITICAL, DEBUG, ERROR, FingersCrossedHandler, INFO, Logger, import config +from math import log + try: import wxversion except ImportError: @@ -169,9 +171,9 @@ def processExportedHtml(fileLocation): outputBaseline.write(stats) outputBaseline.write(',\n') baseN += 1; - limit = 500 - skipTill = 0 - n = 0 + limit = 500 + skipTill = 0 + n = 0 try: with open('pyfaFits.html'): fileLocation = 'pyfaFits.html' @@ -235,7 +237,7 @@ def parseNeededFitDetails(fit, groupID): tracking = stats.itemModifiedAttributes['trackingSpeed'] typeing = 'Turret' name = stats.item.name + ', ' + stats.charge.name - elif stats.hardpoint == 1: + elif stats.hardpoint == 1 or 'Bomb Launcher' in stats.item.name: maxVelocity = stats.chargeModifiedAttributes['maxVelocity'] explosionDelay = stats.chargeModifiedAttributes['explosionDelay'] damageReductionFactor = stats.chargeModifiedAttributes['aoeDamageReductionFactor'] @@ -247,15 +249,15 @@ def parseNeededFitDetails(fit, groupID): aoeFieldRange = stats.itemModifiedAttributes['empFieldRange'] typeing = 'SmartBomb' name = stats.item.name - statDict = {'dps': stats.dps * c, 'capUse': stats.capUse * c, 'falloff': stats.falloff,\ - 'type': typeing, 'name': name, 'optimal': stats.maxRange,\ - 'numCharges': stats.numCharges, 'numShots': stats.numShots, 'reloadTime': stats.reloadTime,\ - 'cycleTime': stats.cycleTime, 'volley': stats.volley * c, 'tracking': tracking,\ - 'maxVelocity': maxVelocity, 'explosionDelay': explosionDelay, 'damageReductionFactor': damageReductionFactor,\ - 'explosionRadius': explosionRadius, 'explosionVelocity': explosionVelocity, 'aoeFieldRange': aoeFieldRange\ - } - weaponSystems.append(statDict) - #if fit.droneDPS > 0: + statDict = {'dps': stats.dps * c, 'capUse': stats.capUse * c, 'falloff': stats.falloff,\ + 'type': typeing, 'name': name, 'optimal': stats.maxRange,\ + 'numCharges': stats.numCharges, 'numShots': stats.numShots, 'reloadTime': stats.reloadTime,\ + 'cycleTime': stats.cycleTime, 'volley': stats.volley * c, 'tracking': tracking,\ + 'maxVelocity': maxVelocity, 'explosionDelay': explosionDelay, 'damageReductionFactor': damageReductionFactor,\ + 'explosionRadius': explosionRadius, 'explosionVelocity': explosionVelocity, 'aoeFieldRange': aoeFieldRange\ + } + weaponSystems.append(statDict) + #if fit.droneDPS > 0: for drone in fit.drones: if drone.dps[0] > 0 and drone.amountActive > 0: newTracking = drone.itemModifiedAttributes['trackingSpeed'] / (drone.itemModifiedAttributes['optimalSigRadius'] / 40000) @@ -266,34 +268,37 @@ def parseNeededFitDetails(fit, groupID): } weaponSystems.append(statDict) for fighter in fit.fighters: + print vars(fighter) if fighter.dps[0] > 0 and fighter.amountActive > 0: abilities = [] #for ability in fighter.abilities: if 'fighterAbilityAttackMissileDamageEM' in fighter.itemModifiedAttributes: baseRef = 'fighterAbilityAttackMissile' baseRefDam = baseRef + 'Damage' + damageReductionFactor = log(fighter.itemModifiedAttributes[baseRef + 'ReductionFactor']) / log(fighter.itemModifiedAttributes[baseRef + 'ReductionSensitivity']) abBaseDamage = fighter.itemModifiedAttributes[baseRefDam + 'EM'] + fighter.itemModifiedAttributes[baseRefDam + 'Therm'] + fighter.itemModifiedAttributes[baseRefDam + 'Exp'] + fighter.itemModifiedAttributes[baseRefDam + 'Kin'] abDamage = abBaseDamage * fighter.itemModifiedAttributes[baseRefDam + 'Multiplier'] ability = {'name': 'RegularAttack', 'volley': abDamage * fighter.amountActive, 'explosionRadius': fighter.itemModifiedAttributes[baseRef + 'ExplosionRadius'],\ 'explosionVelocity': fighter.itemModifiedAttributes[baseRef + 'ExplosionVelocity'], 'optimal': fighter.itemModifiedAttributes[baseRef + 'RangeOptimal'],\ - 'damageReductionFactor': fighter.itemModifiedAttributes[baseRef + 'ReductionFactor'], 'rof': fighter.itemModifiedAttributes[baseRef + 'Duration'],\ + 'damageReductionFactor': damageReductionFactor, 'rof': fighter.itemModifiedAttributes[baseRef + 'Duration'],\ } abilities.append(ability) if 'fighterAbilityMissilesDamageEM' in fighter.itemModifiedAttributes: baseRef = 'fighterAbilityMissiles' baseRefDam = baseRef + 'Damage' + damageReductionFactor = log(fighter.itemModifiedAttributes[baseRefDam + 'ReductionFactor']) / log(fighter.itemModifiedAttributes[baseRefDam + 'ReductionSensitivity']) abBaseDamage = fighter.itemModifiedAttributes[baseRefDam + 'EM'] + fighter.itemModifiedAttributes[baseRefDam + 'Therm'] + fighter.itemModifiedAttributes[baseRefDam + 'Exp'] + fighter.itemModifiedAttributes[baseRefDam + 'Kin'] abDamage = abBaseDamage * fighter.itemModifiedAttributes[baseRefDam + 'Multiplier'] ability = {'name': 'MissileAttack', 'volley': abDamage * fighter.amountActive, 'explosionRadius': fighter.itemModifiedAttributes[baseRef + 'ExplosionRadius'],\ 'explosionVelocity': fighter.itemModifiedAttributes[baseRef + 'ExplosionVelocity'], 'optimal': fighter.itemModifiedAttributes[baseRef + 'Range'],\ - 'damageReductionFactor': fighter.itemModifiedAttributes[baseRefDam + 'ReductionFactor'], 'rof': fighter.itemModifiedAttributes[baseRef + 'Duration'],\ + 'damageReductionFactor': damageReductionFactor, 'rof': fighter.itemModifiedAttributes[baseRef + 'Duration'],\ } abilities.append(ability) - statDict = {'dps': fighter.dps[0], 'type': 'Fighter', 'name': fighter.item.name,\ - 'maxSpeed': fighter.itemModifiedAttributes['maxVelocity'], 'abilities': abilities, 'ehp': fighter.itemModifiedAttributes['shieldCapacity'] / 0.8875 * fighter.amountActive,\ - 'volley': fighter.dps[1], 'signatureRadius': fighter.itemModifiedAttributes['signatureRadius']\ - } - weaponSystems.append(statDict) + statDict = {'dps': fighter.dps[0], 'type': 'Fighter', 'name': fighter.item.name,\ + 'maxSpeed': fighter.itemModifiedAttributes['maxVelocity'], 'abilities': abilities, 'ehp': fighter.itemModifiedAttributes['shieldCapacity'] / 0.8875 * fighter.amountActive,\ + 'volley': fighter.dps[1], 'signatureRadius': fighter.itemModifiedAttributes['signatureRadius']\ + } + weaponSystems.append(statDict) turretSlots = fit.ship.itemModifiedAttributes['turretSlotsLeft'] launcherSlots = fit.ship.itemModifiedAttributes['launcherSlotsLeft'] droneBandwidth = fit.ship.itemModifiedAttributes['droneBandwidth'] @@ -433,14 +438,14 @@ def setFitFromString(dnaString, fitName, groupID) : if fitL.isAmmo(int(modSp[0])): k += 100 ammoArray.append(int(modSp[0])); - fitL.appendModule(fitID, int(modSp[0])) - fit = eos.db.getFit(fitID) - #nonEmptyModules = fit.modules - #while nonEmptyModules.find(None) >= 0: - # print 'ssssssssssssssss' - # nonEmptyModules.remove(None) + fitL.appendModule(fitID, int(modSp[0])) + fit = eos.db.getFit(fitID) + #nonEmptyModules = fit.modules + #while nonEmptyModules.find(None) >= 0: + # print 'ssssssssssssssss' + # nonEmptyModules.remove(None) for ammo in iter(ammoArray): - fitL.setAmmo(fitID, ammo, fit.modules) + fitL.setAmmo(fitID, ammo, filter(lambda mod: str(mod).find('name') > 0, fit.modules)) if len(fit.drones) > 0: fit.drones[0].amountActive = fit.drones[0].amount eos.db.commit() @@ -450,10 +455,10 @@ def setFitFromString(dnaString, fitName, groupID) : for abilityAltRef in fighter.abilities: if abilityAltRef.effect.isImplemented: abilityAltRef.active = True - fitL.recalc(fit) - fit = eos.db.getFit(fitID) - #print fit.modules - #fit.calculateWeaponStats() + fitL.recalc(fit) + fit = eos.db.getFit(fitID) + #print fit.modules + #fit.calculateWeaponStats() fitL.addCommandFit(fit.ID, armorLinkShip) fitL.addCommandFit(fit.ID, shieldLinkShip) fitL.addCommandFit(fit.ID, skirmishLinkShip) From aec9202be1eedaf540b92af7bbb7dca9d9c6c050 Mon Sep 17 00:00:00 2001 From: Maru Maru Date: Thu, 5 Apr 2018 02:24:44 -0400 Subject: [PATCH 04/32] added more data to effs exports, including module names. --- effs_stat_export.py | 292 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 265 insertions(+), 27 deletions(-) diff --git a/effs_stat_export.py b/effs_stat_export.py index 3ce41e9b6..411fdbb86 100755 --- a/effs_stat_export.py +++ b/effs_stat_export.py @@ -97,9 +97,9 @@ skirmishLinkShip = eos.db.searchFits('skirmish links')[0] import json def processExportedHtml(fileLocation): - output = open('./jsonShipStatExport.js', 'w') + output = open('./shipJSON.js', 'w') output.write('let shipJSON = JSON.stringify([') - outputBaseline = open('./jsonShipBaseStatExport.js', 'w') + outputBaseline = open('./shipBaseJSON.js', 'w') outputBaseline.write('let shipBaseJSON = JSON.stringify([') shipCata = eos.db.getItemsByCategory('Ship') #shipCata = eos.db.getItem(638) @@ -158,21 +158,19 @@ def processExportedHtml(fileLocation): print 'Not a list of dicts' #print vars(shipCata._sa_instance_state) - baseLimit = 500 + baseLimit = 0 baseN = 0 + nameReqBase = ''; for ship in iter(shipCata): - if baseN < baseLimit: - #print ship - #print ship.ID - #print ship.categoryName - #print vars(ship) + if baseN < baseLimit and nameReqBase in ship.name: dna = str(ship.ID) stats = setFitFromString(dna, ship.name, ship.groupID) outputBaseline.write(stats) outputBaseline.write(',\n') baseN += 1; - limit = 500 + limit = 0 skipTill = 0 + nameReq = '' n = 0 try: with open('pyfaFits.html'): @@ -191,7 +189,17 @@ def processExportedHtml(fileLocation): fileLocation = '../../.pyfa/pyfaFits.html' except: fileLocation = None; - if fileLocation != None: + fitList = eos.db.getFitList() + with open(fileLocation) as f: + for fit in fitList: + if limit == None or n < limit: + n += 1 + name = fit.ship.name + ': ' + fit.name + if n >= skipTill and nameReq in name: + stats = parseNeededFitDetails(fit, 0) + output.write(stats) + output.write(',\n') + if False and fileLocation != None: with open(fileLocation) as f: for fullLine in f: if limit == None or n < limit: @@ -201,7 +209,7 @@ def processExportedHtml(fileLocation): endInd = line.find('::') dna = line[0:endInd] name = line[line.find('>') + 1:line.find('<')] - if n >= skipTill: + if n >= skipTill and nameReq in name: print 'name: ' + name + ' DNA: ' + dna stats = setFitFromString(dna, name, 0) output.write(stats) @@ -210,19 +218,227 @@ def processExportedHtml(fileLocation): output.close() outputBaseline.write(']);\nexport {shipBaseJSON};') outputBaseline.close() +def attrDirectMap(values, target, source): + for val in values: + target[val] = source.itemModifiedAttributes[val] def parseNeededFitDetails(fit, groupID): singleRunPrintPreformed = False weaponSystems = [] groups = {} - #help(fit.modules) - #help(fit.modules[0]) + moduleNames = [] + fitID = fit.ID + if len(fit.modules) > 0: + fit.name = fit.ship.name + ': ' + fit.name + print '' + print 'name: ' + fit.name + fitL = Fit() + fitL.recalc(fit) + fit = eos.db.getFit(fitID) + if False: + from eos.db import gamedata_session + from eos.gamedata import Group, Category + filterVal = Group.categoryID == 6 + data = gamedata_session.query(Group).options().filter(filterVal).all() + for group in data: + print group.groupName + ' groupID: ' + str(group.groupID) + #print group.categoryName + ' categoryID: ' + str(group.categoryID) + ', published: ' + str(group.published) + #print vars(group) + #print '' + return '' + projectedModGroupIds = [ + 41, 52, 65, 67, 68, 71, 80, 201, 208, 291, 325, 379, 585, + 842, 899, 1150, 1154, 1189, 1306, 1672, 1697, 1698, 1815, 1894 + ] + projectedMods = filter(lambda mod: mod.item and mod.item.groupID in projectedModGroupIds, fit.modules) + + unpropedSpeed = fit.maxSpeed + unpropedSig = fit.ship.itemModifiedAttributes['signatureRadius'] + usingMWD = False + propMods = filter(lambda mod: mod.item and mod.item.groupID in [46], fit.modules) + possibleMWD = filter(lambda mod: 'signatureRadiusBonus' in mod.item.attributes, propMods) + if len(possibleMWD) > 0 and possibleMWD[0].state > 0: + mwd = possibleMWD[0] + oldMwdState = mwd.state + mwd.state = 0 + fitL.recalc(fit) + fit = eos.db.getFit(fitID) + unpropedSpeed = fit.maxSpeed + unpropedSig = fit.ship.itemModifiedAttributes['signatureRadius'] + mwd.state = oldMwdState + fitL.recalc(fit) + fit = eos.db.getFit(fitID) + usingMWD = True + + print fit.ship.itemModifiedAttributes['rigSize'] + print propMods + mwdPropSpeed = fit.maxSpeed + if groupID > 0: + propID = None + rigSize = fit.ship.itemModifiedAttributes['rigSize'] + if rigSize == 1 and fit.ship.itemModifiedAttributes['medSlots'] > 0: + propID = 440 + elif rigSize == 2 and fit.ship.itemModifiedAttributes['medSlots'] > 0: + propID = 12076 + elif rigSize == 3 and fit.ship.itemModifiedAttributes['medSlots'] > 0: + propID = 12084 + elif rigSize == 4 and fit.ship.itemModifiedAttributes['medSlots'] > 0: + if fit.ship.itemModifiedAttributes['powerOutput'] > 60000: + propID = 41253 + else: + propID = 12084 + elif rigSize == None and fit.ship.itemModifiedAttributes['medSlots'] > 0: + propID = 440 + if propID: + fitL.appendModule(fitID, propID) + fitL.recalc(fit) + fit = eos.db.getFit(fitID) + mwdPropSpeed = fit.maxSpeed + mwdPosition = filter(lambda mod: mod.item and mod.item.ID == propID, fit.modules)[0].position + fitL.removeModule(fitID, mwdPosition) + fitL.recalc(fit) + fit = eos.db.getFit(fitID) + + projections = [] + for mod in projectedMods: + stats = {} + if mod.item.groupID == 65 or mod.item.groupID == 1672: + stats['type'] = 'Stasis Web' + stats['optimal'] = mod.itemModifiedAttributes['maxRange'] + attrDirectMap(['duration', 'speedFactor'], stats, mod) + elif mod.item.groupID == 291: + stats['type'] = 'Weapon Disruptor' + stats['optimal'] = mod.itemModifiedAttributes['maxRange'] + stats['falloff'] = mod.itemModifiedAttributes['falloffEffectiveness'] + attrDirectMap([ + 'trackingSpeedBonus', 'maxRangeBonus', 'falloffBonus', 'aoeCloudSizeBonus',\ + 'aoeVelocityBonus', 'missileVelocityBonus', 'explosionDelayBonus'\ + ], stats, mod) + elif mod.item.groupID == 68: + stats['type'] = 'Energy Nosferatu' + attrDirectMap(['powerTransferAmount', 'energyNeutralizerSignatureResolution'], stats, mod) + elif mod.item.groupID == 71: + stats['type'] = 'Energy Neutralizer' + attrDirectMap([ + 'energyNeutralizerSignatureResolution','entityCapacitorLevelModifierSmall',\ + 'entityCapacitorLevelModifierMedium', 'entityCapacitorLevelModifierLarge',\ + 'energyNeutralizerAmount'\ + ], stats, mod) + elif mod.item.groupID == 41 or mod.item.groupID == 1697: + stats['type'] = 'Remote Shield Booster' + attrDirectMap(['shieldBonus'], stats, mod) + elif mod.item.groupID == 325 or mod.item.groupID == 1698: + stats['type'] = 'Remote Armor Repairer' + attrDirectMap(['armorDamageAmount'], stats, mod) + elif mod.item.groupID == 52: + stats['type'] = 'Warp Scrambler' + attrDirectMap(['activationBlockedStrenght', 'warpScrambleStrength'], stats, mod) + elif mod.item.groupID == 379: + stats['type'] = 'Target Painter' + attrDirectMap(['signatureRadiusBonus'], stats, mod) + elif mod.item.groupID == 208: + stats['type'] = 'Sensor Dampener' + attrDirectMap(['maxTargetRangeBonus', 'scanResolutionBonus'], stats, mod) + elif mod.item.groupID == 201: + stats['type'] = 'ECM' + attrDirectMap([ + 'scanGravimetricStrengthBonus', 'scanMagnetometricStrengthBonus',\ + 'scanRadarStrengthBonus', 'scanLadarStrengthBonus',\ + ], stats, mod) + elif mod.item.groupID == 80: + stats['type'] = 'Burst Jammer' + mod.itemModifiedAttributes['maxRange'] = mod.itemModifiedAttributes['ecmBurstRange'] + attrDirectMap([ + 'scanGravimetricStrengthBonus', 'scanMagnetometricStrengthBonus',\ + 'scanRadarStrengthBonus', 'scanLadarStrengthBonus',\ + ], stats, mod) + elif mod.item.groupID == 1189: + stats['type'] = 'Micro Jump Drive' + mod.itemModifiedAttributes['maxRange'] = 0 + attrDirectMap(['moduleReactivationDelay'], stats, mod) + if mod.itemModifiedAttributes['maxRange'] == None: + print mod.item.name + print mod.itemModifiedAttributes.items() + raise ValueError('Projected module lacks a maxRange') + stats['optimal'] = mod.itemModifiedAttributes['maxRange'] + stats['falloff'] = mod.itemModifiedAttributes['falloffEffectiveness'] or 0 + attrDirectMap(['duration', 'capacitorNeed'], stats, mod) + projections.append(stats) + #print '' + #print stats + #print mod.item.name + #print mod.itemModifiedAttributes.items() + #print '' + #print vars(mod.item) + #print vars(web.itemModifiedAttributes) + #print vars(fit.modules) + #print vars(fit.modules[0]) + highSlotNames = [] + midSlotNames = [] + lowSlotNames = [] + rigSlotNames = [] + miscSlotNames = [] #subsystems ect for mod in fit.modules: + if mod.slot == 3: + modSlotNames = highSlotNames + elif mod.slot == 2: + modSlotNames = midSlotNames + elif mod.slot == 1: + modSlotNames = lowSlotNames + elif mod.slot == 4: + modSlotNames = rigSlotNames + elif mod.slot == 5: + modSlotNames = miscSlotNames + try: + if mod.item != None: + if mod.charge != None: + modSlotNames.append(mod.item.name + ': ' + mod.charge.name) + else: + modSlotNames.append(mod.item.name) + else: + modSlotNames.append('Empty Slot') + except: + print vars(mod) + print 'could not find name for module' + print fit.modules if mod.dps > 0: keystr = str(mod.itemID) + '-' + str(mod.chargeID) if keystr in groups: groups[keystr][1] += 1 else: groups[keystr] = [mod, 1] + for modInfo in [['High Slots:'], highSlotNames, ['', 'Med Slots:'], midSlotNames, ['', 'Low Slots:'], lowSlotNames, ['', 'Rig Slots:'], rigSlotNames]: + moduleNames.extend(modInfo) + if len(miscSlotNames) > 0: + moduleNames.append('') + moduleNames.append('Subsystems:') + moduleNames.extend(miscSlotNames) + droneNames = [] + fighterNames = [] + for drone in fit.drones: + if drone.amountActive > 0: + droneNames.append(drone.item.name) + for fighter in fit.fighters: + if fighter.amountActive > 0: + fighterNames.append(fighter.item.name) + if len(droneNames) > 0: + moduleNames.append('') + moduleNames.append('Drones:') + moduleNames.extend(droneNames) + if len(fighterNames) > 0: + moduleNames.append('') + moduleNames.append('Fighters:') + moduleNames.extend(fighterNames) + if len(fit.implants) > 0: + moduleNames.append('') + moduleNames.append('Implants:') + for implant in fit.implants: + moduleNames.append(implant.item.name) + if len(fit.commandFits) > 0: + moduleNames.append('') + moduleNames.append('Command Fits:') + for commandFit in fit.commandFits: + moduleNames.append(commandFit.name) + for wepGroup in groups: stats = groups[wepGroup][0] c = groups[wepGroup][1] @@ -268,7 +484,6 @@ def parseNeededFitDetails(fit, groupID): } weaponSystems.append(statDict) for fighter in fit.fighters: - print vars(fighter) if fighter.dps[0] > 0 and fighter.amountActive > 0: abilities = [] #for ability in fighter.abilities: @@ -313,32 +528,46 @@ def parseNeededFitDetails(fit, groupID): effectiveDroneBandwidth = droneBandwidth from eos.db import gamedata_session from eos.gamedata import Traits - filter = Traits.typeID == fit.shipID - data = gamedata_session.query(Traits).options().filter(filter).all() + filterVal = Traits.typeID == fit.shipID + data = gamedata_session.query(Traits).options().filter(filterVal).all() roleBonusMode = False if len(data) != 0: - print data[0].traitText + #print data[0].traitText + previousTypedBonus = 0 + previousDroneTypeBonus = 0 for bonusText in data[0].traitText.splitlines(): bonusText = bonusText.lower() #print 'bonus text line: ' + bonusText if 'per skill level' in bonusText: roleBonusMode = False - if 'role bonus' in bonusText: + if 'role bonus' in bonusText or 'misc bonus' in bonusText: roleBonusMode = True multi = 1 - if 'damage' in bonusText and not 'control' in bonusText: + if 'damage' in bonusText and not any(e in bonusText for e in ['control', 'heat']):#'control' in bonusText and not 'heat' in bonusText: splitText = bonusText.split('%') - if float(splitText[0]) > 0 == False: - pyfalog.error('damage bonus split did not parse correctly!') + if (float(splitText[0]) > 0) == False: + print 'damage bonus split did not parse correctly!' + print float(splitText[0]) if roleBonusMode: addedMulti = float(splitText[0]) else: addedMulti = float(splitText[0]) * 5 + if any(e in bonusText for e in [' em', 'thermal', 'kinetic', 'explosive']): + if addedMulti > previousTypedBonus: + previousTypedBonus = addedMulti + else: + addedMulti = 0 + if any(e in bonusText for e in ['heavy drone', 'medium drone', 'light drone', 'sentry drone']): + if addedMulti > previousDroneTypeBonus: + previousDroneTypeBonus = addedMulti + else: + addedMulti = 0 multi = 1 + (addedMulti / 100) elif 'rate of fire' in bonusText: splitText = bonusText.split('%') - if splitText[0] > 0 == False: - pyfalog.error('rate of fire bonus split did not parse correctly!') + if (float(splitText[0]) > 0) == False: + print 'rate of fire bonus split did not parse correctly!' + print float(splitText[0]) if roleBonusMode: rofMulti = float(splitText[0]) else: @@ -349,8 +578,11 @@ def parseNeededFitDetails(fit, groupID): effectiveDroneBandwidth *= multi elif 'turret' in bonusText.lower(): effectiveTurretSlots *= multi - elif 'missile' in bonusText.lower(): + elif any(e in bonusText for e in ['missile', 'torpedo']): effectiveLauncherSlots *= multi + if groupID == 485: + effectiveTurretSlots *= 9.4 + effectiveLauncherSlots *= 15 effectiveTurretSlots = round(effectiveTurretSlots, 2); effectiveLauncherSlots = round(effectiveLauncherSlots, 2); effectiveDroneBandwidth = round(effectiveDroneBandwidth, 2); @@ -394,7 +626,10 @@ def parseNeededFitDetails(fit, groupID): 'turretSlots': fit.ship.itemModifiedAttributes['turretSlotsLeft'], 'launcherSlots': fit.ship.itemModifiedAttributes['launcherSlotsLeft'],\ 'powerOutput': fit.ship.itemModifiedAttributes['powerOutput'], 'rigSize': fit.ship.itemModifiedAttributes['rigSize'],\ 'effectiveTurrets': effectiveTurretSlots, 'effectiveLaunchers': effectiveLauncherSlots, 'effectiveDroneBandwidth': effectiveDroneBandwidth,\ - 'resonance': resonance, 'typeID': fit.shipID, 'groupID': groupID, 'shipSize': shipSize\ + 'resonance': resonance, 'typeID': fit.shipID, 'groupID': groupID, 'shipSize': shipSize,\ + 'droneControlRange': fit.ship.itemModifiedAttributes['droneControlRange'], 'mass': fit.ship.itemModifiedAttributes['mass'],\ + 'moduleNames': moduleNames, 'projections': projections, 'unpropedSpeed': unpropedSpeed, 'unpropedSig': unpropedSig,\ + 'usingMWD': usingMWD, 'mwdPropSpeed': mwdPropSpeed } except TypeError: print 'Error parsing fit:' + str(fit) @@ -409,6 +644,9 @@ def parseNeededFitDetails(fit, groupID): return stringified def setFitFromString(dnaString, fitName, groupID) : modArray = dnaString.split(':') + additionalModeFit = '' + #if groupID == 485 and len(modArray) == 1: + #additionalModeFit = ',\n' + setFitFromString(dnaString + ':4292', fitName + ' (Sieged)', groupID) fitL = Fit() print modArray[0] fitID = fitL.newFit(int(modArray[0]), fitName) @@ -457,7 +695,7 @@ def setFitFromString(dnaString, fitName, groupID) : abilityAltRef.active = True fitL.recalc(fit) fit = eos.db.getFit(fitID) - #print fit.modules + print filter(lambda mod: mod.item.groupID in [1189, 658], fit.modules) #fit.calculateWeaponStats() fitL.addCommandFit(fit.ID, armorLinkShip) fitL.addCommandFit(fit.ID, shieldLinkShip) @@ -468,7 +706,7 @@ def setFitFromString(dnaString, fitName, groupID) : #print vars(fit.ship._Ship__item) #help(fit) Fit.deleteFit(fitID) - return jsonStr + return jsonStr + additionalModeFit launchUI = False #launchUI = True if launchUI == False: From 49b1e2ee36bad16dd81c951b19a1e9038168cf0d Mon Sep 17 00:00:00 2001 From: Maru Maru Date: Thu, 5 Apr 2018 02:35:12 -0400 Subject: [PATCH 05/32] Added option to copy EFFS stats to the clipboard via the CopySelectDialog UI --- gui/copySelectDialog.py | 6 ++++-- gui/mainFrame.py | 10 ++++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/gui/copySelectDialog.py b/gui/copySelectDialog.py index 57ce48f47..95f6db57b 100644 --- a/gui/copySelectDialog.py +++ b/gui/copySelectDialog.py @@ -29,19 +29,21 @@ class CopySelectDialog(wx.Dialog): copyFormatDna = 3 copyFormatCrest = 4 copyFormatMultiBuy = 5 + copyFormatEffs = 6 def __init__(self, parent): wx.Dialog.__init__(self, parent, id=wx.ID_ANY, title=u"Select a format", size=(-1, -1), style=wx.DEFAULT_DIALOG_STYLE) mainSizer = wx.BoxSizer(wx.VERTICAL) - copyFormats = [u"EFT", u"EFT (Implants)", u"XML", u"DNA", u"CREST", u"MultiBuy"] + copyFormats = [u"EFT", u"EFT (Implants)", u"XML", u"DNA", u"CREST", u"MultiBuy", u"EFFS"] copyFormatTooltips = {CopySelectDialog.copyFormatEft: u"EFT text format", CopySelectDialog.copyFormatEftImps: u"EFT text format", CopySelectDialog.copyFormatXml: u"EVE native XML format", CopySelectDialog.copyFormatDna: u"A one-line text format", CopySelectDialog.copyFormatCrest: u"A JSON format used for EVE CREST", - CopySelectDialog.copyFormatMultiBuy: u"MultiBuy text format"} + CopySelectDialog.copyFormatMultiBuy: u"MultiBuy text format", + CopySelectDialog.copyFormatEffs: u"EFFS json stats format"} selector = wx.RadioBox(self, wx.ID_ANY, label=u"Copy to the clipboard using:", choices=copyFormats, style=wx.RA_SPECIFY_ROWS) selector.Bind(wx.EVT_RADIOBOX, self.Selected) diff --git a/gui/mainFrame.py b/gui/mainFrame.py index d4b23f3a4..fbd814670 100644 --- a/gui/mainFrame.py +++ b/gui/mainFrame.py @@ -77,6 +77,8 @@ from eos.db.saveddata.queries import getFit as db_getFit from service.port import Port, IPortUser from service.settings import HTMLExportSettings +from effs_stat_export import parseNeededFitDetails as exportEffsStats + from time import gmtime, strftime import threading @@ -754,6 +756,10 @@ class MainFrame(wx.Frame, IPortUser): fit = db_getFit(self.getActiveFit()) toClipboard(Port.exportMultiBuy(fit)) + def clipboardEffs(self): + fit = db_getFit(self.getActiveFit()) + toClipboard(exportEffsStats(fit, 0)) + def importFromClipboard(self, event): clipboard = fromClipboard() try: @@ -769,11 +775,11 @@ class MainFrame(wx.Frame, IPortUser): CopySelectDialog.copyFormatXml: self.clipboardXml, CopySelectDialog.copyFormatDna: self.clipboardDna, CopySelectDialog.copyFormatCrest: self.clipboardCrest, - CopySelectDialog.copyFormatMultiBuy: self.clipboardMultiBuy} + CopySelectDialog.copyFormatMultiBuy: self.clipboardMultiBuy, + CopySelectDialog.copyFormatEffs: self.clipboardEffs} dlg = CopySelectDialog(self) dlg.ShowModal() selected = dlg.GetSelected() - CopySelectDict[selected]() try: From acade567694f7477f2c41571ebdbedfc49d47c03 Mon Sep 17 00:00:00 2001 From: Maru Maru Date: Mon, 30 Apr 2018 20:38:38 -0400 Subject: [PATCH 06/32] Adjusted effs fit name prefixing --- Rapier - 1 TP 1 Web Rapier w hml.xml | 25 +++++++++++++++++++++++++ effs_stat_export.py | 10 ++++++---- eos/events.py | 2 +- shipBaseJSON.js | 2 ++ shipJSON.js | 2 ++ 5 files changed, 36 insertions(+), 5 deletions(-) create mode 100644 Rapier - 1 TP 1 Web Rapier w hml.xml create mode 100644 shipBaseJSON.js create mode 100644 shipJSON.js diff --git a/Rapier - 1 TP 1 Web Rapier w hml.xml b/Rapier - 1 TP 1 Web Rapier w hml.xml new file mode 100644 index 000000000..9ba601692 --- /dev/null +++ b/Rapier - 1 TP 1 Web Rapier w hml.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/effs_stat_export.py b/effs_stat_export.py index 411fdbb86..4acc6b233 100755 --- a/effs_stat_export.py +++ b/effs_stat_export.py @@ -228,7 +228,9 @@ def parseNeededFitDetails(fit, groupID): moduleNames = [] fitID = fit.ID if len(fit.modules) > 0: - fit.name = fit.ship.name + ': ' + fit.name + fitName = fit.ship.name + ': ' + fit.name + else: + fitName = fit.name print '' print 'name: ' + fit.name fitL = Fit() @@ -611,10 +613,10 @@ def parseNeededFitDetails(fit, groupID): elif groupID in [29, 1022]: shipSize = shipSizes[7] else: - shipSize = 'ShipSize not found for ' + fit.name + ' groupID: ' + str(groupID) + shipSize = 'ShipSize not found for ' + fitName + ' groupID: ' + str(groupID) print shipSize try: - parsable = {'name': fit.name, 'ehp': fit.ehp, 'droneDPS': fit.droneDPS, \ + parsable = {'name': fitName, 'ehp': fit.ehp, 'droneDPS': fit.droneDPS, \ 'droneVolley': fit.droneVolley, 'hp': fit.hp, 'maxTargets': fit.maxTargets, \ 'maxSpeed': fit.maxSpeed, 'weaponVolley': fit.weaponVolley, 'totalVolley': fit.totalVolley,\ 'maxTargetRange': fit.maxTargetRange, 'scanStrength': fit.scanStrength,\ @@ -634,7 +636,7 @@ def parseNeededFitDetails(fit, groupID): except TypeError: print 'Error parsing fit:' + str(fit) print TypeError - parsable = {'name': fit.name + 'Fit could not be correctly parsed'} + parsable = {'name': fitName + 'Fit could not be correctly parsed'} #print fit.ship.itemModifiedAttributes.items() #help(fit) #if len(fit.fighters) > 5: diff --git a/eos/events.py b/eos/events.py index de8bdfadb..eabdf0b7e 100644 --- a/eos/events.py +++ b/eos/events.py @@ -58,7 +58,7 @@ def rel_listener(target, value, initiator): if not target or (isinstance(value, Module) and value.isEmpty): return - print "{} has had a relationship change :D".format(target) + #print "{} has had a relationship change :D".format(target) target.modified = datetime.datetime.now() diff --git a/shipBaseJSON.js b/shipBaseJSON.js new file mode 100644 index 000000000..28b7228b2 --- /dev/null +++ b/shipBaseJSON.js @@ -0,0 +1,2 @@ +let shipBaseJSON = JSON.stringify([]); +export {shipBaseJSON}; \ No newline at end of file diff --git a/shipJSON.js b/shipJSON.js new file mode 100644 index 000000000..22c2ed09f --- /dev/null +++ b/shipJSON.js @@ -0,0 +1,2 @@ +let shipJSON = JSON.stringify([]); +export {shipJSON}; \ No newline at end of file From 090065ddd4657c59eb84a3609d8266a92790e9bf Mon Sep 17 00:00:00 2001 From: Maru Maru Date: Mon, 30 Apr 2018 20:44:14 -0400 Subject: [PATCH 07/32] Removed sepurflous effs related files --- .gitignore | 4 ++-- Rapier - 1 TP 1 Web Rapier w hml.xml | 25 ------------------------- 2 files changed, 2 insertions(+), 27 deletions(-) delete mode 100644 Rapier - 1 TP 1 Web Rapier w hml.xml diff --git a/.gitignore b/.gitignore index ec0ef928d..f61f7692b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ #Fit and ship export data generated by effs_stat_export.py -jsonShipBaseStatExport.js -jsonShipStatExport.js +shipBaseJSON.js +shipJSON.js #Python specific *.pyc diff --git a/Rapier - 1 TP 1 Web Rapier w hml.xml b/Rapier - 1 TP 1 Web Rapier w hml.xml deleted file mode 100644 index 9ba601692..000000000 --- a/Rapier - 1 TP 1 Web Rapier w hml.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - From dba86edff24c526422af69208ad52af7bb56fad0 Mon Sep 17 00:00:00 2001 From: Maru Maru Date: Wed, 2 May 2018 03:25:20 -0400 Subject: [PATCH 08/32] Added python3 functionality to effs exporter --- effs_stat_export.py | 108 ++++++++++++++++++++++---------------------- 1 file changed, 54 insertions(+), 54 deletions(-) diff --git a/effs_stat_export.py b/effs_stat_export.py index 4acc6b233..91248276a 100755 --- a/effs_stat_export.py +++ b/effs_stat_export.py @@ -90,10 +90,10 @@ if not os.path.exists(config.savePath): eos.db.saveddata_meta.create_all() -armorLinkShip = eos.db.searchFits('armor links')[0] -infoLinkShip = eos.db.searchFits('information links')[0] -shieldLinkShip = eos.db.searchFits('shield links')[0] -skirmishLinkShip = eos.db.searchFits('skirmish links')[0] +#armorLinkShip = eos.db.searchFits('armor links')[0] +#infoLinkShip = eos.db.searchFits('information links')[0] +#shieldLinkShip = eos.db.searchFits('shield links')[0] +#skirmishLinkShip = eos.db.searchFits('skirmish links')[0] import json def processExportedHtml(fileLocation): @@ -133,31 +133,31 @@ def processExportedHtml(fileLocation): things = []#[Category, MetaGroup, AttributeInfo, MetaData, Item, Attribute, Effect, ItemEffect, Traits]#, Attribute] if False: for dataTab in things : - print 'Data for: ' + str(dataTab) + print('Data for: ' + str(dataTab)) try: filter = dataTab.typeID == 638 except: filter = dataTab.ID == 638 data = gamedata_session.query(dataTab).options().filter(filter).all() - print data + print(data) try: varDict = vars(data) - print varDict + print(varDict) except: - print 'Not a Dict' + print('Not a Dict') try: varDict = data.__doc__ - print varDict + print(varDict) except: - print 'No items()' + print('No items()') try: for varDict in data: - print varDict - print vars(varDict) + print(varDict) + print(vars(varDict)) except: - print 'Not a list of dicts' + print('Not a list of dicts') - #print vars(shipCata._sa_instance_state) + #print(vars(shipCata._sa_instance_state)) baseLimit = 0 baseN = 0 nameReqBase = ''; @@ -210,7 +210,7 @@ def processExportedHtml(fileLocation): dna = line[0:endInd] name = line[line.find('>') + 1:line.find('<')] if n >= skipTill and nameReq in name: - print 'name: ' + name + ' DNA: ' + dna + print('name: ' + name + ' DNA: ' + dna) stats = setFitFromString(dna, name, 0) output.write(stats) output.write(',\n') @@ -231,8 +231,8 @@ def parseNeededFitDetails(fit, groupID): fitName = fit.ship.name + ': ' + fit.name else: fitName = fit.name - print '' - print 'name: ' + fit.name + print('') + print('name: ' + fit.name) fitL = Fit() fitL.recalc(fit) fit = eos.db.getFit(fitID) @@ -242,10 +242,10 @@ def parseNeededFitDetails(fit, groupID): filterVal = Group.categoryID == 6 data = gamedata_session.query(Group).options().filter(filterVal).all() for group in data: - print group.groupName + ' groupID: ' + str(group.groupID) - #print group.categoryName + ' categoryID: ' + str(group.categoryID) + ', published: ' + str(group.published) - #print vars(group) - #print '' + print(group.groupName + ' groupID: ' + str(group.groupID)) + #print(group.categoryName + ' categoryID: ' + str(group.categoryID) + ', published: ' + str(group.published) + #print(vars(group) + #print('' return '' projectedModGroupIds = [ 41, 52, 65, 67, 68, 71, 80, 201, 208, 291, 325, 379, 585, @@ -271,8 +271,8 @@ def parseNeededFitDetails(fit, groupID): fit = eos.db.getFit(fitID) usingMWD = True - print fit.ship.itemModifiedAttributes['rigSize'] - print propMods + print(fit.ship.itemModifiedAttributes['rigSize']) + print(propMods) mwdPropSpeed = fit.maxSpeed if groupID > 0: propID = None @@ -358,22 +358,22 @@ def parseNeededFitDetails(fit, groupID): mod.itemModifiedAttributes['maxRange'] = 0 attrDirectMap(['moduleReactivationDelay'], stats, mod) if mod.itemModifiedAttributes['maxRange'] == None: - print mod.item.name - print mod.itemModifiedAttributes.items() + print(mod.item.name) + print(mod.itemModifiedAttributes.items()) raise ValueError('Projected module lacks a maxRange') stats['optimal'] = mod.itemModifiedAttributes['maxRange'] stats['falloff'] = mod.itemModifiedAttributes['falloffEffectiveness'] or 0 attrDirectMap(['duration', 'capacitorNeed'], stats, mod) projections.append(stats) - #print '' - #print stats - #print mod.item.name - #print mod.itemModifiedAttributes.items() - #print '' - #print vars(mod.item) - #print vars(web.itemModifiedAttributes) - #print vars(fit.modules) - #print vars(fit.modules[0]) + #print('' + #print(stats + #print(mod.item.name + #print(mod.itemModifiedAttributes.items() + #print('' + #print(vars(mod.item) + #print(vars(web.itemModifiedAttributes) + #print(vars(fit.modules) + #print(vars(fit.modules[0]) highSlotNames = [] midSlotNames = [] lowSlotNames = [] @@ -399,9 +399,9 @@ def parseNeededFitDetails(fit, groupID): else: modSlotNames.append('Empty Slot') except: - print vars(mod) - print 'could not find name for module' - print fit.modules + print(vars(mod)) + print('could not find name for module') + print(fit.modules) if mod.dps > 0: keystr = str(mod.itemID) + '-' + str(mod.chargeID) if keystr in groups: @@ -534,12 +534,12 @@ def parseNeededFitDetails(fit, groupID): data = gamedata_session.query(Traits).options().filter(filterVal).all() roleBonusMode = False if len(data) != 0: - #print data[0].traitText + #print(data[0].traitText previousTypedBonus = 0 previousDroneTypeBonus = 0 for bonusText in data[0].traitText.splitlines(): bonusText = bonusText.lower() - #print 'bonus text line: ' + bonusText + #print('bonus text line: ' + bonusText if 'per skill level' in bonusText: roleBonusMode = False if 'role bonus' in bonusText or 'misc bonus' in bonusText: @@ -548,8 +548,8 @@ def parseNeededFitDetails(fit, groupID): if 'damage' in bonusText and not any(e in bonusText for e in ['control', 'heat']):#'control' in bonusText and not 'heat' in bonusText: splitText = bonusText.split('%') if (float(splitText[0]) > 0) == False: - print 'damage bonus split did not parse correctly!' - print float(splitText[0]) + print('damage bonus split did not parse correctly!') + print(float(splitText[0])) if roleBonusMode: addedMulti = float(splitText[0]) else: @@ -568,8 +568,8 @@ def parseNeededFitDetails(fit, groupID): elif 'rate of fire' in bonusText: splitText = bonusText.split('%') if (float(splitText[0]) > 0) == False: - print 'rate of fire bonus split did not parse correctly!' - print float(splitText[0]) + print('rate of fire bonus split did not parse correctly!') + print(float(splitText[0])) if roleBonusMode: rofMulti = float(splitText[0]) else: @@ -614,7 +614,7 @@ def parseNeededFitDetails(fit, groupID): shipSize = shipSizes[7] else: shipSize = 'ShipSize not found for ' + fitName + ' groupID: ' + str(groupID) - print shipSize + print(shipSize) try: parsable = {'name': fitName, 'ehp': fit.ehp, 'droneDPS': fit.droneDPS, \ 'droneVolley': fit.droneVolley, 'hp': fit.hp, 'maxTargets': fit.maxTargets, \ @@ -634,13 +634,13 @@ def parseNeededFitDetails(fit, groupID): 'usingMWD': usingMWD, 'mwdPropSpeed': mwdPropSpeed } except TypeError: - print 'Error parsing fit:' + str(fit) - print TypeError + print('Error parsing fit:' + str(fit)) + print(TypeError) parsable = {'name': fitName + 'Fit could not be correctly parsed'} - #print fit.ship.itemModifiedAttributes.items() + #print(fit.ship.itemModifiedAttributes.items() #help(fit) #if len(fit.fighters) > 5: - #print fit.fighters + #print(fit.fighters #help(fit.fighters[0]) stringified = json.dumps(parsable, skipkeys=True) return stringified @@ -650,7 +650,7 @@ def setFitFromString(dnaString, fitName, groupID) : #if groupID == 485 and len(modArray) == 1: #additionalModeFit = ',\n' + setFitFromString(dnaString + ':4292', fitName + ' (Sieged)', groupID) fitL = Fit() - print modArray[0] + print(modArray[0]) fitID = fitL.newFit(int(modArray[0]), fitName) fit = eos.db.getFit(fitID) ammoArray = [] @@ -658,8 +658,8 @@ def setFitFromString(dnaString, fitName, groupID) : for mod in iter(modArray): n = n + 1 if n > 0: - #print n - #print mod + #print(n + #print(mod modSp = mod.split(';') if len(modSp) == 2: k = 0 @@ -682,7 +682,7 @@ def setFitFromString(dnaString, fitName, groupID) : fit = eos.db.getFit(fitID) #nonEmptyModules = fit.modules #while nonEmptyModules.find(None) >= 0: - # print 'ssssssssssssssss' + # print('ssssssssssssssss' # nonEmptyModules.remove(None) for ammo in iter(ammoArray): fitL.setAmmo(fitID, ammo, filter(lambda mod: str(mod).find('name') > 0, fit.modules)) @@ -697,7 +697,7 @@ def setFitFromString(dnaString, fitName, groupID) : abilityAltRef.active = True fitL.recalc(fit) fit = eos.db.getFit(fitID) - print filter(lambda mod: mod.item.groupID in [1189, 658], fit.modules) + print(filter(lambda mod: mod.item.groupID in [1189, 658], fit.modules)) #fit.calculateWeaponStats() fitL.addCommandFit(fit.ID, armorLinkShip) fitL.addCommandFit(fit.ID, shieldLinkShip) @@ -705,7 +705,7 @@ def setFitFromString(dnaString, fitName, groupID) : fitL.addCommandFit(fit.ID, infoLinkShip) #def anonfunc(unusedArg): True jsonStr = parseNeededFitDetails(fit, groupID) - #print vars(fit.ship._Ship__item) + #print(vars(fit.ship._Ship__item) #help(fit) Fit.deleteFit(fitID) return jsonStr + additionalModeFit From 56a3911b961e366ef4b23db98550f6283b89c96d Mon Sep 17 00:00:00 2001 From: Maru Maru Date: Sat, 5 May 2018 04:09:01 -0400 Subject: [PATCH 09/32] Adjusted effs export to remove bugs with python3 --- effs_stat_export.py | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/effs_stat_export.py b/effs_stat_export.py index 91248276a..f45a4a65c 100755 --- a/effs_stat_export.py +++ b/effs_stat_export.py @@ -90,10 +90,6 @@ if not os.path.exists(config.savePath): eos.db.saveddata_meta.create_all() -#armorLinkShip = eos.db.searchFits('armor links')[0] -#infoLinkShip = eos.db.searchFits('information links')[0] -#shieldLinkShip = eos.db.searchFits('shield links')[0] -#skirmishLinkShip = eos.db.searchFits('skirmish links')[0] import json def processExportedHtml(fileLocation): @@ -138,7 +134,7 @@ def processExportedHtml(fileLocation): filter = dataTab.typeID == 638 except: filter = dataTab.ID == 638 - data = gamedata_session.query(dataTab).options().filter(filter).all() + data = gamedata_session.query(dataTab).options().list(filter(filter).all()) print(data) try: varDict = vars(data) @@ -158,7 +154,7 @@ def processExportedHtml(fileLocation): print('Not a list of dicts') #print(vars(shipCata._sa_instance_state)) - baseLimit = 0 + baseLimit = 10 baseN = 0 nameReqBase = ''; for ship in iter(shipCata): @@ -168,7 +164,7 @@ def processExportedHtml(fileLocation): outputBaseline.write(stats) outputBaseline.write(',\n') baseN += 1; - limit = 0 + limit = 100 skipTill = 0 nameReq = '' n = 0 @@ -240,7 +236,7 @@ def parseNeededFitDetails(fit, groupID): from eos.db import gamedata_session from eos.gamedata import Group, Category filterVal = Group.categoryID == 6 - data = gamedata_session.query(Group).options().filter(filterVal).all() + data = gamedata_session.query(Group).options().list(filter(filterVal).all()) for group in data: print(group.groupName + ' groupID: ' + str(group.groupID)) #print(group.categoryName + ' categoryID: ' + str(group.categoryID) + ', published: ' + str(group.published) @@ -251,13 +247,13 @@ def parseNeededFitDetails(fit, groupID): 41, 52, 65, 67, 68, 71, 80, 201, 208, 291, 325, 379, 585, 842, 899, 1150, 1154, 1189, 1306, 1672, 1697, 1698, 1815, 1894 ] - projectedMods = filter(lambda mod: mod.item and mod.item.groupID in projectedModGroupIds, fit.modules) + projectedMods = list(filter(lambda mod: mod.item and mod.item.groupID in projectedModGroupIds, fit.modules)) unpropedSpeed = fit.maxSpeed unpropedSig = fit.ship.itemModifiedAttributes['signatureRadius'] usingMWD = False - propMods = filter(lambda mod: mod.item and mod.item.groupID in [46], fit.modules) - possibleMWD = filter(lambda mod: 'signatureRadiusBonus' in mod.item.attributes, propMods) + propMods = list(filter(lambda mod: mod.item and mod.item.groupID in [46], fit.modules)) + possibleMWD = list(filter(lambda mod: 'signatureRadiusBonus' in mod.item.attributes, propMods)) if len(possibleMWD) > 0 and possibleMWD[0].state > 0: mwd = possibleMWD[0] oldMwdState = mwd.state @@ -295,7 +291,7 @@ def parseNeededFitDetails(fit, groupID): fitL.recalc(fit) fit = eos.db.getFit(fitID) mwdPropSpeed = fit.maxSpeed - mwdPosition = filter(lambda mod: mod.item and mod.item.ID == propID, fit.modules)[0].position + mwdPosition = list(filter(lambda mod: mod.item and mod.item.ID == propID, fit.modules))[0].position fitL.removeModule(fitID, mwdPosition) fitL.recalc(fit) fit = eos.db.getFit(fitID) @@ -644,7 +640,22 @@ def parseNeededFitDetails(fit, groupID): #help(fit.fighters[0]) stringified = json.dumps(parsable, skipkeys=True) return stringified + +try: + armorLinkShip = eos.db.searchFits('armor links')[0] + infoLinkShip = eos.db.searchFits('information links')[0] + shieldLinkShip = eos.db.searchFits('shield links')[0] + skirmishLinkShip = eos.db.searchFits('skirmish links')[0] +except: + armorLinkShip = None + infoLinkShip = None + shieldLinkShip = None + skirmishLinkShip = None + def setFitFromString(dnaString, fitName, groupID) : + if armorLinkShip == None: + print('Cannot find correct link fits for base calculations') + return '' modArray = dnaString.split(':') additionalModeFit = '' #if groupID == 485 and len(modArray) == 1: @@ -685,7 +696,7 @@ def setFitFromString(dnaString, fitName, groupID) : # print('ssssssssssssssss' # nonEmptyModules.remove(None) for ammo in iter(ammoArray): - fitL.setAmmo(fitID, ammo, filter(lambda mod: str(mod).find('name') > 0, fit.modules)) + fitL.setAmmo(fitID, ammo, list(filter(lambda mod: str(mod).find('name') > 0, fit.modules))) if len(fit.drones) > 0: fit.drones[0].amountActive = fit.drones[0].amount eos.db.commit() @@ -697,7 +708,7 @@ def setFitFromString(dnaString, fitName, groupID) : abilityAltRef.active = True fitL.recalc(fit) fit = eos.db.getFit(fitID) - print(filter(lambda mod: mod.item.groupID in [1189, 658], fit.modules)) + print(list(filter(lambda mod: mod.item.groupID in [1189, 658], fit.modules))) #fit.calculateWeaponStats() fitL.addCommandFit(fit.ID, armorLinkShip) fitL.addCommandFit(fit.ID, shieldLinkShip) From 2a410a13a0567cf1ae4d2ce7793fd79767a74193 Mon Sep 17 00:00:00 2001 From: Maru Maru Date: Sun, 20 May 2018 04:36:20 -0400 Subject: [PATCH 10/32] EFS mass export now uses the configured save path for consistancy. --- effs_stat_export.py | 32 ++++++++++++-------------------- shipBaseJSON.js | 2 -- shipJSON.js | 2 -- 3 files changed, 12 insertions(+), 24 deletions(-) delete mode 100644 shipBaseJSON.js delete mode 100644 shipJSON.js diff --git a/effs_stat_export.py b/effs_stat_export.py index f45a4a65c..0b3836b93 100755 --- a/effs_stat_export.py +++ b/effs_stat_export.py @@ -92,10 +92,11 @@ eos.db.saveddata_meta.create_all() import json -def processExportedHtml(fileLocation): - output = open('./shipJSON.js', 'w') +def processExportedHtml(): + basePath = config.savePath + os.sep + output = open(basePath + 'shipJSON.js', 'w') output.write('let shipJSON = JSON.stringify([') - outputBaseline = open('./shipBaseJSON.js', 'w') + outputBaseline = open(basePath + 'shipBaseJSON.js', 'w') outputBaseline.write('let shipBaseJSON = JSON.stringify([') shipCata = eos.db.getItemsByCategory('Ship') #shipCata = eos.db.getItem(638) @@ -154,7 +155,7 @@ def processExportedHtml(fileLocation): print('Not a list of dicts') #print(vars(shipCata._sa_instance_state)) - baseLimit = 10 + baseLimit = 0 baseN = 0 nameReqBase = ''; for ship in iter(shipCata): @@ -164,7 +165,7 @@ def processExportedHtml(fileLocation): outputBaseline.write(stats) outputBaseline.write(',\n') baseN += 1; - limit = 100 + limit = 10 skipTill = 0 nameReq = '' n = 0 @@ -173,18 +174,12 @@ def processExportedHtml(fileLocation): fileLocation = 'pyfaFits.html' except: try: - with open('.pyfa/pyfaFits.html'): - fileLocation = '.pyfa/pyfaFits.html' + d = config.savePath + os.sep + 'pyfaFits.html' + print(d) + with open(d): + fileLocation = d except: - try: - with open('../.pyfa/pyfaFits.html'): - fileLocation = '../.pyfa/pyfaFits.html' - except: - try: - with open('../../.pyfa/pyfaFits.html'): - fileLocation = '../../.pyfa/pyfaFits.html' - except: - fileLocation = None; + fileLocation = None; fitList = eos.db.getFitList() with open(fileLocation) as f: for fit in fitList: @@ -724,7 +719,4 @@ launchUI = False #launchUI = True if launchUI == False: from service.fit import Fit - #setFitFromString(dnaChim, 'moMachsD') - #help(eos.db.getItem) - #ship = es_Ship(eos.db.getItem(27)) - processExportedHtml('../.pyfa/pyfaFits.html') + processExportedHtml() diff --git a/shipBaseJSON.js b/shipBaseJSON.js deleted file mode 100644 index 28b7228b2..000000000 --- a/shipBaseJSON.js +++ /dev/null @@ -1,2 +0,0 @@ -let shipBaseJSON = JSON.stringify([]); -export {shipBaseJSON}; \ No newline at end of file diff --git a/shipJSON.js b/shipJSON.js deleted file mode 100644 index 22c2ed09f..000000000 --- a/shipJSON.js +++ /dev/null @@ -1,2 +0,0 @@ -let shipJSON = JSON.stringify([]); -export {shipJSON}; \ No newline at end of file From 05e76a884ad879516feb308a82944f292b97139b Mon Sep 17 00:00:00 2001 From: Maru Maru Date: Sun, 27 May 2018 04:07:21 -0400 Subject: [PATCH 11/32] Partially cleaned up efs utilities --- effs_stat_export.py | 672 ++++++++------------------- savedata/effs_export_all_fits.py | 0 savedata/effs_export_base_fits.py | 247 ++++++++++ savedata/effs_export_pyfa_fits.py | 53 +++ savedata/effs_process_html_export.py | 60 +++ savedata/effs_util.py | 56 +++ 6 files changed, 614 insertions(+), 474 deletions(-) create mode 100644 savedata/effs_export_all_fits.py create mode 100644 savedata/effs_export_base_fits.py create mode 100644 savedata/effs_export_pyfa_fits.py create mode 100644 savedata/effs_process_html_export.py create mode 100644 savedata/effs_util.py diff --git a/effs_stat_export.py b/effs_stat_export.py index 0b3836b93..c89d0f781 100755 --- a/effs_stat_export.py +++ b/effs_stat_export.py @@ -4,249 +4,49 @@ import platform import re import sys import traceback -from optparse import AmbiguousOptionError, BadOptionError, OptionParser - -from logbook import CRITICAL, DEBUG, ERROR, FingersCrossedHandler, INFO, Logger, NestedSetup, NullHandler, StreamHandler, TimedRotatingFileHandler, WARNING, \ - __version__ as logbook_version - -import config - from math import log -try: - import wxversion -except ImportError: - wxversion = None - -try: - import sqlalchemy -except ImportError: - sqlalchemy = None - -pyfalog = Logger(__name__) - -class PassThroughOptionParser(OptionParser): - - def _process_args(self, largs, rargs, values): - while rargs: - try: - OptionParser._process_args(self, largs, rargs, values) - except (BadOptionError, AmbiguousOptionError) as e: - pyfalog.error("Bad startup option passed.") - largs.append(e.opt_str) - -usage = "usage: %prog [--root]" -parser = PassThroughOptionParser(usage=usage) -parser.add_option("-r", "--root", action="store_true", dest="rootsavedata", help="if you want pyfa to store its data in root folder, use this option", default=False) -parser.add_option("-w", "--wx28", action="store_true", dest="force28", help="Force usage of wxPython 2.8", default=False) -parser.add_option("-d", "--debug", action="store_true", dest="debug", help="Set logger to debug level.", default=False) -parser.add_option("-t", "--title", action="store", dest="title", help="Set Window Title", default=None) -parser.add_option("-s", "--savepath", action="store", dest="savepath", help="Set the folder for savedata", default=None) -parser.add_option("-l", "--logginglevel", action="store", dest="logginglevel", help="Set desired logging level [Critical|Error|Warning|Info|Debug]", default="Error") - -(options, args) = parser.parse_args() - -if options.rootsavedata is True: - config.saveInRoot = True - -# set title if it wasn't supplied by argument -if options.title is None: - options.title = "pyfa %s%s - Python Fitting Assistant" % (config.version, "" if config.tag.lower() != 'git' else " (git)") - -config.debug = options.debug - -# convert to unicode if it is set -if options.savepath is not None: - options.savepath = unicode(options.savepath) -config.defPaths(options.savepath) - -try: - # noinspection PyPackageRequirements - import wx -except: - exit_message = "Cannot import wxPython. You can download wxPython (2.8+) from http://www.wxpython.org/" - raise PreCheckException(exit_message) - -try: - import requests - config.requestsVersion = requests.__version__ -except ImportError: - raise PreCheckException("Cannot import requests. You can download requests from https://pypi.python.org/pypi/requests.") - import eos.db -#if config.saVersion[0] > 0 or config.saVersion[1] >= 7: - # <0.7 doesn't have support for events ;_; (mac-deprecated) -config.sa_events = True -import eos.events - - # noinspection PyUnresolvedReferences -import service.prefetch # noqa: F401 - - # Make sure the saveddata db exists -if not os.path.exists(config.savePath): - os.mkdir(config.savePath) - eos.db.saveddata_meta.create_all() - import json +from service.fit import Fit -def processExportedHtml(): - basePath = config.savePath + os.sep - output = open(basePath + 'shipJSON.js', 'w') - output.write('let shipJSON = JSON.stringify([') - outputBaseline = open(basePath + 'shipBaseJSON.js', 'w') - outputBaseline.write('let shipBaseJSON = JSON.stringify([') - shipCata = eos.db.getItemsByCategory('Ship') - #shipCata = eos.db.getItem(638) - #shipCata = eos.db.getMetaGroup(638) - #shipCata = eos.db.getAttributeInfo(638) - #shipCata = eos.db.getItemsByCategory('Traits') - #shipCata = eos.db.getGroup('invtraits') - #shipCata = eos.db.getCategory('Traits') - from sqlalchemy import Column, String, Integer, ForeignKey, Boolean, Table - from sqlalchemy.orm import relation, mapper, synonym, deferred - from eos.db import gamedata_session - from eos.db import gamedata_meta - from eos.db.gamedata.metaGroup import metatypes_table, items_table - from eos.db.gamedata.group import groups_table - - from eos.gamedata import AlphaClone, Attribute, Category, Group, Item, MarketGroup, \ - MetaGroup, AttributeInfo, MetaData, Effect, ItemEffect, Traits - from eos.db.gamedata.traits import traits_table - #shipCata = traits_table #categories_table - #print shipCata - #print shipCata.columns - #print shipCata.categoryName - #print vars(shipCata) - data = category = gamedata_session.query(Category).all() - #print data - #print iter(data) - eff = gamedata_session.query(Category).get(53) #Bonus (id14) #Effects (id 53) - data = eff; - #print eff - #print vars(eff) - things = []#[Category, MetaGroup, AttributeInfo, MetaData, Item, Attribute, Effect, ItemEffect, Traits]#, Attribute] - if False: - for dataTab in things : - print('Data for: ' + str(dataTab)) - try: - filter = dataTab.typeID == 638 - except: - filter = dataTab.ID == 638 - data = gamedata_session.query(dataTab).options().list(filter(filter).all()) - print(data) - try: - varDict = vars(data) - print(varDict) - except: - print('Not a Dict') - try: - varDict = data.__doc__ - print(varDict) - except: - print('No items()') - try: - for varDict in data: - print(varDict) - print(vars(varDict)) - except: - print('Not a list of dicts') - - #print(vars(shipCata._sa_instance_state)) - baseLimit = 0 - baseN = 0 - nameReqBase = ''; - for ship in iter(shipCata): - if baseN < baseLimit and nameReqBase in ship.name: - dna = str(ship.ID) - stats = setFitFromString(dna, ship.name, ship.groupID) - outputBaseline.write(stats) - outputBaseline.write(',\n') - baseN += 1; - limit = 10 - skipTill = 0 - nameReq = '' - n = 0 - try: - with open('pyfaFits.html'): - fileLocation = 'pyfaFits.html' - except: - try: - d = config.savePath + os.sep + 'pyfaFits.html' - print(d) - with open(d): - fileLocation = d - except: - fileLocation = None; - fitList = eos.db.getFitList() - with open(fileLocation) as f: - for fit in fitList: - if limit == None or n < limit: - n += 1 - name = fit.ship.name + ': ' + fit.name - if n >= skipTill and nameReq in name: - stats = parseNeededFitDetails(fit, 0) - output.write(stats) - output.write(',\n') - if False and fileLocation != None: - with open(fileLocation) as f: - for fullLine in f: - if limit == None or n < limit: - n += 1 - startInd = fullLine.find('/dna/') + 5 - line = fullLine[startInd:len(fullLine)] - endInd = line.find('::') - dna = line[0:endInd] - name = line[line.find('>') + 1:line.find('<')] - if n >= skipTill and nameReq in name: - print('name: ' + name + ' DNA: ' + dna) - stats = setFitFromString(dna, name, 0) - output.write(stats) - output.write(',\n') - output.write(']);\nexport {shipJSON};') - output.close() - outputBaseline.write(']);\nexport {shipBaseJSON};') - outputBaseline.close() def attrDirectMap(values, target, source): for val in values: target[val] = source.itemModifiedAttributes[val] -def parseNeededFitDetails(fit, groupID): - singleRunPrintPreformed = False - weaponSystems = [] - groups = {} - moduleNames = [] - fitID = fit.ID - if len(fit.modules) > 0: - fitName = fit.ship.name + ': ' + fit.name - else: - fitName = fit.name - print('') - print('name: ' + fit.name) - fitL = Fit() - fitL.recalc(fit) - fit = eos.db.getFit(fitID) - if False: - from eos.db import gamedata_session - from eos.gamedata import Group, Category - filterVal = Group.categoryID == 6 - data = gamedata_session.query(Group).options().list(filter(filterVal).all()) - for group in data: - print(group.groupName + ' groupID: ' + str(group.groupID)) - #print(group.categoryName + ' categoryID: ' + str(group.categoryID) + ', published: ' + str(group.published) - #print(vars(group) - #print('' - return '' - projectedModGroupIds = [ - 41, 52, 65, 67, 68, 71, 80, 201, 208, 291, 325, 379, 585, - 842, 899, 1150, 1154, 1189, 1306, 1672, 1697, 1698, 1815, 1894 - ] - projectedMods = list(filter(lambda mod: mod.item and mod.item.groupID in projectedModGroupIds, fit.modules)) - unpropedSpeed = fit.maxSpeed - unpropedSig = fit.ship.itemModifiedAttributes['signatureRadius'] - usingMWD = False +def getT2MwdSpeed(fit, fitL): + fitID = fit.ID + propID = None + rigSize = fit.ship.itemModifiedAttributes['rigSize'] + if rigSize == 1 and fit.ship.itemModifiedAttributes['medSlots'] > 0: + propID = 440 + elif rigSize == 2 and fit.ship.itemModifiedAttributes['medSlots'] > 0: + propID = 12076 + elif rigSize == 3 and fit.ship.itemModifiedAttributes['medSlots'] > 0: + propID = 12084 + elif rigSize == 4 and fit.ship.itemModifiedAttributes['medSlots'] > 0: + if fit.ship.itemModifiedAttributes['powerOutput'] > 60000: + propID = 41253 + else: + propID = 12084 + elif rigSize == None and fit.ship.itemModifiedAttributes['medSlots'] > 0: + propID = 440 + if propID: + fitL.appendModule(fitID, propID) + fitL.recalc(fit) + fit = eos.db.getFit(fitID) + mwdPropSpeed = fit.maxSpeed + mwdPosition = list(filter(lambda mod: mod.item and mod.item.ID == propID, fit.modules))[0].position + fitL.removeModule(fitID, mwdPosition) + fitL.recalc(fit) + fit = eos.db.getFit(fitID) + return mwdPropSpeed + +def getPropData(fit, fitL): + fitID = fit.ID propMods = list(filter(lambda mod: mod.item and mod.item.groupID in [46], fit.modules)) possibleMWD = list(filter(lambda mod: 'signatureRadiusBonus' in mod.item.attributes, propMods)) if len(possibleMWD) > 0 and possibleMWD[0].state > 0: @@ -255,42 +55,21 @@ def parseNeededFitDetails(fit, groupID): mwd.state = 0 fitL.recalc(fit) fit = eos.db.getFit(fitID) - unpropedSpeed = fit.maxSpeed - unpropedSig = fit.ship.itemModifiedAttributes['signatureRadius'] + sp = fit.maxSpeed + sig = fit.ship.itemModifiedAttributes['signatureRadius'] mwd.state = oldMwdState fitL.recalc(fit) fit = eos.db.getFit(fitID) - usingMWD = True - - print(fit.ship.itemModifiedAttributes['rigSize']) - print(propMods) - mwdPropSpeed = fit.maxSpeed - if groupID > 0: - propID = None - rigSize = fit.ship.itemModifiedAttributes['rigSize'] - if rigSize == 1 and fit.ship.itemModifiedAttributes['medSlots'] > 0: - propID = 440 - elif rigSize == 2 and fit.ship.itemModifiedAttributes['medSlots'] > 0: - propID = 12076 - elif rigSize == 3 and fit.ship.itemModifiedAttributes['medSlots'] > 0: - propID = 12084 - elif rigSize == 4 and fit.ship.itemModifiedAttributes['medSlots'] > 0: - if fit.ship.itemModifiedAttributes['powerOutput'] > 60000: - propID = 41253 - else: - propID = 12084 - elif rigSize == None and fit.ship.itemModifiedAttributes['medSlots'] > 0: - propID = 440 - if propID: - fitL.appendModule(fitID, propID) - fitL.recalc(fit) - fit = eos.db.getFit(fitID) - mwdPropSpeed = fit.maxSpeed - mwdPosition = list(filter(lambda mod: mod.item and mod.item.ID == propID, fit.modules))[0].position - fitL.removeModule(fitID, mwdPosition) - fitL.recalc(fit) - fit = eos.db.getFit(fitID) + return {'usingMWD': True, 'unpropedSpeed': sp, 'unpropedSig': sig} + return {'usingMWD': False, 'unpropedSpeed': fit.maxSpeed, 'unpropedSig': fit.ship.itemModifiedAttributes['signatureRadius']} +def getOutgoingProjectionData(fit): + # This is a subset of module groups capable of projection and a superset of those currently used by efs + projectedModGroupIds = [ + 41, 52, 65, 67, 68, 71, 80, 201, 208, 291, 325, 379, 585, + 842, 899, 1150, 1154, 1189, 1306, 1672, 1697, 1698, 1815, 1894 + ] + projectedMods = list(filter(lambda mod: mod.item and mod.item.groupID in projectedModGroupIds, fit.modules)) projections = [] for mod in projectedMods: stats = {} @@ -356,15 +135,10 @@ def parseNeededFitDetails(fit, groupID): stats['falloff'] = mod.itemModifiedAttributes['falloffEffectiveness'] or 0 attrDirectMap(['duration', 'capacitorNeed'], stats, mod) projections.append(stats) - #print('' - #print(stats - #print(mod.item.name - #print(mod.itemModifiedAttributes.items() - #print('' - #print(vars(mod.item) - #print(vars(web.itemModifiedAttributes) - #print(vars(fit.modules) - #print(vars(fit.modules[0]) + return projections + +def getModuleNames(fit): + moduleNames = [] highSlotNames = [] midSlotNames = [] lowSlotNames = [] @@ -393,12 +167,6 @@ def parseNeededFitDetails(fit, groupID): print(vars(mod)) print('could not find name for module') print(fit.modules) - if mod.dps > 0: - keystr = str(mod.itemID) + '-' + str(mod.chargeID) - if keystr in groups: - groups[keystr][1] += 1 - else: - groups[keystr] = [mod, 1] for modInfo in [['High Slots:'], highSlotNames, ['', 'Med Slots:'], midSlotNames, ['', 'Low Slots:'], lowSlotNames, ['', 'Rig Slots:'], rigSlotNames]: moduleNames.extend(modInfo) if len(miscSlotNames) > 0: @@ -409,10 +177,10 @@ def parseNeededFitDetails(fit, groupID): fighterNames = [] for drone in fit.drones: if drone.amountActive > 0: - droneNames.append(drone.item.name) + droneNames.append("%s x%s" % (drone.item.name, drone.amount)) for fighter in fit.fighters: if fighter.amountActive > 0: - fighterNames.append(fighter.item.name) + fighterNames.append("%s x%s" % (fighter.item.name, fighter.amountActive)) if len(droneNames) > 0: moduleNames.append('') moduleNames.append('Drones:') @@ -431,7 +199,18 @@ def parseNeededFitDetails(fit, groupID): moduleNames.append('Command Fits:') for commandFit in fit.commandFits: moduleNames.append(commandFit.name) + return moduleNames +def getWeaponSystemData(fit): + weaponSystems = [] + groups = {} + for mod in fit.modules: + if mod.dps > 0: + keystr = str(mod.itemID) + '-' + str(mod.chargeID) + if keystr in groups: + groups[keystr][1] += 1 + else: + groups[keystr] = [mod, 1] for wepGroup in groups: stats = groups[wepGroup][0] c = groups[wepGroup][1] @@ -507,216 +286,161 @@ def parseNeededFitDetails(fit, groupID): 'volley': fighter.dps[1], 'signatureRadius': fighter.itemModifiedAttributes['signatureRadius']\ } weaponSystems.append(statDict) - turretSlots = fit.ship.itemModifiedAttributes['turretSlotsLeft'] - launcherSlots = fit.ship.itemModifiedAttributes['launcherSlotsLeft'] - droneBandwidth = fit.ship.itemModifiedAttributes['droneBandwidth'] - if turretSlots == None: - turretSlots = 0 - if launcherSlots == None: - launcherSlots = 0 - if droneBandwidth == None: - droneBandwidth = 0 - effectiveTurretSlots = turretSlots - effectiveLauncherSlots = launcherSlots - effectiveDroneBandwidth = droneBandwidth + return weaponSystems + +def getWeaponBonusMultipliers(fit): + multipliers = {'turret': 1, 'launcher': 1, 'droneBandwidth': 1} from eos.db import gamedata_session from eos.gamedata import Traits filterVal = Traits.typeID == fit.shipID data = gamedata_session.query(Traits).options().filter(filterVal).all() roleBonusMode = False - if len(data) != 0: - #print(data[0].traitText - previousTypedBonus = 0 - previousDroneTypeBonus = 0 - for bonusText in data[0].traitText.splitlines(): - bonusText = bonusText.lower() - #print('bonus text line: ' + bonusText - if 'per skill level' in bonusText: - roleBonusMode = False - if 'role bonus' in bonusText or 'misc bonus' in bonusText: - roleBonusMode = True - multi = 1 - if 'damage' in bonusText and not any(e in bonusText for e in ['control', 'heat']):#'control' in bonusText and not 'heat' in bonusText: - splitText = bonusText.split('%') - if (float(splitText[0]) > 0) == False: - print('damage bonus split did not parse correctly!') - print(float(splitText[0])) - if roleBonusMode: - addedMulti = float(splitText[0]) + if len(data) == 0: + return multipliers + previousTypedBonus = 0 + previousDroneTypeBonus = 0 + for bonusText in data[0].traitText.splitlines(): + bonusText = bonusText.lower() + if 'per skill level' in bonusText: + roleBonusMode = False + if 'role bonus' in bonusText or 'misc bonus' in bonusText: + roleBonusMode = True + multi = 1 + if 'damage' in bonusText and not any(e in bonusText for e in ['control', 'heat']): + splitText = bonusText.split('%') + if (float(splitText[0]) > 0) == False: + print('damage bonus split did not parse correctly!') + print(float(splitText[0])) + if roleBonusMode: + addedMulti = float(splitText[0]) + else: + addedMulti = float(splitText[0]) * 5 + if any(e in bonusText for e in [' em', 'thermal', 'kinetic', 'explosive']): + if addedMulti > previousTypedBonus: + previousTypedBonus = addedMulti else: - addedMulti = float(splitText[0]) * 5 - if any(e in bonusText for e in [' em', 'thermal', 'kinetic', 'explosive']): - if addedMulti > previousTypedBonus: - previousTypedBonus = addedMulti - else: - addedMulti = 0 - if any(e in bonusText for e in ['heavy drone', 'medium drone', 'light drone', 'sentry drone']): - if addedMulti > previousDroneTypeBonus: - previousDroneTypeBonus = addedMulti - else: - addedMulti = 0 - multi = 1 + (addedMulti / 100) - elif 'rate of fire' in bonusText: - splitText = bonusText.split('%') - if (float(splitText[0]) > 0) == False: - print('rate of fire bonus split did not parse correctly!') - print(float(splitText[0])) - if roleBonusMode: - rofMulti = float(splitText[0]) + addedMulti = 0 + if any(e in bonusText for e in ['heavy drone', 'medium drone', 'light drone', 'sentry drone']): + if addedMulti > previousDroneTypeBonus: + previousDroneTypeBonus = addedMulti else: - rofMulti = float(splitText[0]) * 5 - multi = 1 / (1 - (rofMulti / 100)) - if multi > 1: - if 'drone' in bonusText.lower(): - effectiveDroneBandwidth *= multi - elif 'turret' in bonusText.lower(): - effectiveTurretSlots *= multi - elif any(e in bonusText for e in ['missile', 'torpedo']): - effectiveLauncherSlots *= multi + addedMulti = 0 + multi = 1 + (addedMulti / 100) + elif 'rate of fire' in bonusText: + splitText = bonusText.split('%') + if (float(splitText[0]) > 0) == False: + print('rate of fire bonus split did not parse correctly!') + print(float(splitText[0])) + if roleBonusMode: + rofMulti = float(splitText[0]) + else: + rofMulti = float(splitText[0]) * 5 + multi = 1 / (1 - (rofMulti / 100)) + if multi > 1: + if 'drone' in bonusText.lower(): + multipliers['droneBandwidth'] *= multi + elif 'turret' in bonusText.lower(): + multipliers['turret'] *= multi + elif any(e in bonusText for e in ['missile', 'torpedo']): + multipliers['launcher'] *= multi + return multipliers +def getShipSize(groupID): + # Sizings are somewhat arbitrary but allow for a more managable number of top level groupings in a tree structure. + shipSizes = ['Frigate', 'Destroyer', 'Cruiser', 'Battlecruiser', 'Battleship', 'Capital', 'Industrial', 'Misc'] + if groupID in [25, 31, 237, 324, 830, 831, 834, 893, 1283, 1527]: + return shipSizes[0] + elif groupID in [420, 541, 1305, 1534]: + return shipSizes[1] + elif groupID in [26, 358, 832, 833, 894, 906, 963]: + return shipSizes[2] + elif groupID in [419, 540, 1201]: + return shipSizes[3] + elif groupID in [27, 381, 898, 900]: + return shipSizes[4] + elif groupID in [30, 485, 513, 547, 659, 883, 902, 1538]: + return shipSizes[5] + elif groupID in [28, 380, 1202, 463, 543, 941]: + return shipSizes[6] + elif groupID in [29, 1022]: + return shipSizes[7] + else: + sizeNotFoundMsg = 'ShipSize not found for groupID: ' + str(groupID) + print(sizeNotFoundMsg) + return sizeNotFoundMsg + +def parseNeededFitDetails(fit, groupID): + includeShipTypeData = groupID > 0 + fitID = fit.ID + if len(fit.modules) > 0: + fitName = fit.ship.name + ': ' + fit.name + else: + fitName = fit.name + print('') + print('name: ' + fit.name) + fitL = Fit() + fitL.recalc(fit) + fit = eos.db.getFit(fitID) + fitModAttr = fit.ship.itemModifiedAttributes + propData = getPropData(fit, fitL) + print(fitModAttr['rigSize']) + print(propData) + mwdPropSpeed = fit.maxSpeed + if includeShipTypeData: + mwdPropSpeed = getT2MwdSpeed(fit, fitL) + projections = getOutgoingProjectionData(fit) + moduleNames = getModuleNames(fit) + weaponSystems = getWeaponSystemData(fit) + + turretSlots = fitModAttr['turretSlotsLeft'] if fitModAttr['turretSlotsLeft'] is not None else 0 + launcherSlots = fitModAttr['launcherSlotsLeft'] if fitModAttr['launcherSlotsLeft'] is not None else 0 + droneBandwidth = fitModAttr['droneBandwidth'] if fitModAttr['droneBandwidth'] is not None else 0 + weaponBonusMultipliers = getWeaponBonusMultipliers(fit) + effectiveTurretSlots = round(turretSlots * weaponBonusMultipliers['turret'], 2); + effectiveLauncherSlots = round(launcherSlots * weaponBonusMultipliers['launcher'], 2); + effectiveDroneBandwidth = round(droneBandwidth * weaponBonusMultipliers['droneBandwidth'], 2); + # Assume a T2 siege module for dreads if groupID == 485: effectiveTurretSlots *= 9.4 effectiveLauncherSlots *= 15 - effectiveTurretSlots = round(effectiveTurretSlots, 2); - effectiveLauncherSlots = round(effectiveLauncherSlots, 2); - effectiveDroneBandwidth = round(effectiveDroneBandwidth, 2); - hullResonance = {'exp': fit.ship.itemModifiedAttributes['explosiveDamageResonance'], 'kin': fit.ship.itemModifiedAttributes['kineticDamageResonance'], \ - 'therm': fit.ship.itemModifiedAttributes['thermalDamageResonance'], 'em': fit.ship.itemModifiedAttributes['emDamageResonance']} - armorResonance = {'exp': fit.ship.itemModifiedAttributes['armorExplosiveDamageResonance'], 'kin': fit.ship.itemModifiedAttributes['armorKineticDamageResonance'], \ - 'therm': fit.ship.itemModifiedAttributes['armorThermalDamageResonance'], 'em': fit.ship.itemModifiedAttributes['armorEmDamageResonance']} - shieldResonance = {'exp': fit.ship.itemModifiedAttributes['shieldExplosiveDamageResonance'], 'kin': fit.ship.itemModifiedAttributes['shieldKineticDamageResonance'], \ - 'therm': fit.ship.itemModifiedAttributes['shieldThermalDamageResonance'], 'em': fit.ship.itemModifiedAttributes['shieldEmDamageResonance']} + hullResonance = { + 'exp': fitModAttr['explosiveDamageResonance'], 'kin': fitModAttr['kineticDamageResonance'], \ + 'therm': fitModAttr['thermalDamageResonance'], 'em': fitModAttr['emDamageResonance'] + } + armorResonance = { + 'exp': fitModAttr['armorExplosiveDamageResonance'], 'kin': fitModAttr['armorKineticDamageResonance'], \ + 'therm': fitModAttr['armorThermalDamageResonance'], 'em': fitModAttr['armorEmDamageResonance'] + } + shieldResonance = { + 'exp': fitModAttr['shieldExplosiveDamageResonance'], 'kin': fitModAttr['shieldKineticDamageResonance'], \ + 'therm': fitModAttr['shieldThermalDamageResonance'], 'em': fitModAttr['shieldEmDamageResonance'] + } resonance = {'hull': hullResonance, 'armor': armorResonance, 'shield': shieldResonance} - shipSizes = ['Frigate', 'Destroyer', 'Cruiser', 'Battlecruiser', 'Battleship', 'Capital', 'Industrial', 'Misc'] - if groupID in [25, 31, 237, 324, 830, 831, 834, 893, 1283, 1527]: - shipSize = shipSizes[0] - elif groupID in [420, 541, 1305, 1534]: - shipSize = shipSizes[1] - elif groupID in [26, 358, 832, 833, 894, 906, 963]: - shipSize = shipSizes[2] - elif groupID in [419, 540, 1201]: - shipSize = shipSizes[3] - elif groupID in [27, 381, 898, 900]: - shipSize = shipSizes[4] - elif groupID in [30, 485, 513, 547, 659, 883, 902, 1538]: - shipSize = shipSizes[5] - elif groupID in [28, 380, 1202, 463, 543, 941]: - shipSize = shipSizes[6] - elif groupID in [29, 1022]: - shipSize = shipSizes[7] - else: - shipSize = 'ShipSize not found for ' + fitName + ' groupID: ' + str(groupID) - print(shipSize) + shipSize = getShipSize(groupID) + try: - parsable = {'name': fitName, 'ehp': fit.ehp, 'droneDPS': fit.droneDPS, \ - 'droneVolley': fit.droneVolley, 'hp': fit.hp, 'maxTargets': fit.maxTargets, \ - 'maxSpeed': fit.maxSpeed, 'weaponVolley': fit.weaponVolley, 'totalVolley': fit.totalVolley,\ - 'maxTargetRange': fit.maxTargetRange, 'scanStrength': fit.scanStrength,\ - 'weaponDPS': fit.weaponDPS, 'alignTime': fit.alignTime, 'signatureRadius': fit.ship.itemModifiedAttributes['signatureRadius'],\ - 'weapons': weaponSystems, 'scanRes': fit.ship.itemModifiedAttributes['scanResolution'],\ - 'projectedModules': fit.projectedModules, 'capUsed': fit.capUsed, 'capRecharge': fit.capRecharge,\ - 'rigSlots': fit.ship.itemModifiedAttributes['rigSlots'], 'lowSlots': fit.ship.itemModifiedAttributes['lowSlots'],\ - 'midSlots': fit.ship.itemModifiedAttributes['medSlots'], 'highSlots': fit.ship.itemModifiedAttributes['hiSlots'],\ - 'turretSlots': fit.ship.itemModifiedAttributes['turretSlotsLeft'], 'launcherSlots': fit.ship.itemModifiedAttributes['launcherSlotsLeft'],\ - 'powerOutput': fit.ship.itemModifiedAttributes['powerOutput'], 'rigSize': fit.ship.itemModifiedAttributes['rigSize'],\ - 'effectiveTurrets': effectiveTurretSlots, 'effectiveLaunchers': effectiveLauncherSlots, 'effectiveDroneBandwidth': effectiveDroneBandwidth,\ - 'resonance': resonance, 'typeID': fit.shipID, 'groupID': groupID, 'shipSize': shipSize,\ - 'droneControlRange': fit.ship.itemModifiedAttributes['droneControlRange'], 'mass': fit.ship.itemModifiedAttributes['mass'],\ - 'moduleNames': moduleNames, 'projections': projections, 'unpropedSpeed': unpropedSpeed, 'unpropedSig': unpropedSig,\ - 'usingMWD': usingMWD, 'mwdPropSpeed': mwdPropSpeed + parsable = { + 'name': fitName, 'ehp': fit.ehp, 'droneDPS': fit.droneDPS, \ + 'droneVolley': fit.droneVolley, 'hp': fit.hp, 'maxTargets': fit.maxTargets, \ + 'maxSpeed': fit.maxSpeed, 'weaponVolley': fit.weaponVolley, 'totalVolley': fit.totalVolley,\ + 'maxTargetRange': fit.maxTargetRange, 'scanStrength': fit.scanStrength,\ + 'weaponDPS': fit.weaponDPS, 'alignTime': fit.alignTime, 'signatureRadius': fitModAttr['signatureRadius'],\ + 'weapons': weaponSystems, 'scanRes': fitModAttr['scanResolution'],\ + 'projectedModules': fit.projectedModules, 'capUsed': fit.capUsed, 'capRecharge': fit.capRecharge,\ + 'rigSlots': fitModAttr['rigSlots'], 'lowSlots': fitModAttr['lowSlots'],\ + 'midSlots': fitModAttr['medSlots'], 'highSlots': fitModAttr['hiSlots'],\ + 'turretSlots': fitModAttr['turretSlotsLeft'], 'launcherSlots': fitModAttr['launcherSlotsLeft'],\ + 'powerOutput': fitModAttr['powerOutput'], 'rigSize': fitModAttr['rigSize'],\ + 'effectiveTurrets': effectiveTurretSlots, 'effectiveLaunchers': effectiveLauncherSlots,\ + 'effectiveDroneBandwidth': effectiveDroneBandwidth,\ + 'resonance': resonance, 'typeID': fit.shipID, 'groupID': groupID, 'shipSize': shipSize,\ + 'droneControlRange': fitModAttr['droneControlRange'], 'mass': fitModAttr['mass'],\ + 'moduleNames': moduleNames, 'projections': projections,\ + 'unpropedSpeed': propData['unpropedSpeed'], 'unpropedSig': propData['unpropedSig'],\ + 'usingMWD': propData['usingMWD'], 'mwdPropSpeed': mwdPropSpeed } except TypeError: print('Error parsing fit:' + str(fit)) print(TypeError) parsable = {'name': fitName + 'Fit could not be correctly parsed'} - #print(fit.ship.itemModifiedAttributes.items() - #help(fit) - #if len(fit.fighters) > 5: - #print(fit.fighters - #help(fit.fighters[0]) stringified = json.dumps(parsable, skipkeys=True) return stringified - -try: - armorLinkShip = eos.db.searchFits('armor links')[0] - infoLinkShip = eos.db.searchFits('information links')[0] - shieldLinkShip = eos.db.searchFits('shield links')[0] - skirmishLinkShip = eos.db.searchFits('skirmish links')[0] -except: - armorLinkShip = None - infoLinkShip = None - shieldLinkShip = None - skirmishLinkShip = None - -def setFitFromString(dnaString, fitName, groupID) : - if armorLinkShip == None: - print('Cannot find correct link fits for base calculations') - return '' - modArray = dnaString.split(':') - additionalModeFit = '' - #if groupID == 485 and len(modArray) == 1: - #additionalModeFit = ',\n' + setFitFromString(dnaString + ':4292', fitName + ' (Sieged)', groupID) - fitL = Fit() - print(modArray[0]) - fitID = fitL.newFit(int(modArray[0]), fitName) - fit = eos.db.getFit(fitID) - ammoArray = [] - n = -1 - for mod in iter(modArray): - n = n + 1 - if n > 0: - #print(n - #print(mod - modSp = mod.split(';') - if len(modSp) == 2: - k = 0 - while k < int(modSp[1]): - k = k + 1 - itemID = int(modSp[0]) - item = eos.db.getItem(int(modSp[0]), eager=("attributes", "group.category")) - cat = item.category.name - if cat == 'Drone': - fitL.addDrone(fitID, itemID, int(modSp[1]), recalc=False) - k += int(modSp[1]) - if cat == 'Fighter': - fitL.addFighter(fitID, itemID, recalc=False) - #fit.fighters.last.abilities.active = True - k += 100 - if fitL.isAmmo(int(modSp[0])): - k += 100 - ammoArray.append(int(modSp[0])); - fitL.appendModule(fitID, int(modSp[0])) - fit = eos.db.getFit(fitID) - #nonEmptyModules = fit.modules - #while nonEmptyModules.find(None) >= 0: - # print('ssssssssssssssss' - # nonEmptyModules.remove(None) - for ammo in iter(ammoArray): - fitL.setAmmo(fitID, ammo, list(filter(lambda mod: str(mod).find('name') > 0, fit.modules))) - if len(fit.drones) > 0: - fit.drones[0].amountActive = fit.drones[0].amount - eos.db.commit() - for fighter in iter(fit.fighters): - for ability in fighter.abilities: - if ability.effect.handlerName == u'fighterabilityattackm' and ability.active == True: - for abilityAltRef in fighter.abilities: - if abilityAltRef.effect.isImplemented: - abilityAltRef.active = True - fitL.recalc(fit) - fit = eos.db.getFit(fitID) - print(list(filter(lambda mod: mod.item.groupID in [1189, 658], fit.modules))) - #fit.calculateWeaponStats() - fitL.addCommandFit(fit.ID, armorLinkShip) - fitL.addCommandFit(fit.ID, shieldLinkShip) - fitL.addCommandFit(fit.ID, skirmishLinkShip) - fitL.addCommandFit(fit.ID, infoLinkShip) - #def anonfunc(unusedArg): True - jsonStr = parseNeededFitDetails(fit, groupID) - #print(vars(fit.ship._Ship__item) - #help(fit) - Fit.deleteFit(fitID) - return jsonStr + additionalModeFit -launchUI = False -#launchUI = True -if launchUI == False: - from service.fit import Fit - processExportedHtml() diff --git a/savedata/effs_export_all_fits.py b/savedata/effs_export_all_fits.py new file mode 100644 index 000000000..e69de29bb diff --git a/savedata/effs_export_base_fits.py b/savedata/effs_export_base_fits.py new file mode 100644 index 000000000..e1be23e3b --- /dev/null +++ b/savedata/effs_export_base_fits.py @@ -0,0 +1,247 @@ +import inspect +import os +import platform +import re +import sys +import traceback +from optparse import AmbiguousOptionError, BadOptionError, OptionParser + +from logbook import CRITICAL, DEBUG, ERROR, FingersCrossedHandler, INFO, Logger, NestedSetup, NullHandler, StreamHandler, TimedRotatingFileHandler, WARNING, \ + __version__ as logbook_version + +sys.path.append(os.getcwd()) +import config + +from math import log + +try: + import wxversion +except ImportError: + wxversion = None + +try: + import sqlalchemy +except ImportError: + sqlalchemy = None + +pyfalog = Logger(__name__) + +class PassThroughOptionParser(OptionParser): + + def _process_args(self, largs, rargs, values): + while rargs: + try: + OptionParser._process_args(self, largs, rargs, values) + except (BadOptionError, AmbiguousOptionError) as e: + pyfalog.error("Bad startup option passed.") + largs.append(e.opt_str) + +usage = "usage: %prog [--root]" +parser = PassThroughOptionParser(usage=usage) +parser.add_option("-r", "--root", action="store_true", dest="rootsavedata", help="if you want pyfa to store its data in root folder, use this option", default=False) +parser.add_option("-w", "--wx28", action="store_true", dest="force28", help="Force usage of wxPython 2.8", default=False) +parser.add_option("-d", "--debug", action="store_true", dest="debug", help="Set logger to debug level.", default=False) +parser.add_option("-t", "--title", action="store", dest="title", help="Set Window Title", default=None) +parser.add_option("-s", "--savepath", action="store", dest="savepath", help="Set the folder for savedata", default=None) +parser.add_option("-l", "--logginglevel", action="store", dest="logginglevel", help="Set desired logging level [Critical|Error|Warning|Info|Debug]", default="Error") + +(options, args) = parser.parse_args() + +if options.rootsavedata is True: + config.saveInRoot = True + +config.debug = options.debug + +config.defPaths(options.savepath) + +try: + import requests + config.requestsVersion = requests.__version__ +except ImportError: + raise PreCheckException("Cannot import requests. You can download requests from https://pypi.python.org/pypi/requests.") + +import eos.db + +#if config.saVersion[0] > 0 or config.saVersion[1] >= 7: + # <0.7 doesn't have support for events ;_; (mac-deprecated) +config.sa_events = True +import eos.events + + # noinspection PyUnresolvedReferences +import service.prefetch # noqa: F401 + + # Make sure the saveddata db exists +if not os.path.exists(config.savePath): + os.mkdir(config.savePath) + +eos.db.saveddata_meta.create_all() + +import json +from service.fit import Fit +from effs_stat_export import parseNeededFitDetails + +from sqlalchemy import Column, String, Integer, ForeignKey, Boolean, Table +from sqlalchemy.orm import relation, mapper, synonym, deferred +from eos.db import gamedata_session +from eos.db import gamedata_meta +from eos.db.gamedata.metaGroup import metatypes_table, items_table +from eos.db.gamedata.group import groups_table + +from eos.gamedata import AlphaClone, Attribute, Category, Group, Item, MarketGroup, \ + MetaGroup, AttributeInfo, MetaData, Effect, ItemEffect, Traits +from eos.db.gamedata.traits import traits_table +from eos.saveddata.mode import Mode + +def exportBaseShips(opts): + if opts: + if opts.outputpath: + basePath = opts.outputpath + elif opts.savepath: + basePath = opts.savepath + else: + basePath = config.savePath + os.sep + else: + basePath = config.savePath + os.sep + if basePath[len(basePath) - 1] != os.sep: + basePath = basePath + os.sep + outputBaseline = open(basePath + 'shipBaseJSON.js', 'w') + outputBaseline.write('let shipBaseJSON = JSON.stringify([') + shipCata = eos.db.getItemsByCategory('Ship') + baseLimit = 1000 + baseN = 0 + nameReqBase = ''; + for ship in iter(shipCata): + if baseN < baseLimit and nameReqBase in ship.name: + print(ship.name) + print(ship.groupID) + dna = str(ship.ID) + if ship.groupID == 963: + stats = t3cGetStatSet(dna, ship.name, ship.groupID, ship.raceID) + elif ship.groupID == 1305: + stats = t3dGetStatSet(dna, ship.name, ship.groupID, ship.raceID) + else: + stats = setFitFromString(dna, ship.name, ship.groupID) + outputBaseline.write(stats) + outputBaseline.write(',\n') + baseN += 1 + outputBaseline.write(']);\nexport {shipBaseJSON};') + outputBaseline.close() + +def t3dGetStatSet(dnaString, shipName, groupID, raceID): + t3dModeGroupFilter = Group.groupID == 1306 + data = list(gamedata_session.query(Group).options().filter(t3dModeGroupFilter).all()) + #Normally we would filter this via the raceID, + #Unfortunately somebody fat fingered the Jackdaw modes raceIDs as 4 (Amarr) not 1 (Caldari) + # t3dModes = list(filter(lambda mode: mode.raceID == raceID, data[0].items)) #Line for if/when they fix it + t3dModes = list(filter(lambda mode: shipName in mode.name, data[0].items)) + shipModeData = '' + n = 0 + while n < len(t3dModes): + dna = dnaString + ':' + str(t3dModes[n].ID) + ';1' + shipModeData += setFitFromString(dna, t3dModes[n].name, groupID) + ',\n' + n += 1 + return shipModeData + +def t3cGetStatSet(dnaString, shipName, groupID, raceID): + subsystemFilter = Group.categoryID == 32 + data = list(gamedata_session.query(Group).options().filter(subsystemFilter).all()) + # multi dimension array to hold the t3c subsystems as ss[index of subsystem type][index subsystem item] + ss = [[], [], [], []] + s = 0 + while s < 4: + ss[s] = list(filter(lambda subsystem: subsystem.raceID == raceID, data[s].items)) + s += 1 + print(shipName) + print(ss) + shipPermutationData = '' + n = 0 + a = 0 + while a < 3: + b = 0 + while b < 3: + c = 0 + while c < 3: + d = 0 + while d < 3: + dna = dnaString + ':' + str(ss[0][a].ID) \ + + ';1:' + str(ss[1][b].ID) + ';1:' + str(ss[2][c].ID) \ + + ';1:' + str(ss[3][d].ID) + ';1' + name = shipName + str(a) + str(b) + str(c) + str(d) + shipPermutationData += setFitFromString(dna, name, groupID) + ',\n' + d += 1 + n += 1 + c += 1 + b += 1 + a += 1 + print(str(n) + ' subsystem conbinations for ' + shipName) + return shipPermutationData +try: + armorLinkShip = eos.db.searchFits('armor links')[0] + infoLinkShip = eos.db.searchFits('information links')[0] + shieldLinkShip = eos.db.searchFits('shield links')[0] + skirmishLinkShip = eos.db.searchFits('skirmish links')[0] +except: + armorLinkShip = None + infoLinkShip = None + shieldLinkShip = None + skirmishLinkShip = None + +def setFitFromString(dnaString, fitName, groupID) : + if armorLinkShip == None: + print('Cannot find correct link fits for base calculations') + return '' + modArray = dnaString.split(':') + additionalModeFit = '' + fitL = Fit() + fitID = fitL.newFit(int(modArray[0]), fitName) + fit = eos.db.getFit(fitID) + ammoArray = [] + n = -1 + for mod in iter(modArray): + n = n + 1 + if n > 0: + modSp = mod.split(';') + if len(modSp) == 2: + k = 0 + while k < int(modSp[1]): + k = k + 1 + itemID = int(modSp[0]) + item = eos.db.getItem(int(modSp[0]), eager=("attributes", "group.category")) + cat = item.category.name + print(cat) + if cat == 'Drone': + fitL.addDrone(fitID, itemID, int(modSp[1]), recalc=False) + k += int(modSp[1]) + if cat == 'Fighter': + fitL.addFighter(fitID, itemID, recalc=False) + k += 100 + if fitL.isAmmo(int(modSp[0])): + k += 100 + ammoArray.append(int(modSp[0])); + # Set mode if module is a mode on a t3d + if item.groupID == 1306 and groupID == 1305: + fitL.setMode(fitID, Mode(item)) + else: + fitL.appendModule(fitID, int(modSp[0])) + fit = eos.db.getFit(fitID) + for ammo in iter(ammoArray): + fitL.setAmmo(fitID, ammo, list(filter(lambda mod: str(mod).find('name') > 0, fit.modules))) + if len(fit.drones) > 0: + fit.drones[0].amountActive = fit.drones[0].amount + eos.db.commit() + for fighter in iter(fit.fighters): + for ability in fighter.abilities: + if ability.effect.handlerName == u'fighterabilityattackm' and ability.active == True: + for abilityAltRef in fighter.abilities: + if abilityAltRef.effect.isImplemented: + abilityAltRef.active = True + fitL.recalc(fit) + fit = eos.db.getFit(fitID) + print(list(filter(lambda mod: mod.item and mod.item.groupID in [1189, 658], fit.modules))) + fitL.addCommandFit(fit.ID, armorLinkShip) + fitL.addCommandFit(fit.ID, shieldLinkShip) + fitL.addCommandFit(fit.ID, skirmishLinkShip) + fitL.addCommandFit(fit.ID, infoLinkShip) + jsonStr = parseNeededFitDetails(fit, groupID) + Fit.deleteFit(fitID) + return jsonStr + additionalModeFit diff --git a/savedata/effs_export_pyfa_fits.py b/savedata/effs_export_pyfa_fits.py new file mode 100644 index 000000000..f49cc0971 --- /dev/null +++ b/savedata/effs_export_pyfa_fits.py @@ -0,0 +1,53 @@ +import inspect +import os +import platform +import re +import sys +import traceback + +sys.path.append(os.getcwd()) +import config +from pyfa import options + +if options.rootsavedata is True: + config.saveInRoot = True +config.debug = options.debug +config.defPaths(options.savepath) + +import eos.db +# Make sure the saveddata db exists +if not os.path.exists(config.savePath): + os.mkdir(config.savePath) + +from effs_stat_export import parseNeededFitDetails + +def exportPyfaFits(opts): + if opts: + if opts.outputpath: + basePath = opts.outputpath + elif opts.savepath: + basePath = opts.savepath + else: + basePath = config.savePath + os.sep + else: + basePath = config.savePath + os.sep + if basePath[len(basePath) - 1] != os.sep: + basePath = basePath + os.sep + output = open(basePath + 'shipJSON.js', 'w') + output.write('let shipJSON = JSON.stringify([') + #The current storage system isn't going to hold more than 2500 fits as local browser storage is limited + limit = 2500 + skipTill = 0 + nameReq = '' + n = 0 + fitList = eos.db.getFitList() + for fit in fitList: + if limit == None or n < limit: + n += 1 + name = fit.ship.name + ': ' + fit.name + if n >= skipTill and nameReq in name: + stats = parseNeededFitDetails(fit, 0) + output.write(stats) + output.write(',\n') + output.write(']);\nexport {shipJSON};') + output.close() diff --git a/savedata/effs_process_html_export.py b/savedata/effs_process_html_export.py new file mode 100644 index 000000000..5d89a4547 --- /dev/null +++ b/savedata/effs_process_html_export.py @@ -0,0 +1,60 @@ +from effs_export_base_fits import * + +def effsFitsFromHTMLExport(opts): + if opts: + if opts.outputpath: + basePath = opts.outputpath + elif opts.savepath: + basePath = opts.savepath + else: + basePath = config.savePath + os.sep + else: + basePath = config.savePath + os.sep + if basePath[len(basePath) - 1] != os.sep: + basePath = basePath + os.sep + output = open(basePath + 'shipJSON.js', 'w') + output.write('let shipJSON = JSON.stringify([') + try: + with open('pyfaFits.html'): + fileLocation = 'pyfaFits.html' + except: + try: + d = config.savePath + os.sep + 'pyfaFits.html' + print(d) + with open(d): + fileLocation = d + except: + fileLocation = None; + limit = 10000 + n = 0 + skipTill = 0 + nameReq = '' + minimalExport = True + if fileLocation != None: + with open(fileLocation) as f: + for fullLine in f: + if limit == None or n < limit: + if n <= 1 and '' in fullLine: + minimalExport = False + n += 1 + fullIndex = fullLine.find('data-dna="') + minimalIndex = fullLine.find('/dna/') + if fullIndex >= 0: + startInd = fullLine.find('data-dna="') + 10 + elif minimalIndex >= 0 and minimalExport: + startInd = fullLine.find('/dna/') + 5 + else: + startInd = -1 + print(startInd) + if startInd >= 0: + line = fullLine[startInd:len(fullLine)] + endInd = line.find('::') + dna = line[0:endInd] + name = line[line.find('>') + 1:line.find('<')] + if n >= skipTill and nameReq in name: + print('name: ' + name + ' DNA: ' + dna + fullLine) + stats = setFitFromString(dna, name, 0) + output.write(stats) + output.write(',\n') + output.write(']);\nexport {shipJSON};') + output.close() diff --git a/savedata/effs_util.py b/savedata/effs_util.py new file mode 100644 index 000000000..1b77238f8 --- /dev/null +++ b/savedata/effs_util.py @@ -0,0 +1,56 @@ +from optparse import AmbiguousOptionError, BadOptionError, OptionParser + +class PassThroughOptionParser(OptionParser): + + def _process_args(self, largs, rargs, values): + while rargs: + try: + OptionParser._process_args(self, largs, rargs, values) + except (BadOptionError, AmbiguousOptionError) as e: + pyfalog.error("Bad startup option passed.") + largs.append(e.opt_str) + +usage = "usage: %prog [options]" +parser = PassThroughOptionParser(usage=usage) +parser.add_option( + "-f", "--exportfits", action="store_true", dest="exportfits", \ + help="Export this copy of pyfa's local fits to a shipJSON file that Eve Fleet Simulator can import from", \ + default=False) +parser.add_option( + "-b", "--exportbaseships", action="store_true", dest="exportbaseships", \ + help="Export ship stats to a shipBaseJSON file used by Eve Fleet Simulator", \ + default=False) +parser.add_option( + "-c", "--convertfitsfromhtml", action="store_true", dest="convertfitsfromhtml", \ + help="Convert an exported pyfaFits.html file to a shipJSON file that Eve Fleet Simulator can import from\n" + + " Note this process loses data like fleet boosters as the DNA format exported by to html contains limited data", \ + default=False) +parser.add_option("-s", "--savepath", action="store", dest="savepath", help="Set the folder for savedata", default=None) +parser.add_option( + "-o", "--outputpath", action="store", dest="outputpath", + help="Output directory, defaults to the savepath", default=None) + + +(options, args) = parser.parse_args() + +if options.exportfits: + from effs_export_pyfa_fits import exportPyfaFits + exportPyfaFits(options) + +if options.exportbaseships: + from effs_export_base_fits import exportBaseShips + exportBaseShips(options) + +if options.convertfitsfromhtml: + from effs_process_html_export import effsFitsFromHTMLExport + effsFitsFromHTMLExport(options) + +#stuff bellow this point is purely scrap diagnostic stuff and should not be public (as it's scrawl) +def printGroupData(): + from eos.db import gamedata_session + from eos.gamedata import Group, Category + filterVal = Group.categoryID == 6 + data = gamedata_session.query(Group).options().list(filter(filterVal).all()) + for group in data: + print(group.groupName + ' groupID: ' + str(group.groupID)) + return '' From d61ab0ff5a5498ffdc3a930e11458eddef318e49 Mon Sep 17 00:00:00 2001 From: Maru Maru Date: Sat, 16 Jun 2018 04:50:55 -0400 Subject: [PATCH 12/32] Refactoring for various EFS export code --- effs_stat_export.py | 592 +++++++++++------- eos/effects/shipdronescoutthermaldamagegf2.py | 2 +- savedata/effs_export_base_fits.py | 6 +- savedata/effs_export_pyfa_fits.py | 4 +- savedata/effs_util.py | 158 ++++- savedata/getmods.py | 88 +++ savedata/makeAndDiffCheck.sh | 55 ++ 7 files changed, 689 insertions(+), 216 deletions(-) create mode 100644 savedata/getmods.py create mode 100755 savedata/makeAndDiffCheck.sh diff --git a/effs_stat_export.py b/effs_stat_export.py index c89d0f781..e723f5485 100755 --- a/effs_stat_export.py +++ b/effs_stat_export.py @@ -8,126 +8,174 @@ from math import log import eos.db -eos.db.saveddata_meta.create_all() - import json from service.fit import Fit +from service.market import Market +from eos.enum import Enum +from eos.saveddata.module import Hardpoint, Slot, Module +from eos.saveddata.drone import Drone +from eos.effectHandlerHelpers import HandledList +from eos.db import gamedata_session, getItemsByCategory, getCategory, getAttributeInfo, getGroup +from eos.gamedata import Category, Group, Item, Traits, Attribute, Effect, ItemEffect + +eos.db.saveddata_meta.create_all() + + +class RigSize(Enum): + # Matches to item attribute 'rigSize' on ship and rig items + SMALL = 1 + MEDIUM = 2 + LARGE = 3 + CAPITAL = 4 + def attrDirectMap(values, target, source): for val in values: target[val] = source.itemModifiedAttributes[val] + def getT2MwdSpeed(fit, fitL): fitID = fit.ID propID = None + shipHasMedSlots = fit.ship.itemModifiedAttributes['medSlots'] > 0 + shipPower = fit.ship.itemModifiedAttributes['powerOutput'] + # Monitors have a 99% reduction to prop mod power requirements + if fit.ship.name == 'Monitor': + shipPower *= 100 rigSize = fit.ship.itemModifiedAttributes['rigSize'] - if rigSize == 1 and fit.ship.itemModifiedAttributes['medSlots'] > 0: - propID = 440 - elif rigSize == 2 and fit.ship.itemModifiedAttributes['medSlots'] > 0: - propID = 12076 - elif rigSize == 3 and fit.ship.itemModifiedAttributes['medSlots'] > 0: - propID = 12084 - elif rigSize == 4 and fit.ship.itemModifiedAttributes['medSlots'] > 0: - if fit.ship.itemModifiedAttributes['powerOutput'] > 60000: - propID = 41253 - else: - propID = 12084 - elif rigSize == None and fit.ship.itemModifiedAttributes['medSlots'] > 0: - propID = 440 - if propID: - fitL.appendModule(fitID, propID) - fitL.recalc(fit) - fit = eos.db.getFit(fitID) - mwdPropSpeed = fit.maxSpeed - mwdPosition = list(filter(lambda mod: mod.item and mod.item.ID == propID, fit.modules))[0].position - fitL.removeModule(fitID, mwdPosition) - fitL.recalc(fit) - fit = eos.db.getFit(fitID) - return mwdPropSpeed + if not shipHasMedSlots: + return None + + filterVal = Item.groupID == getGroup('Propulsion Module').ID + propMods = gamedata_session.query(Item).options().filter(filterVal).all() + mapPropData = lambda propName: \ + next(map(lambda propMod: {'id': propMod.typeID, 'powerReq': propMod.attributes['power'].value}, + (filter(lambda mod: mod.name == propName, propMods)))) + mwd5mn = mapPropData('5MN Microwarpdrive II') + mwd50mn = mapPropData('50MN Microwarpdrive II') + mwd500mn = mapPropData('500MN Microwarpdrive II') + mwd50000mn = mapPropData('50000MN Microwarpdrive II') + if rigSize == RigSize.SMALL or rigSize is None: + propID = mwd5mn['id'] if shipPower > mwd5mn['powerReq'] else None + elif rigSize == RigSize.MEDIUM: + propID = mwd50mn['id'] if shipPower > mwd50mn['powerReq'] else mwd5mn['id'] + elif rigSize == RigSize.LARGE: + propID = mwd500mn['id'] if shipPower > mwd500mn['powerReq'] else mwd50mn['id'] + elif rigSize == RigSize.CAPITAL: + propID = mwd50000mn['id'] if shipPower > mwd50000mn['powerReq'] else mwd500mn['id'] + + if propID is None: + return None + fitL.appendModule(fitID, propID) + fitL.recalc(fit) + fit = eos.db.getFit(fitID) + mwdPropSpeed = fit.maxSpeed + mwdPosition = list(filter(lambda mod: mod.item and mod.item.ID == propID, fit.modules))[0].position + fitL.removeModule(fitID, mwdPosition) + fitL.recalc(fit) + fit = eos.db.getFit(fitID) + return mwdPropSpeed + def getPropData(fit, fitL): fitID = fit.ID - propMods = list(filter(lambda mod: mod.item and mod.item.groupID in [46], fit.modules)) - possibleMWD = list(filter(lambda mod: 'signatureRadiusBonus' in mod.item.attributes, propMods)) - if len(possibleMWD) > 0 and possibleMWD[0].state > 0: - mwd = possibleMWD[0] - oldMwdState = mwd.state - mwd.state = 0 + propGroupId = getGroup('Propulsion Module').ID + propMods = filter(lambda mod: mod.item and mod.item.groupID == propGroupId, fit.modules) + activePropWBloomFilter = lambda mod: mod.state > 0 and 'signatureRadiusBonus' in mod.item.attributes + propWithBloom = next(filter(activePropWBloomFilter, propMods), None) + if propWithBloom is not None: + oldPropState = propWithBloom.state + propWithBloom.state = 0 fitL.recalc(fit) fit = eos.db.getFit(fitID) sp = fit.maxSpeed sig = fit.ship.itemModifiedAttributes['signatureRadius'] - mwd.state = oldMwdState + propWithBloom.state = oldPropState fitL.recalc(fit) fit = eos.db.getFit(fitID) return {'usingMWD': True, 'unpropedSpeed': sp, 'unpropedSig': sig} - return {'usingMWD': False, 'unpropedSpeed': fit.maxSpeed, 'unpropedSig': fit.ship.itemModifiedAttributes['signatureRadius']} + return { + 'usingMWD': False, + 'unpropedSpeed': fit.maxSpeed, + 'unpropedSig': fit.ship.itemModifiedAttributes['signatureRadius'] + } + def getOutgoingProjectionData(fit): # This is a subset of module groups capable of projection and a superset of those currently used by efs - projectedModGroupIds = [ - 41, 52, 65, 67, 68, 71, 80, 201, 208, 291, 325, 379, 585, - 842, 899, 1150, 1154, 1189, 1306, 1672, 1697, 1698, 1815, 1894 + modGroupNames = [ + 'Remote Shield Booster', 'Warp Scrambler', 'Stasis Web', 'Remote Capacitor Transmitter', + 'Energy Nosferatu', 'Energy Neutralizer', 'Burst Jammer', 'ECM', 'Sensor Dampener', + 'Weapon Disruptor', 'Remote Armor Repairer', 'Target Painter', 'Remote Hull Repairer', + 'Burst Projectors', 'Warp Disrupt Field Generator', 'Armor Resistance Shift Hardener', + 'Target Breaker', 'Micro Jump Drive', 'Ship Modifiers', 'Stasis Grappler', + 'Ancillary Remote Shield Booster', 'Ancillary Remote Armor Repairer', + 'Titan Phenomena Generator', 'Non-Repeating Hardeners' ] - projectedMods = list(filter(lambda mod: mod.item and mod.item.groupID in projectedModGroupIds, fit.modules)) + modGroupIds = list(map(lambda s: getGroup(s).ID, modGroupNames)) + modGroupData = dict(map(lambda name, gid: (name, {'name': name, 'id': gid}), + modGroupNames, modGroupIds)) + projectedMods = list(filter(lambda mod: mod.item and mod.item.groupID in modGroupIds, fit.modules)) projections = [] for mod in projectedMods: stats = {} - if mod.item.groupID == 65 or mod.item.groupID == 1672: + if mod.item.groupID in [modGroupData['Stasis Web']['id'], modGroupData['Stasis Grappler']['id']]: stats['type'] = 'Stasis Web' stats['optimal'] = mod.itemModifiedAttributes['maxRange'] attrDirectMap(['duration', 'speedFactor'], stats, mod) - elif mod.item.groupID == 291: + elif mod.item.groupID == modGroupData['Weapon Disruptor']['id']: stats['type'] = 'Weapon Disruptor' stats['optimal'] = mod.itemModifiedAttributes['maxRange'] stats['falloff'] = mod.itemModifiedAttributes['falloffEffectiveness'] attrDirectMap([ - 'trackingSpeedBonus', 'maxRangeBonus', 'falloffBonus', 'aoeCloudSizeBonus',\ - 'aoeVelocityBonus', 'missileVelocityBonus', 'explosionDelayBonus'\ + 'trackingSpeedBonus', 'maxRangeBonus', 'falloffBonus', 'aoeCloudSizeBonus', + 'aoeVelocityBonus', 'missileVelocityBonus', 'explosionDelayBonus' ], stats, mod) - elif mod.item.groupID == 68: + elif mod.item.groupID == modGroupData['Energy Nosferatu']['id']: stats['type'] = 'Energy Nosferatu' attrDirectMap(['powerTransferAmount', 'energyNeutralizerSignatureResolution'], stats, mod) - elif mod.item.groupID == 71: + elif mod.item.groupID == modGroupData['Energy Neutralizer']['id']: stats['type'] = 'Energy Neutralizer' attrDirectMap([ - 'energyNeutralizerSignatureResolution','entityCapacitorLevelModifierSmall',\ - 'entityCapacitorLevelModifierMedium', 'entityCapacitorLevelModifierLarge',\ - 'energyNeutralizerAmount'\ + 'energyNeutralizerSignatureResolution', 'entityCapacitorLevelModifierSmall', + 'entityCapacitorLevelModifierMedium', 'entityCapacitorLevelModifierLarge', + 'energyNeutralizerAmount' ], stats, mod) - elif mod.item.groupID == 41 or mod.item.groupID == 1697: + elif mod.item.groupID in [modGroupData['Remote Shield Booster']['id'], + modGroupData['Ancillary Remote Shield Booster']['id']]: stats['type'] = 'Remote Shield Booster' attrDirectMap(['shieldBonus'], stats, mod) - elif mod.item.groupID == 325 or mod.item.groupID == 1698: + elif mod.item.groupID in [modGroupData['Remote Armor Repairer']['id'], + modGroupData['Ancillary Remote Armor Repairer']['id']]: stats['type'] = 'Remote Armor Repairer' attrDirectMap(['armorDamageAmount'], stats, mod) - elif mod.item.groupID == 52: + elif mod.item.groupID == modGroupData['Warp Scrambler']['id']: stats['type'] = 'Warp Scrambler' attrDirectMap(['activationBlockedStrenght', 'warpScrambleStrength'], stats, mod) - elif mod.item.groupID == 379: + elif mod.item.groupID == modGroupData['Target Painter']['id']: stats['type'] = 'Target Painter' attrDirectMap(['signatureRadiusBonus'], stats, mod) - elif mod.item.groupID == 208: + elif mod.item.groupID == modGroupData['Sensor Dampener']['id']: stats['type'] = 'Sensor Dampener' attrDirectMap(['maxTargetRangeBonus', 'scanResolutionBonus'], stats, mod) - elif mod.item.groupID == 201: + elif mod.item.groupID == modGroupData['ECM']['id']: stats['type'] = 'ECM' attrDirectMap([ - 'scanGravimetricStrengthBonus', 'scanMagnetometricStrengthBonus',\ - 'scanRadarStrengthBonus', 'scanLadarStrengthBonus',\ + 'scanGravimetricStrengthBonus', 'scanMagnetometricStrengthBonus', + 'scanRadarStrengthBonus', 'scanLadarStrengthBonus', ], stats, mod) - elif mod.item.groupID == 80: + elif mod.item.groupID == modGroupData['Burst Jammer']['id']: stats['type'] = 'Burst Jammer' mod.itemModifiedAttributes['maxRange'] = mod.itemModifiedAttributes['ecmBurstRange'] attrDirectMap([ - 'scanGravimetricStrengthBonus', 'scanMagnetometricStrengthBonus',\ - 'scanRadarStrengthBonus', 'scanLadarStrengthBonus',\ + 'scanGravimetricStrengthBonus', 'scanMagnetometricStrengthBonus', + 'scanRadarStrengthBonus', 'scanLadarStrengthBonus', ], stats, mod) - elif mod.item.groupID == 1189: + elif mod.item.groupID == modGroupData['Micro Jump Drive']['id']: stats['type'] = 'Micro Jump Drive' mod.itemModifiedAttributes['maxRange'] = 0 attrDirectMap(['moduleReactivationDelay'], stats, mod) - if mod.itemModifiedAttributes['maxRange'] == None: + if mod.itemModifiedAttributes['maxRange'] is None: print(mod.item.name) print(mod.itemModifiedAttributes.items()) raise ValueError('Projected module lacks a maxRange') @@ -137,13 +185,14 @@ def getOutgoingProjectionData(fit): projections.append(stats) return projections + def getModuleNames(fit): moduleNames = [] highSlotNames = [] midSlotNames = [] lowSlotNames = [] rigSlotNames = [] - miscSlotNames = [] #subsystems ect + miscSlotNames = [] # subsystems ect for mod in fit.modules: if mod.slot == 3: modSlotNames = highSlotNames @@ -156,8 +205,8 @@ def getModuleNames(fit): elif mod.slot == 5: modSlotNames = miscSlotNames try: - if mod.item != None: - if mod.charge != None: + if mod.item is not None: + if mod.charge is not None: modSlotNames.append(mod.item.name + ': ' + mod.charge.name) else: modSlotNames.append(mod.item.name) @@ -167,8 +216,12 @@ def getModuleNames(fit): print(vars(mod)) print('could not find name for module') print(fit.modules) - for modInfo in [['High Slots:'], highSlotNames, ['', 'Med Slots:'], midSlotNames, ['', 'Low Slots:'], lowSlotNames, ['', 'Rig Slots:'], rigSlotNames]: + for modInfo in [ + ['High Slots:'], highSlotNames, ['', 'Med Slots:'], midSlotNames, + ['', 'Low Slots:'], lowSlotNames, ['', 'Rig Slots:'], rigSlotNames + ]: moduleNames.extend(modInfo) + if len(miscSlotNames) > 0: moduleNames.append('') moduleNames.append('Subsystems:') @@ -201,19 +254,37 @@ def getModuleNames(fit): moduleNames.append(commandFit.name) return moduleNames + +def getFighterAbilityData(fighterAttr, fighter, baseRef): + baseRefDam = baseRef + 'Damage' + abilityName = 'RegularAttack' if baseRef == 'fighterAbilityAttackMissile' else 'MissileAttack' + rangeSuffix = 'RangeOptimal' if baseRef == 'fighterAbilityAttackMissile' else 'Range' + reductionRef = baseRef if baseRef == 'fighterAbilityAttackMissile' else baseRefDam + damageReductionFactor = log(fighterAttr[reductionRef + 'ReductionFactor']) / log(fighterAttr[reductionRef + 'ReductionSensitivity']) + damTypes = ['EM', 'Therm', 'Exp', 'Kin'] + abBaseDamage = sum(map(lambda damType: fighterAttr[baseRefDam + damType], damTypes)) + abDamage = abBaseDamage * fighterAttr[baseRefDam + 'Multiplier'] + return { + 'name': abilityName, 'volley': abDamage * fighter.amountActive, 'explosionRadius': fighterAttr[baseRef + 'ExplosionRadius'], + 'explosionVelocity': fighterAttr[baseRef + 'ExplosionVelocity'], 'optimal': fighterAttr[baseRef + rangeSuffix], + 'damageReductionFactor': damageReductionFactor, 'rof': fighterAttr[baseRef + 'Duration'], + } + + def getWeaponSystemData(fit): weaponSystems = [] groups = {} for mod in fit.modules: if mod.dps > 0: + # Group weapon + ammo combinations that occur more than once keystr = str(mod.itemID) + '-' + str(mod.chargeID) if keystr in groups: groups[keystr][1] += 1 else: groups[keystr] = [mod, 1] - for wepGroup in groups: - stats = groups[wepGroup][0] - c = groups[wepGroup][1] + for wepGroup in groups.values(): + stats = wepGroup[0] + n = wepGroup[1] tracking = 0 maxVelocity = 0 explosionDelay = 0 @@ -221,11 +292,12 @@ def getWeaponSystemData(fit): explosionRadius = 0 explosionVelocity = 0 aoeFieldRange = 0 - if stats.hardpoint == 2: + if stats.hardpoint == Hardpoint.TURRET: tracking = stats.itemModifiedAttributes['trackingSpeed'] typeing = 'Turret' name = stats.item.name + ', ' + stats.charge.name - elif stats.hardpoint == 1 or 'Bomb Launcher' in stats.item.name: + # Bombs share most attributes with missiles despite not needing the hardpoint + elif stats.hardpoint == Hardpoint.MISSILE or 'Bomb Launcher' in stats.item.name: maxVelocity = stats.chargeModifiedAttributes['maxVelocity'] explosionDelay = stats.chargeModifiedAttributes['explosionDelay'] damageReductionFactor = stats.chargeModifiedAttributes['aoeDamageReductionFactor'] @@ -233,140 +305,240 @@ def getWeaponSystemData(fit): explosionVelocity = stats.chargeModifiedAttributes['aoeVelocity'] typeing = 'Missile' name = stats.item.name + ', ' + stats.charge.name - elif stats.hardpoint == 0: + elif stats.hardpoint == Hardpoint.NONE: aoeFieldRange = stats.itemModifiedAttributes['empFieldRange'] + # This also covers non-bomb weapons with dps values and no hardpoints, most notably targeted doomsdays. typeing = 'SmartBomb' name = stats.item.name - statDict = {'dps': stats.dps * c, 'capUse': stats.capUse * c, 'falloff': stats.falloff,\ - 'type': typeing, 'name': name, 'optimal': stats.maxRange,\ - 'numCharges': stats.numCharges, 'numShots': stats.numShots, 'reloadTime': stats.reloadTime,\ - 'cycleTime': stats.cycleTime, 'volley': stats.volley * c, 'tracking': tracking,\ - 'maxVelocity': maxVelocity, 'explosionDelay': explosionDelay, 'damageReductionFactor': damageReductionFactor,\ - 'explosionRadius': explosionRadius, 'explosionVelocity': explosionVelocity, 'aoeFieldRange': aoeFieldRange\ + statDict = { + 'dps': stats.dps * n, 'capUse': stats.capUse * n, 'falloff': stats.falloff, + 'type': typeing, 'name': name, 'optimal': stats.maxRange, + 'numCharges': stats.numCharges, 'numShots': stats.numShots, 'reloadTime': stats.reloadTime, + 'cycleTime': stats.cycleTime, 'volley': stats.volley * n, 'tracking': tracking, + 'maxVelocity': maxVelocity, 'explosionDelay': explosionDelay, 'damageReductionFactor': damageReductionFactor, + 'explosionRadius': explosionRadius, 'explosionVelocity': explosionVelocity, 'aoeFieldRange': aoeFieldRange } weaponSystems.append(statDict) - #if fit.droneDPS > 0: for drone in fit.drones: if drone.dps[0] > 0 and drone.amountActive > 0: - newTracking = drone.itemModifiedAttributes['trackingSpeed'] / (drone.itemModifiedAttributes['optimalSigRadius'] / 40000) - statDict = {'dps': drone.dps[0], 'cycleTime': drone.cycleTime, 'type': 'Drone',\ - 'optimal': drone.maxRange, 'name': drone.item.name, 'falloff': drone.falloff,\ - 'maxSpeed': drone.itemModifiedAttributes['maxVelocity'], 'tracking': newTracking,\ - 'volley': drone.dps[1]\ + droneAttr = drone.itemModifiedAttributes + # Drones are using the old tracking formula for trackingSpeed. This updates it to match turrets. + newTracking = droneAttr['trackingSpeed'] / (droneAttr['optimalSigRadius'] / 40000) + statDict = { + 'dps': drone.dps[0], 'cycleTime': drone.cycleTime, 'type': 'Drone', + 'optimal': drone.maxRange, 'name': drone.item.name, 'falloff': drone.falloff, + 'maxSpeed': droneAttr['maxVelocity'], 'tracking': newTracking, + 'volley': drone.dps[1] } weaponSystems.append(statDict) for fighter in fit.fighters: if fighter.dps[0] > 0 and fighter.amountActive > 0: + fighterAttr = fighter.itemModifiedAttributes abilities = [] - #for ability in fighter.abilities: - if 'fighterAbilityAttackMissileDamageEM' in fighter.itemModifiedAttributes: + if 'fighterAbilityAttackMissileDamageEM' in fighterAttr: baseRef = 'fighterAbilityAttackMissile' - baseRefDam = baseRef + 'Damage' - damageReductionFactor = log(fighter.itemModifiedAttributes[baseRef + 'ReductionFactor']) / log(fighter.itemModifiedAttributes[baseRef + 'ReductionSensitivity']) - abBaseDamage = fighter.itemModifiedAttributes[baseRefDam + 'EM'] + fighter.itemModifiedAttributes[baseRefDam + 'Therm'] + fighter.itemModifiedAttributes[baseRefDam + 'Exp'] + fighter.itemModifiedAttributes[baseRefDam + 'Kin'] - abDamage = abBaseDamage * fighter.itemModifiedAttributes[baseRefDam + 'Multiplier'] - ability = {'name': 'RegularAttack', 'volley': abDamage * fighter.amountActive, 'explosionRadius': fighter.itemModifiedAttributes[baseRef + 'ExplosionRadius'],\ - 'explosionVelocity': fighter.itemModifiedAttributes[baseRef + 'ExplosionVelocity'], 'optimal': fighter.itemModifiedAttributes[baseRef + 'RangeOptimal'],\ - 'damageReductionFactor': damageReductionFactor, 'rof': fighter.itemModifiedAttributes[baseRef + 'Duration'],\ - } + ability = getFighterAbilityData(fighterAttr, fighter, baseRef) abilities.append(ability) - if 'fighterAbilityMissilesDamageEM' in fighter.itemModifiedAttributes: + if 'fighterAbilityMissilesDamageEM' in fighterAttr: baseRef = 'fighterAbilityMissiles' - baseRefDam = baseRef + 'Damage' - damageReductionFactor = log(fighter.itemModifiedAttributes[baseRefDam + 'ReductionFactor']) / log(fighter.itemModifiedAttributes[baseRefDam + 'ReductionSensitivity']) - abBaseDamage = fighter.itemModifiedAttributes[baseRefDam + 'EM'] + fighter.itemModifiedAttributes[baseRefDam + 'Therm'] + fighter.itemModifiedAttributes[baseRefDam + 'Exp'] + fighter.itemModifiedAttributes[baseRefDam + 'Kin'] - abDamage = abBaseDamage * fighter.itemModifiedAttributes[baseRefDam + 'Multiplier'] - ability = {'name': 'MissileAttack', 'volley': abDamage * fighter.amountActive, 'explosionRadius': fighter.itemModifiedAttributes[baseRef + 'ExplosionRadius'],\ - 'explosionVelocity': fighter.itemModifiedAttributes[baseRef + 'ExplosionVelocity'], 'optimal': fighter.itemModifiedAttributes[baseRef + 'Range'],\ - 'damageReductionFactor': damageReductionFactor, 'rof': fighter.itemModifiedAttributes[baseRef + 'Duration'],\ - } + ability = getFighterAbilityData(fighterAttr, fighter, baseRef) abilities.append(ability) - statDict = {'dps': fighter.dps[0], 'type': 'Fighter', 'name': fighter.item.name,\ - 'maxSpeed': fighter.itemModifiedAttributes['maxVelocity'], 'abilities': abilities, 'ehp': fighter.itemModifiedAttributes['shieldCapacity'] / 0.8875 * fighter.amountActive,\ - 'volley': fighter.dps[1], 'signatureRadius': fighter.itemModifiedAttributes['signatureRadius']\ + statDict = { + 'dps': fighter.dps[0], 'type': 'Fighter', 'name': fighter.item.name, + 'maxSpeed': fighterAttr['maxVelocity'], 'abilities': abilities, + 'ehp': fighterAttr['shieldCapacity'] / 0.8875 * fighter.amountActive, + 'volley': fighter.dps[1], 'signatureRadius': fighterAttr['signatureRadius'] } weaponSystems.append(statDict) return weaponSystems -def getWeaponBonusMultipliers(fit): - multipliers = {'turret': 1, 'launcher': 1, 'droneBandwidth': 1} - from eos.db import gamedata_session - from eos.gamedata import Traits - filterVal = Traits.typeID == fit.shipID - data = gamedata_session.query(Traits).options().filter(filterVal).all() - roleBonusMode = False - if len(data) == 0: - return multipliers - previousTypedBonus = 0 - previousDroneTypeBonus = 0 - for bonusText in data[0].traitText.splitlines(): - bonusText = bonusText.lower() - if 'per skill level' in bonusText: - roleBonusMode = False - if 'role bonus' in bonusText or 'misc bonus' in bonusText: - roleBonusMode = True - multi = 1 - if 'damage' in bonusText and not any(e in bonusText for e in ['control', 'heat']): - splitText = bonusText.split('%') - if (float(splitText[0]) > 0) == False: - print('damage bonus split did not parse correctly!') - print(float(splitText[0])) - if roleBonusMode: - addedMulti = float(splitText[0]) - else: - addedMulti = float(splitText[0]) * 5 - if any(e in bonusText for e in [' em', 'thermal', 'kinetic', 'explosive']): - if addedMulti > previousTypedBonus: - previousTypedBonus = addedMulti - else: - addedMulti = 0 - if any(e in bonusText for e in ['heavy drone', 'medium drone', 'light drone', 'sentry drone']): - if addedMulti > previousDroneTypeBonus: - previousDroneTypeBonus = addedMulti - else: - addedMulti = 0 - multi = 1 + (addedMulti / 100) - elif 'rate of fire' in bonusText: - splitText = bonusText.split('%') - if (float(splitText[0]) > 0) == False: - print('rate of fire bonus split did not parse correctly!') - print(float(splitText[0])) - if roleBonusMode: - rofMulti = float(splitText[0]) - else: - rofMulti = float(splitText[0]) * 5 - multi = 1 / (1 - (rofMulti / 100)) - if multi > 1: - if 'drone' in bonusText.lower(): - multipliers['droneBandwidth'] *= multi - elif 'turret' in bonusText.lower(): - multipliers['turret'] *= multi - elif any(e in bonusText for e in ['missile', 'torpedo']): - multipliers['launcher'] *= multi - return multipliers -def getShipSize(groupID): - # Sizings are somewhat arbitrary but allow for a more managable number of top level groupings in a tree structure. - shipSizes = ['Frigate', 'Destroyer', 'Cruiser', 'Battlecruiser', 'Battleship', 'Capital', 'Industrial', 'Misc'] - if groupID in [25, 31, 237, 324, 830, 831, 834, 893, 1283, 1527]: - return shipSizes[0] - elif groupID in [420, 541, 1305, 1534]: - return shipSizes[1] - elif groupID in [26, 358, 832, 833, 894, 906, 963]: - return shipSizes[2] - elif groupID in [419, 540, 1201]: - return shipSizes[3] - elif groupID in [27, 381, 898, 900]: - return shipSizes[4] - elif groupID in [30, 485, 513, 547, 659, 883, 902, 1538]: - return shipSizes[5] - elif groupID in [28, 380, 1202, 463, 543, 941]: - return shipSizes[6] - elif groupID in [29, 1022]: - return shipSizes[7] + +wepTestSet = {} + + +def getTestSet(setType): + def GetT2ItemsWhere(additionalFilter, mustBeOffensive=False, category='Module'): + # Used to obtain a smaller subset of items while still containing examples of each group. + T2_META_LEVEL = 5 + metaLevelAttrID = getAttributeInfo('metaLevel').attributeID + categoryID = getCategory(category).categoryID + result = gamedata_session.query(Item).join(ItemEffect, Group, Attribute).\ + filter( + additionalFilter, + Attribute.attributeID == metaLevelAttrID, + Attribute.value == T2_META_LEVEL, + Group.categoryID == categoryID, + ).all() + if mustBeOffensive: + result = filter(lambda t: t.offensive is True, result) + return list(result) + + def getChargeType(item, setType): + if setType == 'turret': + return str(item.attributes['chargeGroup1'].value) + '-' + str(item.attributes['chargeSize'].value) + return str(item.attributes['chargeGroup1'].value) + + if setType in wepTestSet.keys(): + return wepTestSet[setType] else: - sizeNotFoundMsg = 'ShipSize not found for groupID: ' + str(groupID) - print(sizeNotFoundMsg) - return sizeNotFoundMsg + wepTestSet[setType] = [] + modSet = wepTestSet[setType] + + if setType == 'drone': + ilist = GetT2ItemsWhere(True, True, 'Drone') + for item in ilist: + drone = Drone(item) + drone.amount = 1 + drone.amountActive = 1 + drone.itemModifiedAttributes.parent = drone + modSet.append(drone) + return modSet + + turretFittedEffectID = gamedata_session.query(Effect).filter(Effect.name == 'turretFitted').first().effectID + launcherFittedEffectID = gamedata_session.query(Effect).filter(Effect.name == 'launcherFitted').first().effectID + if setType == 'launcher': + effectFilter = ItemEffect.effectID == launcherFittedEffectID + reqOff = False + else: + effectFilter = ItemEffect.effectID == turretFittedEffectID + reqOff = True + ilist = GetT2ItemsWhere(effectFilter, reqOff) + previousChargeTypes = [] + # Get modules from item list + for item in ilist: + chargeType = getChargeType(item, setType) + # Only add turrets if we don't already have one with the same size and ammo type. + if setType == 'launcher' or chargeType not in previousChargeTypes: + previousChargeTypes.append(chargeType) + mod = Module(item) + modSet.append(mod) + + mkt = Market.getInstance() + # Due to typed missile damage bonuses we'll need to add extra launchers to cover all four types. + additionalLaunchers = [] + for mod in modSet: + clist = list(gamedata_session.query(Item).options(). + filter(Item.groupID == mod.itemModifiedAttributes['chargeGroup1']).all()) + mods = [mod] + charges = [clist[0]] + if setType == 'launcher': + # We don't want variations of missiles we already have + prevCharges = list(mkt.getVariationsByItems(charges)) + testCharges = [] + for charge in clist: + if charge not in prevCharges: + testCharges.append(charge) + prevCharges += mkt.getVariationsByItems([charge]) + for c in testCharges: + charges.append(c) + additionalLauncher = Module(mod.item) + mods.append(additionalLauncher) + for i in range(len(mods)): + mods[i].charge = charges[i] + mods[i].reloadForce = True + mods[i].state = 2 + if setType == 'launcher' and i > 0: + additionalLaunchers.append(mods[i]) + modSet += additionalLaunchers + return modSet + + +def getWeaponBonusMultipliers(fit): + def sumDamage(attr): + totalDamage = 0 + for damageType in ['emDamage', 'thermalDamage', 'kineticDamage', 'explosiveDamage']: + if attr[damageType] is not None: + totalDamage += attr[damageType] + return totalDamage + + def getCurrentMultipliers(tf): + fitMultipliers = {} + getDroneMulti = lambda d: sumDamage(d.itemModifiedAttributes) * d.itemModifiedAttributes['damageMultiplier'] + fitMultipliers['drones'] = list(map(getDroneMulti, tf.drones)) + + getFitTurrets = lambda f: filter(lambda mod: mod.hardpoint == Hardpoint.TURRET, f.modules) + getTurretMulti = lambda mod: mod.itemModifiedAttributes['damageMultiplier'] / mod.cycleTime + fitMultipliers['turrets'] = list(map(getTurretMulti, getFitTurrets(tf))) + + getFitLaunchers = lambda f: filter(lambda mod: mod.hardpoint == Hardpoint.MISSILE, f.modules) + getLauncherMulti = lambda mod: sumDamage(mod.chargeModifiedAttributes) / mod.cycleTime + fitMultipliers['launchers'] = list(map(getLauncherMulti, getFitLaunchers(tf))) + return fitMultipliers + + multipliers = {'turret': 1, 'launcher': 1, 'droneBandwidth': 1} + drones = getTestSet('drone') + launchers = getTestSet('launcher') + turrets = getTestSet('turret') + for weaponTypeSet in [turrets, launchers, drones]: + for mod in weaponTypeSet: + mod.owner = fit + turrets = list(filter(lambda mod: mod.itemModifiedAttributes['damageMultiplier'], turrets)) + launchers = list(filter(lambda mod: sumDamage(mod.chargeModifiedAttributes), launchers)) + # Since the effect modules are fairly opaque a mock test fit is used to test the impact of traits. + tf = Fit.getInstance() + tf.modules = HandledList(turrets + launchers) + tf.character = fit.character + tf.ship = fit.ship + tf.drones = HandledList(drones) + tf.fighters = HandledList([]) + tf.boosters = HandledList([]) + tf.extraAttributes = fit.extraAttributes + tf.mode = fit.mode + preTraitMultipliers = getCurrentMultipliers(tf) + for effect in fit.ship.item.effects.values(): + if effect._Effect__effectModule is not None: + effect.handler(tf, tf.ship, []) + # Factor in mode effects for T3 Destroyers + if fit.mode is not None: + for effect in fit.mode.item.effects.values(): + if effect._Effect__effectModule is not None: + effect.handler(tf, fit.mode, []) + if fit.ship.item.groupID == getGroup('Strategic Cruiser').ID: + subSystems = list(filter(lambda mod: mod.slot == Slot.SUBSYSTEM and mod.item, fit.modules)) + for sub in subSystems: + for effect in sub.item.effects.values(): + if effect._Effect__effectModule is not None: + effect.handler(tf, sub, []) + postTraitMultipliers = getCurrentMultipliers(tf) + getMaxRatio = lambda dictA, dictB, key: max(map(lambda a, b: b / a, dictA[key], dictB[key])) + multipliers['turret'] = round(getMaxRatio(preTraitMultipliers, postTraitMultipliers, 'turrets'), 6) + multipliers['launcher'] = round(getMaxRatio(preTraitMultipliers, postTraitMultipliers, 'launchers'), 6) + multipliers['droneBandwidth'] = round(getMaxRatio(preTraitMultipliers, postTraitMultipliers, 'drones'), 6) + tf.recalc(fit) + return multipliers + + +def getShipSize(groupID): + # Size groupings are somewhat arbitrary but allow for a more managable number of top level groupings in a tree structure. + frigateGroupNames = ['Frigate', 'Shuttle', 'Corvette', 'Assault Frigate', 'Covert Ops', 'Interceptor', + 'Stealth Bomber', 'Electronic Attack Ship', 'Expedition Frigate', 'Logistics Frigate'] + destroyerGroupNames = ['Destroyer', 'Interdictor', 'Tactical Destroyer', 'Command Destroyer'] + cruiserGroupNames = ['Cruiser', 'Heavy Assault Cruiser', 'Logistics', 'Force Recon Ship', + 'Heavy Interdiction Cruiser', 'Combat Recon Ship', 'Strategic Cruiser'] + bcGroupNames = ['Combat Battlecruiser', 'Command Ship', 'Attack Battlecruiser'] + bsGroupNames = ['Battleship', 'Elite Battleship', 'Black Ops', 'Marauder'] + capitalGroupNames = ['Titan', 'Dreadnought', 'Freighter', 'Carrier', 'Supercarrier', + 'Capital Industrial Ship', 'Jump Freighter', 'Force Auxiliary'] + indyGroupNames = ['Industrial', 'Deep Space Transport', 'Blockade Runner', + 'Mining Barge', 'Exhumer', 'Industrial Command Ship'] + miscGroupNames = ['Capsule', 'Prototype Exploration Ship'] + shipSizes = [ + {'name': 'Frigate', 'groupIDs': map(lambda s: getGroup(s).ID, frigateGroupNames)}, + {'name': 'Destroyer', 'groupIDs': map(lambda s: getGroup(s).ID, destroyerGroupNames)}, + {'name': 'Cruiser', 'groupIDs': map(lambda s: getGroup(s).ID, cruiserGroupNames)}, + {'name': 'Battlecruiser', 'groupIDs': map(lambda s: getGroup(s).ID, bcGroupNames)}, + {'name': 'Battleship', 'groupIDs': map(lambda s: getGroup(s).ID, bsGroupNames)}, + {'name': 'Capital', 'groupIDs': map(lambda s: getGroup(s).ID, capitalGroupNames)}, + {'name': 'Industrial', 'groupIDs': map(lambda s: getGroup(s).ID, indyGroupNames)}, + {'name': 'Misc', 'groupIDs': map(lambda s: getGroup(s).ID, miscGroupNames)} + ] + for size in shipSizes: + if groupID in size['groupIDs']: + return size['name'] + sizeNotFoundMsg = 'ShipSize not found for groupID: ' + str(groupID) + print(sizeNotFoundMsg) + return sizeNotFoundMsg + def parseNeededFitDetails(fit, groupID): includeShipTypeData = groupID > 0 @@ -377,13 +549,11 @@ def parseNeededFitDetails(fit, groupID): fitName = fit.name print('') print('name: ' + fit.name) - fitL = Fit() + fitL = Fit.getInstance() fitL.recalc(fit) fit = eos.db.getFit(fitID) fitModAttr = fit.ship.itemModifiedAttributes propData = getPropData(fit, fitL) - print(fitModAttr['rigSize']) - print(propData) mwdPropSpeed = fit.maxSpeed if includeShipTypeData: mwdPropSpeed = getT2MwdSpeed(fit, fitL) @@ -395,52 +565,52 @@ def parseNeededFitDetails(fit, groupID): launcherSlots = fitModAttr['launcherSlotsLeft'] if fitModAttr['launcherSlotsLeft'] is not None else 0 droneBandwidth = fitModAttr['droneBandwidth'] if fitModAttr['droneBandwidth'] is not None else 0 weaponBonusMultipliers = getWeaponBonusMultipliers(fit) - effectiveTurretSlots = round(turretSlots * weaponBonusMultipliers['turret'], 2); - effectiveLauncherSlots = round(launcherSlots * weaponBonusMultipliers['launcher'], 2); - effectiveDroneBandwidth = round(droneBandwidth * weaponBonusMultipliers['droneBandwidth'], 2); + effectiveTurretSlots = round(turretSlots * weaponBonusMultipliers['turret'], 2) + effectiveLauncherSlots = round(launcherSlots * weaponBonusMultipliers['launcher'], 2) + effectiveDroneBandwidth = round(droneBandwidth * weaponBonusMultipliers['droneBandwidth'], 2) # Assume a T2 siege module for dreads - if groupID == 485: + if groupID == getGroup('Dreadnought').ID: effectiveTurretSlots *= 9.4 effectiveLauncherSlots *= 15 hullResonance = { - 'exp': fitModAttr['explosiveDamageResonance'], 'kin': fitModAttr['kineticDamageResonance'], \ + 'exp': fitModAttr['explosiveDamageResonance'], 'kin': fitModAttr['kineticDamageResonance'], 'therm': fitModAttr['thermalDamageResonance'], 'em': fitModAttr['emDamageResonance'] } armorResonance = { - 'exp': fitModAttr['armorExplosiveDamageResonance'], 'kin': fitModAttr['armorKineticDamageResonance'], \ + 'exp': fitModAttr['armorExplosiveDamageResonance'], 'kin': fitModAttr['armorKineticDamageResonance'], 'therm': fitModAttr['armorThermalDamageResonance'], 'em': fitModAttr['armorEmDamageResonance'] } shieldResonance = { - 'exp': fitModAttr['shieldExplosiveDamageResonance'], 'kin': fitModAttr['shieldKineticDamageResonance'], \ + 'exp': fitModAttr['shieldExplosiveDamageResonance'], 'kin': fitModAttr['shieldKineticDamageResonance'], 'therm': fitModAttr['shieldThermalDamageResonance'], 'em': fitModAttr['shieldEmDamageResonance'] } resonance = {'hull': hullResonance, 'armor': armorResonance, 'shield': shieldResonance} shipSize = getShipSize(groupID) try: - parsable = { - 'name': fitName, 'ehp': fit.ehp, 'droneDPS': fit.droneDPS, \ - 'droneVolley': fit.droneVolley, 'hp': fit.hp, 'maxTargets': fit.maxTargets, \ - 'maxSpeed': fit.maxSpeed, 'weaponVolley': fit.weaponVolley, 'totalVolley': fit.totalVolley,\ - 'maxTargetRange': fit.maxTargetRange, 'scanStrength': fit.scanStrength,\ - 'weaponDPS': fit.weaponDPS, 'alignTime': fit.alignTime, 'signatureRadius': fitModAttr['signatureRadius'],\ - 'weapons': weaponSystems, 'scanRes': fitModAttr['scanResolution'],\ - 'projectedModules': fit.projectedModules, 'capUsed': fit.capUsed, 'capRecharge': fit.capRecharge,\ - 'rigSlots': fitModAttr['rigSlots'], 'lowSlots': fitModAttr['lowSlots'],\ - 'midSlots': fitModAttr['medSlots'], 'highSlots': fitModAttr['hiSlots'],\ - 'turretSlots': fitModAttr['turretSlotsLeft'], 'launcherSlots': fitModAttr['launcherSlotsLeft'],\ - 'powerOutput': fitModAttr['powerOutput'], 'rigSize': fitModAttr['rigSize'],\ - 'effectiveTurrets': effectiveTurretSlots, 'effectiveLaunchers': effectiveLauncherSlots,\ - 'effectiveDroneBandwidth': effectiveDroneBandwidth,\ - 'resonance': resonance, 'typeID': fit.shipID, 'groupID': groupID, 'shipSize': shipSize,\ - 'droneControlRange': fitModAttr['droneControlRange'], 'mass': fitModAttr['mass'],\ - 'moduleNames': moduleNames, 'projections': projections,\ - 'unpropedSpeed': propData['unpropedSpeed'], 'unpropedSig': propData['unpropedSig'],\ + dataDict = { + 'name': fitName, 'ehp': fit.ehp, 'droneDPS': fit.droneDPS, + 'droneVolley': fit.droneVolley, 'hp': fit.hp, 'maxTargets': fit.maxTargets, + 'maxSpeed': fit.maxSpeed, 'weaponVolley': fit.weaponVolley, 'totalVolley': fit.totalVolley, + 'maxTargetRange': fit.maxTargetRange, 'scanStrength': fit.scanStrength, + 'weaponDPS': fit.weaponDPS, 'alignTime': fit.alignTime, 'signatureRadius': fitModAttr['signatureRadius'], + 'weapons': weaponSystems, 'scanRes': fitModAttr['scanResolution'], + 'projectedModules': fit.projectedModules, 'capUsed': fit.capUsed, 'capRecharge': fit.capRecharge, + 'rigSlots': fitModAttr['rigSlots'], 'lowSlots': fitModAttr['lowSlots'], + 'midSlots': fitModAttr['medSlots'], 'highSlots': fitModAttr['hiSlots'], + 'turretSlots': fitModAttr['turretSlotsLeft'], 'launcherSlots': fitModAttr['launcherSlotsLeft'], + 'powerOutput': fitModAttr['powerOutput'], 'rigSize': fitModAttr['rigSize'], + 'effectiveTurrets': effectiveTurretSlots, 'effectiveLaunchers': effectiveLauncherSlots, + 'effectiveDroneBandwidth': effectiveDroneBandwidth, + 'resonance': resonance, 'typeID': fit.shipID, 'groupID': groupID, 'shipSize': shipSize, + 'droneControlRange': fitModAttr['droneControlRange'], 'mass': fitModAttr['mass'], + 'moduleNames': moduleNames, 'projections': projections, + 'unpropedSpeed': propData['unpropedSpeed'], 'unpropedSig': propData['unpropedSig'], 'usingMWD': propData['usingMWD'], 'mwdPropSpeed': mwdPropSpeed } except TypeError: print('Error parsing fit:' + str(fit)) print(TypeError) parsable = {'name': fitName + 'Fit could not be correctly parsed'} - stringified = json.dumps(parsable, skipkeys=True) - return stringified + export = json.dumps(dataDict, skipkeys=True) + return export diff --git a/eos/effects/shipdronescoutthermaldamagegf2.py b/eos/effects/shipdronescoutthermaldamagegf2.py index afe18cb9d..54f7716e0 100644 --- a/eos/effects/shipdronescoutthermaldamagegf2.py +++ b/eos/effects/shipdronescoutthermaldamagegf2.py @@ -6,5 +6,5 @@ type = "passive" def handler(fit, ship, context): - fit.drones.filteredItemBoost(lambda mod: mod.item.requiresSkill("Drone Avionics"), + fit.drones.filteredItemBoost(lambda mod: mod.item.requiresSkill("Light Drone Operation"), "thermalDamage", ship.getModifiedItemAttr("shipBonusGF2"), skill="Gallente Frigate") diff --git a/savedata/effs_export_base_fits.py b/savedata/effs_export_base_fits.py index e1be23e3b..c08c6c003 100644 --- a/savedata/effs_export_base_fits.py +++ b/savedata/effs_export_base_fits.py @@ -93,7 +93,10 @@ from eos.db.gamedata.traits import traits_table from eos.saveddata.mode import Mode def exportBaseShips(opts): + nameReq = '' if opts: + if opts.search: + nameReq = opts.search if opts.outputpath: basePath = opts.outputpath elif opts.savepath: @@ -109,9 +112,8 @@ def exportBaseShips(opts): shipCata = eos.db.getItemsByCategory('Ship') baseLimit = 1000 baseN = 0 - nameReqBase = ''; for ship in iter(shipCata): - if baseN < baseLimit and nameReqBase in ship.name: + if baseN < baseLimit and nameReq in ship.name: print(ship.name) print(ship.groupID) dna = str(ship.ID) diff --git a/savedata/effs_export_pyfa_fits.py b/savedata/effs_export_pyfa_fits.py index f49cc0971..82949f1c4 100644 --- a/savedata/effs_export_pyfa_fits.py +++ b/savedata/effs_export_pyfa_fits.py @@ -22,7 +22,10 @@ if not os.path.exists(config.savePath): from effs_stat_export import parseNeededFitDetails def exportPyfaFits(opts): + nameReq = '' if opts: + if opts.search: + nameReq = opts.search if opts.outputpath: basePath = opts.outputpath elif opts.savepath: @@ -38,7 +41,6 @@ def exportPyfaFits(opts): #The current storage system isn't going to hold more than 2500 fits as local browser storage is limited limit = 2500 skipTill = 0 - nameReq = '' n = 0 fitList = eos.db.getFitList() for fit in fitList: diff --git a/savedata/effs_util.py b/savedata/effs_util.py index 1b77238f8..93276d281 100644 --- a/savedata/effs_util.py +++ b/savedata/effs_util.py @@ -25,10 +25,14 @@ parser.add_option( help="Convert an exported pyfaFits.html file to a shipJSON file that Eve Fleet Simulator can import from\n" + " Note this process loses data like fleet boosters as the DNA format exported by to html contains limited data", \ default=False) -parser.add_option("-s", "--savepath", action="store", dest="savepath", help="Set the folder for savedata", default=None) +parser.add_option("-s", "--savepath", action="store", dest="savepath", + help="Set the folder for savedata", default=None) parser.add_option( "-o", "--outputpath", action="store", dest="outputpath", help="Output directory, defaults to the savepath", default=None) +parser.add_option( + '-i', "--search", action="store", dest="search", + help="Ignore ships and fits that don't contain the searched string", default=None) (options, args) = parser.parse_args() @@ -54,3 +58,155 @@ def printGroupData(): for group in data: print(group.groupName + ' groupID: ' + str(group.groupID)) return '' + +def printSizeData(): + from eos.db import gamedata_session + from eos.gamedata import Group + filterVal = Group.categoryID == 6 + data = gamedata_session.query(Group).options().filter(filterVal).all() + ships = gamedata_session.query(Group).options().filter(filterVal) + print(data) + print(vars(data[0])) + + shipSizes = ['Frigate', 'Destroyer', 'Cruiser', 'Battlecruiser', 'Battleship', 'Capital', 'Industrial', 'Misc'] + groupSets = [ + [25, 31, 237, 324, 830, 831, 834, 893, 1283, 1527], + [420, 541, 1305, 1534], + [26, 358, 832, 833, 894, 906, 963], + [419, 540, 1201], + [27, 381, 898, 900], + [30, 485, 513, 547, 659, 883, 902, 1538], + [28, 380, 1202, 463, 543, 941], + [29, 1022] + ] + i = 0 + while i < 8: + groupNames = '\'' + shipSizes[i] + '\': {\'name\': \'' + shipSizes[i] + '\', \'groupIDs\': groupIDFromGroupName([' + for gid in groupSets[i]: + if gid is not groupSets[i][0]: + groupNames = groupNames + '\', ' + groupNames = groupNames + '\'' + list(filter(lambda gr: gr.groupID == gid, data))[0].groupName + print(groupNames + '\'], data)}') + i = i + 1 + projectedModGroupIds = [ + 41, 52, 65, 67, 68, 71, 80, 201, 208, 291, 325, 379, 585, + 842, 899, 1150, 1154, 1189, 1306, 1672, 1697, 1698, 1815, 1894 + ] + from eos.db import gamedata_session + from eos.gamedata import Group + data = gamedata_session.query(Group).all() + groupNames = '' + for gid in projectedModGroupIds: + if gid is not projectedModGroupIds[0]: + groupNames = groupNames + '\', ' + print(gid) + groupNames = groupNames + '\'' + list(filter(lambda gr: gr.groupID == gid, data))[0].groupName + print(groupNames + '\'') + +def wepMultisFromTraitText(fit): + filterVal = Traits.typeID == fit.shipID + data = gamedata_session.query(Traits).options().filter(filterVal).all() + roleBonusMode = False + if len(data) == 0: + return multipliers + d = data[0] + s1 = str(vars(d)) + ds = s1.encode(encoding="utf-8", errors="ignore") + #print(ds) + previousTypedBonus = 0 + previousDroneTypeBonus = 0 + for bonusText in data[0].traitText.splitlines(): + bonusText = bonusText.lower() + if 'per skill level' in bonusText: + roleBonusMode = False + if 'role bonus' in bonusText or 'misc bonus' in bonusText: + roleBonusMode = True + multi = 1 + if 'damage' in bonusText and not any(e in bonusText for e in ['control', 'heat']): + splitText = bonusText.split('%') + if (float(splitText[0]) > 0) is False: + print('damage bonus split did not parse correctly!') + print(float(splitText[0])) + if roleBonusMode: + addedMulti = float(splitText[0]) + else: + addedMulti = float(splitText[0]) * 5 + if any(e in bonusText for e in [' em', 'thermal', 'kinetic', 'explosive']): + if addedMulti > previousTypedBonus: + previousTypedBonus = addedMulti + else: + addedMulti = 0 + if any(e in bonusText for e in ['heavy drone', 'medium drone', 'light drone', 'sentry drone']): + if addedMulti > previousDroneTypeBonus: + previousDroneTypeBonus = addedMulti + else: + addedMulti = 0 + multi = 1 + (addedMulti / 100) + elif 'rate of fire' in bonusText: + splitText = bonusText.split('%') + if (float(splitText[0]) > 0) is False: + print('rate of fire bonus split did not parse correctly!') + print(float(splitText[0])) + if roleBonusMode: + rofMulti = float(splitText[0]) + else: + rofMulti = float(splitText[0]) * 5 + multi = 1 / (1 - (rofMulti / 100)) + if multi > 1: + if 'drone' in bonusText.lower(): + multipliers['droneBandwidth'] *= multi + elif 'turret' in bonusText.lower(): + multipliers['turret'] *= multi + elif any(e in bonusText for e in ['missile', 'torpedo']): + multipliers['launcher'] *= multi + + +def examDiff(ai, bi, attr=False): + print('') + print('A:' + str(ai)) + print('B:' + str(bi)) + a = dict(map(lambda k: (k, getattr(ai, k)), dir(ai))) + b = dict(map(lambda k: (k, getattr(bi, k)), dir(bi))) + try: + print(a.keys()) + print('A:' + str(a)) + print(b.keys()) + print('B:' + str(b)) + print('A exclusive keys:') + for key in filter(lambda k: k not in b.keys(), a.keys()): + print(key) + print('B exclusive keys:') + for key in filter(lambda k: k not in a.keys(), b.keys()): + print(key) + print('A key/value pairs where B is None:') + for key in filter(lambda k: k in b.keys() and b[k] == None and a[k] != None, a.keys()): + print(key) + print(a[key]) + print('B key/value pairs where A is None:') + for key in filter(lambda k: k in a.keys() and a[k] == None and b[k] != None, b.keys()): + print(key) + print(b[key]) + except Exception as e: + if attr == True: + print('Could not print itemModifiedAttributes for a or b') + print(e) + else: + print('Checking itemModifiedAttributes diff') + examDiff(ai.itemModifiedAttributes, bi.itemModifiedAttributes, True) + if attr == False: + print('Checking itemModifiedAttributes diff') + examDiff(ai.itemModifiedAttributes, bi.itemModifiedAttributes, True) + print('') + +def groupIDFromGroupName(names, data=None): + # Group data can optionally be passed to the function to improve preformace with repeated calls. + if data is None: + data = gamedata_session.query(Group).all() + returnSingle = False + if not isinstance(names, list): + names = [names] + returnSingle = True + gidList = list(map(lambda incGroup: incGroup.groupID, (filter(lambda group: group.groupName in names, data)))) + if returnSingle: + return gidList[0] + return gidList diff --git a/savedata/getmods.py b/savedata/getmods.py new file mode 100644 index 000000000..16ef06103 --- /dev/null +++ b/savedata/getmods.py @@ -0,0 +1,88 @@ +# -*- coding: utf-8 -*- +#!/usr/bin/env python +if __name__ == "__main__": + import argparse + import json + import os.path + import sys + sys.path.append(os.getcwd()) + + from eos import * + from eos.data.data_handler import JsonDataHandler + from eos.const.eos import * + + json_path = r"/path/to/Phobos/dump" + + parser = argparse.ArgumentParser(description="Figure out what actually effect does") + parser.add_argument("-e", "--effect", type=str, required=True, help="effect name") + args = parser.parse_args() + + # open a few files to get human-readable names for data (EOS strictly works with numerical identifiers) + with open(os.path.join(json_path, "dgmattribs.json"), mode='r', encoding="utf8") as file: + dgmattribs = json.load(file) + + with open(os.path.join(json_path, 'dgmeffects.json'), mode='r', encoding="utf8") as file: + dgmeffects = json.load(file) + + with open(os.path.join(json_path, 'invtypes.json'), mode='r', encoding="utf8") as file: + invtypes = json.load(file) + + with open(os.path.join(json_path, 'invgroups.json'), mode='r', encoding="utf8") as file: + invgroups = json.load(file) + + attr_id_name = {} + attr_id_penalized = {} + for row in dgmattribs: + attr_id_name[row['attributeID']] = row['attributeName'] + attr_id_penalized[row['attributeID']] = 'not penalized' if row['stackable'] else 'penalized' + + effect_id_name = {} + for row in dgmeffects: + effect_id_name[row['effectID']] = row['effectName'] + if row['effectName'] == args.effect: + effect_id = row['effectID'] + break + + type_id_name = {} + for _, row in invtypes.items(): + name = row.get("typeName_en-us", None) + if name: + type_id_name[row['typeID']] = name + + group_id_name = {} + for _, row in invgroups.items(): + group_id_name[row['groupID']] = row['groupName_en-us'] + + data_handler = JsonDataHandler(json_path) # Folder with Phobos data dump + cache_handler = JsonCacheHandler(os.path.join(json_path, "cache", "eos_tq.json.bz2")) + SourceManager.add('evedata', data_handler, cache_handler, make_default=True) + + effect = cache_handler.get_effect(effect_id) + modifiers = effect.modifiers + mod_counter = 1 + indent = ' ' + print('effect {}.py (id: {}) - build status is {}'.format(args.effect.lower(), effect_id, EffectBuildStatus(effect.build_status).name)) + for modifier in modifiers: + print('{}Modifier {}:'.format(indent, mod_counter)) + print('{0}{0}state: {1}'.format(indent, State(modifier.state).name)) + print('{0}{0}scope: {1}'.format(indent, Scope(modifier.scope).name)) + print('{0}{0}srcattr: {1} {2}'.format(indent, attr_id_name[modifier.src_attr], modifier.src_attr)) + print('{0}{0}operator: {1} {2}'.format(indent, Operator(modifier.operator).name, modifier.operator)) + print('{0}{0}tgtattr: {1} ({2}) {3}'.format( + indent, + attr_id_name[modifier.tgt_attr], + attr_id_penalized[modifier.tgt_attr],modifier.tgt_attr) + ) + print('{0}{0}location: {1}'.format(indent, Domain(modifier.domain).name)) + try: + filter_type = FilterType(modifier.filter_type).name + except ValueError: + filter_type = None + print('{0}{0}filter type: {1}'.format(indent, filter_type)) + if modifier.filter_type is None or modifier.filter_type in (FilterType.all_, FilterType.skill_self): + pass + elif modifier.filter_type == FilterType.skill: + print('{0}{0}filter value: {1}'.format(indent, type_id_name[modifier.filter_value])) + elif modifier.filter_type == FilterType.group: + print('{0}{0}filter value: {1}'.format(indent, group_id_name[modifier.filter_value])) + mod_counter += 1 diff --git a/savedata/makeAndDiffCheck.sh b/savedata/makeAndDiffCheck.sh new file mode 100755 index 000000000..6b3bb7640 --- /dev/null +++ b/savedata/makeAndDiffCheck.sh @@ -0,0 +1,55 @@ +#!/bin/bash +if [[ $2 == -v ]] ; then + MUTE=False +else + MUTE=TRUE +fi +EXPECTERRORS=False +if [[ $3 == --search ]] ; then + if [[ $5 == --expect-errors ]] ; then + EXPECTERRORS=True + fi +else + if [[ $3 == --expect-errors ]] ; then + EXPECTERRORS=True + fi +fi +if [[ $1 == -f ]] ; then + if [[ $MUTE == TRUE ]] ; then + python3opt savedata/effs_util.py\ -f | grep awgahwogfa + else + python3opt savedata/effs_util.py\ -f\ --search=$4 + fi +elif [[ $1 == -b ]] ; then + if [[ $MUTE == TRUE ]] ; then + python3opt savedata/effs_util.py\ -b | grep awgahwogfa + else + python3opt savedata/effs_util.py\ -b\ --search=$4 + fi +elif [[ $1 == -u ]] ; then + if [[ $MUTE == TRUE ]] ; then + python3opt savedata/effs_util.py\ -b\ -f\ -o\ .. | grep awgahwogfa + else + python3opt savedata/effs_util.py\ -b\ -f\ -o\ .. + fi +elif [[ $1 == -a ]] ; then + if [[ $MUTE == TRUE ]] ; then + python3opt savedata/effs_util.py\ -b\ -f | grep awgahwogfa + else + python3opt savedata/effs_util.py\ -b\ -f\ --search=$4 + fi +else + echo Defaulting to fits and base ships.\n + if [[ $MUTE == TRUE ]] ; then + python3opt savedata/effs_util.py\ -b\ -f | grep awgahwogfa + else + python3opt savedata/effs_util.py\ -b\ -f\ --search=$4 + fi +fi +if [[ $EXPECTERRORS == True ]] ; then + echo Expecting non standard output, this should only be used for testing +else +diff -s --color=always ../shipJSON.js ~/.pyfa/shipJSON.js | grep -m 3 --color '' +diff -s --color=always ../shipBaseJSON.js ~/.pyfa/shipBaseJSON.js | grep -m 3 --color '' +/home/stock/scripts/Pyfa/.tox/pep8/bin/flake8 --exclude=.svn,CVS,.bzr,.hg,.git,__pycache__,venv,tests,.tox,build,dist,__init__.py,floatspin.py --ignore=E121,E126,E127,E128,E203,E731,F401,E722,E741 effs_stat_export.py --max-line-length=165 +fi From 7af5c17015127935f58e9bd8336b1082bb28360d Mon Sep 17 00:00:00 2001 From: Maru Maru Date: Fri, 6 Jul 2018 14:01:54 -0400 Subject: [PATCH 13/32] Changed the name of Eve Fleet Fight Simulator to Eve Fleet Simulator and updated refs to match --- .gitignore | 2 +- effs_stat_export.py => efs_stat_export.py | 14 ++++++------ gui/copySelectDialog.py | 6 ++--- gui/mainFrame.py | 8 +++---- ...ort_all_fits.py => efs_export_all_fits.py} | 0 ...t_base_fits.py => efs_export_base_fits.py} | 18 ++++++++++----- ...t_pyfa_fits.py => efs_export_pyfa_fits.py} | 2 +- ...l_export.py => efs_process_html_export.py} | 4 ++-- savedata/{effs_util.py => efs_util.py} | 8 +++---- savedata/makeAndDiffCheck.sh | 22 +++++++++---------- 10 files changed, 45 insertions(+), 39 deletions(-) rename effs_stat_export.py => efs_stat_export.py (98%) rename savedata/{effs_export_all_fits.py => efs_export_all_fits.py} (100%) rename savedata/{effs_export_base_fits.py => efs_export_base_fits.py} (93%) rename savedata/{effs_export_pyfa_fits.py => efs_export_pyfa_fits.py} (96%) rename savedata/{effs_process_html_export.py => efs_process_html_export.py} (96%) rename savedata/{effs_util.py => efs_util.py} (97%) diff --git a/.gitignore b/.gitignore index e520bee03..a9f2eb124 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -#Fit and ship export data generated by effs_stat_export.py +#Fit and ship export data generated by efs_stat_export.py *JSON.js #Python specific diff --git a/effs_stat_export.py b/efs_stat_export.py similarity index 98% rename from effs_stat_export.py rename to efs_stat_export.py index e723f5485..a8e50f7f4 100755 --- a/effs_stat_export.py +++ b/efs_stat_export.py @@ -543,10 +543,10 @@ def getShipSize(groupID): def parseNeededFitDetails(fit, groupID): includeShipTypeData = groupID > 0 fitID = fit.ID - if len(fit.modules) > 0: - fitName = fit.ship.name + ': ' + fit.name - else: + if includeShipTypeData: fitName = fit.name + else: + fitName = fit.ship.name + ': ' + fit.name print('') print('name: ' + fit.name) fitL = Fit.getInstance() @@ -599,9 +599,9 @@ def parseNeededFitDetails(fit, groupID): 'rigSlots': fitModAttr['rigSlots'], 'lowSlots': fitModAttr['lowSlots'], 'midSlots': fitModAttr['medSlots'], 'highSlots': fitModAttr['hiSlots'], 'turretSlots': fitModAttr['turretSlotsLeft'], 'launcherSlots': fitModAttr['launcherSlotsLeft'], - 'powerOutput': fitModAttr['powerOutput'], 'rigSize': fitModAttr['rigSize'], - 'effectiveTurrets': effectiveTurretSlots, 'effectiveLaunchers': effectiveLauncherSlots, - 'effectiveDroneBandwidth': effectiveDroneBandwidth, + 'powerOutput': fitModAttr['powerOutput'], 'cpuOutput': fitModAttr['cpuOutput'], + 'rigSize': fitModAttr['rigSize'], 'effectiveTurrets': effectiveTurretSlots, + 'effectiveLaunchers': effectiveLauncherSlots, 'effectiveDroneBandwidth': effectiveDroneBandwidth, 'resonance': resonance, 'typeID': fit.shipID, 'groupID': groupID, 'shipSize': shipSize, 'droneControlRange': fitModAttr['droneControlRange'], 'mass': fitModAttr['mass'], 'moduleNames': moduleNames, 'projections': projections, @@ -611,6 +611,6 @@ def parseNeededFitDetails(fit, groupID): except TypeError: print('Error parsing fit:' + str(fit)) print(TypeError) - parsable = {'name': fitName + 'Fit could not be correctly parsed'} + dataDict = {'name': fitName + 'Fit could not be correctly parsed'} export = json.dumps(dataDict, skipkeys=True) return export diff --git a/gui/copySelectDialog.py b/gui/copySelectDialog.py index c1e784853..0c6fe35a2 100644 --- a/gui/copySelectDialog.py +++ b/gui/copySelectDialog.py @@ -29,21 +29,21 @@ class CopySelectDialog(wx.Dialog): copyFormatDna = 3 copyFormatEsi = 4 copyFormatMultiBuy = 5 - copyFormatEffs = 6 + copyFormatEfs = 6 def __init__(self, parent): wx.Dialog.__init__(self, parent, id=wx.ID_ANY, title="Select a format", size=(-1, -1), style=wx.DEFAULT_DIALOG_STYLE) mainSizer = wx.BoxSizer(wx.VERTICAL) - copyFormats = ["EFT", "EFT (Implants)", "XML", "DNA", "CREST", "MultiBuy", "EFFS"] + copyFormats = ["EFT", "EFT (Implants)", "XML", "DNA", "CREST", "MultiBuy", "EFS"] copyFormatTooltips = {CopySelectDialog.copyFormatEft: "EFT text format", CopySelectDialog.copyFormatEftImps: "EFT text format", CopySelectDialog.copyFormatXml: "EVE native XML format", CopySelectDialog.copyFormatDna: "A one-line text format", CopySelectDialog.copyFormatEsi: "A JSON format used for EVE CREST", CopySelectDialog.copyFormatMultiBuy: "MultiBuy text format", - CopySelectDialog.copyFormatEffs: u"EFFS json stats format"} + CopySelectDialog.copyFormatEfs: u"EFS json stats format"} selector = wx.RadioBox(self, wx.ID_ANY, label="Copy to the clipboard using:", choices=copyFormats, style=wx.RA_SPECIFY_ROWS) selector.Bind(wx.EVT_RADIOBOX, self.Selected) diff --git a/gui/mainFrame.py b/gui/mainFrame.py index 4b7366e4a..3458cd6d0 100644 --- a/gui/mainFrame.py +++ b/gui/mainFrame.py @@ -79,7 +79,7 @@ from eos.db.saveddata.queries import getFit as db_getFit from service.port import Port, IPortUser from service.settings import HTMLExportSettings -from effs_stat_export import parseNeededFitDetails as exportEffsStats +from efs_stat_export import parseNeededFitDetails as exportEfsStats from time import gmtime, strftime @@ -728,9 +728,9 @@ class MainFrame(wx.Frame): fit = db_getFit(self.getActiveFit()) toClipboard(Port.exportMultiBuy(fit)) - def clipboardEffs(self): + def clipboardEfs(self): fit = db_getFit(self.getActiveFit()) - toClipboard(exportEffsStats(fit, 0)) + toClipboard(exportEfsStats(fit, 0)) def importFromClipboard(self, event): clipboard = fromClipboard() @@ -748,7 +748,7 @@ class MainFrame(wx.Frame): CopySelectDialog.copyFormatDna: self.clipboardDna, CopySelectDialog.copyFormatEsi: self.clipboardEsi, CopySelectDialog.copyFormatMultiBuy: self.clipboardMultiBuy, - CopySelectDialog.copyFormatEffs: self.clipboardEffs} + CopySelectDialog.copyFormatEfs: self.clipboardEfs} dlg = CopySelectDialog(self) dlg.ShowModal() selected = dlg.GetSelected() diff --git a/savedata/effs_export_all_fits.py b/savedata/efs_export_all_fits.py similarity index 100% rename from savedata/effs_export_all_fits.py rename to savedata/efs_export_all_fits.py diff --git a/savedata/effs_export_base_fits.py b/savedata/efs_export_base_fits.py similarity index 93% rename from savedata/effs_export_base_fits.py rename to savedata/efs_export_base_fits.py index c08c6c003..a4fa8404d 100644 --- a/savedata/effs_export_base_fits.py +++ b/savedata/efs_export_base_fits.py @@ -78,7 +78,7 @@ eos.db.saveddata_meta.create_all() import json from service.fit import Fit -from effs_stat_export import parseNeededFitDetails +from efs_stat_export import parseNeededFitDetails from sqlalchemy import Column, String, Integer, ForeignKey, Boolean, Table from sqlalchemy.orm import relation, mapper, synonym, deferred @@ -140,7 +140,11 @@ def t3dGetStatSet(dnaString, shipName, groupID, raceID): n = 0 while n < len(t3dModes): dna = dnaString + ':' + str(t3dModes[n].ID) + ';1' - shipModeData += setFitFromString(dna, t3dModes[n].name, groupID) + ',\n' + #Don't add the new line for the last mode + if n < len(t3dModes) - 1: + shipModeData += setFitFromString(dna, t3dModes[n].name, groupID) + ',\n' + else: + shipModeData += setFitFromString(dna, t3dModes[n].name, groupID) n += 1 return shipModeData @@ -168,8 +172,11 @@ def t3cGetStatSet(dnaString, shipName, groupID, raceID): dna = dnaString + ':' + str(ss[0][a].ID) \ + ';1:' + str(ss[1][b].ID) + ';1:' + str(ss[2][c].ID) \ + ';1:' + str(ss[3][d].ID) + ';1' - name = shipName + str(a) + str(b) + str(c) + str(d) - shipPermutationData += setFitFromString(dna, name, groupID) + ',\n' + #Don't add the new line for the last permutation + if a == 2 and b == 2 and c == 2 and d == 2: + shipPermutationData += setFitFromString(dna, shipName, groupID) + else: + shipPermutationData += setFitFromString(dna, shipName, groupID) + ',\n' d += 1 n += 1 c += 1 @@ -193,7 +200,6 @@ def setFitFromString(dnaString, fitName, groupID) : print('Cannot find correct link fits for base calculations') return '' modArray = dnaString.split(':') - additionalModeFit = '' fitL = Fit() fitID = fitL.newFit(int(modArray[0]), fitName) fit = eos.db.getFit(fitID) @@ -246,4 +252,4 @@ def setFitFromString(dnaString, fitName, groupID) : fitL.addCommandFit(fit.ID, infoLinkShip) jsonStr = parseNeededFitDetails(fit, groupID) Fit.deleteFit(fitID) - return jsonStr + additionalModeFit + return jsonStr diff --git a/savedata/effs_export_pyfa_fits.py b/savedata/efs_export_pyfa_fits.py similarity index 96% rename from savedata/effs_export_pyfa_fits.py rename to savedata/efs_export_pyfa_fits.py index 82949f1c4..749fdc1d4 100644 --- a/savedata/effs_export_pyfa_fits.py +++ b/savedata/efs_export_pyfa_fits.py @@ -19,7 +19,7 @@ import eos.db if not os.path.exists(config.savePath): os.mkdir(config.savePath) -from effs_stat_export import parseNeededFitDetails +from efs_stat_export import parseNeededFitDetails def exportPyfaFits(opts): nameReq = '' diff --git a/savedata/effs_process_html_export.py b/savedata/efs_process_html_export.py similarity index 96% rename from savedata/effs_process_html_export.py rename to savedata/efs_process_html_export.py index 5d89a4547..8e48bda3c 100644 --- a/savedata/effs_process_html_export.py +++ b/savedata/efs_process_html_export.py @@ -1,6 +1,6 @@ -from effs_export_base_fits import * +from efs_export_base_fits import * -def effsFitsFromHTMLExport(opts): +def efsFitsFromHTMLExport(opts): if opts: if opts.outputpath: basePath = opts.outputpath diff --git a/savedata/effs_util.py b/savedata/efs_util.py similarity index 97% rename from savedata/effs_util.py rename to savedata/efs_util.py index 93276d281..e52ee82bd 100644 --- a/savedata/effs_util.py +++ b/savedata/efs_util.py @@ -38,16 +38,16 @@ parser.add_option( (options, args) = parser.parse_args() if options.exportfits: - from effs_export_pyfa_fits import exportPyfaFits + from efs_export_pyfa_fits import exportPyfaFits exportPyfaFits(options) if options.exportbaseships: - from effs_export_base_fits import exportBaseShips + from efs_export_base_fits import exportBaseShips exportBaseShips(options) if options.convertfitsfromhtml: - from effs_process_html_export import effsFitsFromHTMLExport - effsFitsFromHTMLExport(options) + from efs_process_html_export import efsFitsFromHTMLExport + efsFitsFromHTMLExport(options) #stuff bellow this point is purely scrap diagnostic stuff and should not be public (as it's scrawl) def printGroupData(): diff --git a/savedata/makeAndDiffCheck.sh b/savedata/makeAndDiffCheck.sh index 6b3bb7640..84ddd89a5 100755 --- a/savedata/makeAndDiffCheck.sh +++ b/savedata/makeAndDiffCheck.sh @@ -16,34 +16,34 @@ else fi if [[ $1 == -f ]] ; then if [[ $MUTE == TRUE ]] ; then - python3opt savedata/effs_util.py\ -f | grep awgahwogfa + python3opt savedata/efs_util.py\ -f | grep awgahwogfa else - python3opt savedata/effs_util.py\ -f\ --search=$4 + python3opt savedata/efs_util.py\ -f\ --search=$4 fi elif [[ $1 == -b ]] ; then if [[ $MUTE == TRUE ]] ; then - python3opt savedata/effs_util.py\ -b | grep awgahwogfa + python3opt savedata/efs_util.py\ -b | grep awgahwogfa else - python3opt savedata/effs_util.py\ -b\ --search=$4 + python3opt savedata/efs_util.py\ -b\ --search=$4 fi elif [[ $1 == -u ]] ; then if [[ $MUTE == TRUE ]] ; then - python3opt savedata/effs_util.py\ -b\ -f\ -o\ .. | grep awgahwogfa + python3opt savedata/efs_util.py\ -b\ -f\ -o\ .. | grep awgahwogfa else - python3opt savedata/effs_util.py\ -b\ -f\ -o\ .. + python3opt savedata/efs_util.py\ -b\ -f\ -o\ .. fi elif [[ $1 == -a ]] ; then if [[ $MUTE == TRUE ]] ; then - python3opt savedata/effs_util.py\ -b\ -f | grep awgahwogfa + python3opt savedata/efs_util.py\ -b\ -f | grep awgahwogfa else - python3opt savedata/effs_util.py\ -b\ -f\ --search=$4 + python3opt savedata/efs_util.py\ -b\ -f\ --search=$4 fi else echo Defaulting to fits and base ships.\n if [[ $MUTE == TRUE ]] ; then - python3opt savedata/effs_util.py\ -b\ -f | grep awgahwogfa + python3opt savedata/efs_util.py\ -b\ -f | grep awgahwogfa else - python3opt savedata/effs_util.py\ -b\ -f\ --search=$4 + python3opt savedata/efs_util.py\ -b\ -f\ --search=$4 fi fi if [[ $EXPECTERRORS == True ]] ; then @@ -51,5 +51,5 @@ if [[ $EXPECTERRORS == True ]] ; then else diff -s --color=always ../shipJSON.js ~/.pyfa/shipJSON.js | grep -m 3 --color '' diff -s --color=always ../shipBaseJSON.js ~/.pyfa/shipBaseJSON.js | grep -m 3 --color '' -/home/stock/scripts/Pyfa/.tox/pep8/bin/flake8 --exclude=.svn,CVS,.bzr,.hg,.git,__pycache__,venv,tests,.tox,build,dist,__init__.py,floatspin.py --ignore=E121,E126,E127,E128,E203,E731,F401,E722,E741 effs_stat_export.py --max-line-length=165 +/home/stock/scripts/Pyfa/.tox/pep8/bin/flake8 --exclude=.svn,CVS,.bzr,.hg,.git,__pycache__,venv,tests,.tox,build,dist,__init__.py,floatspin.py --ignore=E121,E126,E127,E128,E203,E731,F401,E722,E741 efs_stat_export.py --max-line-length=165 fi From 7a078f433a0facaa769e577befd78a38b2b66382 Mon Sep 17 00:00:00 2001 From: Maru Maru Date: Wed, 11 Jul 2018 12:05:57 -0400 Subject: [PATCH 14/32] draft of misc patches for main branch --- eos/db/saveddata/fit.py | 2 +- eos/effects/skillbonusdronedurability.py | 2 +- eos/effects/skillbonusdroneinterfacing.py | 2 +- eos/gamedata.py | 2 +- .../pyfaGeneralPreferences.py | 10 ++ gui/characterSelection.py | 138 +++++++++++++++++- gui/itemStats.py | 2 +- service/fit.py | 6 +- 8 files changed, 152 insertions(+), 12 deletions(-) diff --git a/eos/db/saveddata/fit.py b/eos/db/saveddata/fit.py index 07375dcaf..0c34d5279 100644 --- a/eos/db/saveddata/fit.py +++ b/eos/db/saveddata/fit.py @@ -56,7 +56,7 @@ fits_table = Table("fits", saveddata_meta, Column("booster", Boolean, nullable=False, index=True, default=0), Column("targetResistsID", ForeignKey("targetResists.ID"), nullable=True), Column("modeID", Integer, nullable=True), - Column("implantLocation", Integer, nullable=False, default=ImplantLocation.FIT), + Column("implantLocation", Integer, nullable=True), Column("notes", String, nullable=True), Column("ignoreRestrictions", Boolean, default=0), Column("created", DateTime, nullable=True, default=datetime.datetime.now), diff --git a/eos/effects/skillbonusdronedurability.py b/eos/effects/skillbonusdronedurability.py index 1023c8412..f36e82a3f 100644 --- a/eos/effects/skillbonusdronedurability.py +++ b/eos/effects/skillbonusdronedurability.py @@ -6,7 +6,7 @@ type = "passive" def handler(fit, src, context): - lvl = src.level + lvl = src.level if "skill" in context else 1 fit.drones.filteredItemBoost(lambda mod: mod.item.requiresSkill("Drones"), "hp", src.getModifiedItemAttr("hullHpBonus") * lvl) fit.drones.filteredItemBoost(lambda mod: mod.item.requiresSkill("Drones"), "armorHP", diff --git a/eos/effects/skillbonusdroneinterfacing.py b/eos/effects/skillbonusdroneinterfacing.py index 4aec63e83..d832d432b 100644 --- a/eos/effects/skillbonusdroneinterfacing.py +++ b/eos/effects/skillbonusdroneinterfacing.py @@ -6,7 +6,7 @@ type = "passive" def handler(fit, src, context): - lvl = src.level + lvl = src.level if "skill" in context else 1 fit.drones.filteredItemBoost(lambda mod: mod.item.requiresSkill("Drones"), "damageMultiplier", src.getModifiedItemAttr("damageMultiplierBonus") * lvl) fit.fighters.filteredItemBoost(lambda mod: mod.item.requiresSkill("Fighters"), diff --git a/eos/gamedata.py b/eos/gamedata.py index 342a4caf4..243f71bad 100644 --- a/eos/gamedata.py +++ b/eos/gamedata.py @@ -592,7 +592,7 @@ class Unit(EqBase): lambda d: d * 1000.0, lambda u: u), "Boolean": ( - lambda v, u: "Yes" if v == 1 else "No", + lambda v: "Yes" if v == 1 else "No", lambda d: 1.0 if d == "Yes" else 0.0, lambda u: ""), "typeID": ( diff --git a/gui/builtinPreferenceViews/pyfaGeneralPreferences.py b/gui/builtinPreferenceViews/pyfaGeneralPreferences.py index 412e1a988..6dc9b8ecb 100644 --- a/gui/builtinPreferenceViews/pyfaGeneralPreferences.py +++ b/gui/builtinPreferenceViews/pyfaGeneralPreferences.py @@ -34,6 +34,10 @@ class PFGeneralPref(PreferenceView): self.m_staticline1 = wx.StaticLine(panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL) mainSizer.Add(self.m_staticline1, 0, wx.EXPAND | wx.TOP | wx.BOTTOM, 5) + self.cbDefaultCharImplants = wx.CheckBox(panel, wx.ID_ANY, "Have new fits default to character implants", + wx.DefaultPosition, wx.DefaultSize, 0) + mainSizer.Add(self.cbDefaultCharImplants, 0, wx.ALL | wx.EXPAND, 5) + self.cbGlobalChar = wx.CheckBox(panel, wx.ID_ANY, "Use global character", wx.DefaultPosition, wx.DefaultSize, 0) mainSizer.Add(self.cbGlobalChar, 0, wx.ALL | wx.EXPAND, 5) @@ -118,6 +122,7 @@ class PFGeneralPref(PreferenceView): self.sFit = Fit.getInstance() + self.cbDefaultCharImplants.SetValue(self.sFit.serviceFittingOptions["useCharecterImplantsByDefault"]) self.cbGlobalChar.SetValue(self.sFit.serviceFittingOptions["useGlobalCharacter"]) self.cbGlobalDmgPattern.SetValue(self.sFit.serviceFittingOptions["useGlobalDamagePattern"]) self.cbFitColorSlots.SetValue(self.sFit.serviceFittingOptions["colorFitBySlot"] or False) @@ -135,6 +140,7 @@ class PFGeneralPref(PreferenceView): self.cbShowShipBrowserTooltip.SetValue(self.sFit.serviceFittingOptions["showShipBrowserTooltip"]) self.intDelay.SetValue(self.sFit.serviceFittingOptions["marketSearchDelay"]) + self.cbDefaultCharImplants.Bind(wx.EVT_CHECKBOX, self.OnCBDefaultCharImplantsStateChange) self.cbGlobalChar.Bind(wx.EVT_CHECKBOX, self.OnCBGlobalCharStateChange) self.cbGlobalDmgPattern.Bind(wx.EVT_CHECKBOX, self.OnCBGlobalDmgPatternStateChange) self.cbFitColorSlots.Bind(wx.EVT_CHECKBOX, self.onCBGlobalColorBySlot) @@ -183,6 +189,10 @@ class PFGeneralPref(PreferenceView): wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) event.Skip() + def OnCBDefaultCharImplantsStateChange(self, event): + self.sFit.serviceFittingOptions["useCharecterImplantsByDefault"] = self.cbDefaultCharImplants.GetValue() + event.Skip() + def OnCBGlobalCharStateChange(self, event): self.sFit.serviceFittingOptions["useGlobalCharacter"] = self.cbGlobalChar.GetValue() event.Skip() diff --git a/gui/characterSelection.py b/gui/characterSelection.py index 051ce69b4..b6b034a4c 100644 --- a/gui/characterSelection.py +++ b/gui/characterSelection.py @@ -45,8 +45,15 @@ class CharacterSelection(wx.Panel): # cache current selection to fall back in case we choose to open char editor self.charCache = None - self.charChoice = wx.Choice(self) - mainSizer.Add(self.charChoice, 1, wx.ALIGN_CENTER_VERTICAL | wx.RIGHT | wx.LEFT, 3) + #self.charChoice = wx.Choice(self) + #self.charChoice.Append('blarg') + #self.charChoice = wx.Choice(self, wx.ID_ANY, wx.Point(-1,0), wx.DefaultSize, [], style=0, validator=wx.DefaultValidator, name='welp') + self.charChoice = wx.ComboBox( + self, id=wx.ID_ANY, value="", pos=wx.DefaultPosition, + size=wx.DefaultSize, choices=[], style=wx.CB_READONLY, validator=wx.DefaultValidator, + name='welp' + ) + mainSizer.Add(self.charChoice, 1, wx.ALIGN_RIGHT | wx.RIGHT | wx.LEFT, 3) self.refreshCharacterList() @@ -74,7 +81,8 @@ class CharacterSelection(wx.Panel): self.skillReqsStaticBitmap.Bind(wx.EVT_RIGHT_UP, self.OnContextMenu) - self.Bind(wx.EVT_CHOICE, self.charChanged) + #self.Bind(wx.EVT_CHOICE, self.charChanged) + self.Bind(wx.EVT_COMBOBOX, self.charChanged) self.mainFrame.Bind(GE.CHAR_LIST_UPDATED, self.refreshCharacterList) self.mainFrame.Bind(GE.FIT_CHANGED, self.fitChanged) @@ -120,6 +128,91 @@ class CharacterSelection(wx.Panel): selection = self.charChoice.GetCurrentSelection() return self.charChoice.GetClientData(selection) if selection is not -1 else None + def padChoice(self, ind): + return; + from logbook import Logger + pyfalog = Logger(__name__) + #sChar = Character.getInstance() + #activeChar = self.getActiveCharacter() + #charList = sorted(sChar.getCharacterList(), key=lambda c: (not c.ro, c.name)) + charList = list(self.charChoice.GetItems()) + selection = charList[ind] + maxOverallLength = max(map(lambda c: self.mainFrame.GetTextExtent(c).x, charList)) + maxOverallLength = max(self.mainFrame.GetTextExtent("\u2015 Open Character Editor \u2015").x, maxOverallLength) + summedSizeO = sum([ + self.btnRefresh.GetSize().x if 'btnRefresh' in dir(self) else 0, + self.skillReqsStaticBitmap.GetSize().x if 'skillReqsStaticBitmap' in dir(self) else 0, + self.mainFrame.GetTextExtent("Character: ").x, + self.charChoice.GetSize().x if 'charChoice' in dir(self) \ + and self.charChoice is not None and 'GetSize' in dir(self.charChoice) else 0, + ]) + summedSize = sum([ + self.btnRefresh.GetSize().x if 'btnRefresh' in dir(self) else 0, + self.skillReqsStaticBitmap.GetSize().x if 'skillReqsStaticBitmap' in dir(self) else 0, + self.mainFrame.GetTextExtent("Character: ").x, + self.charCache.GetSize().x if 'charCache' in dir(self) \ + and self.charCache is not None and 'GetSize' in dir(self.charCache) else 0 + ]) + realSize = self.GetSize().x + #sizeGap = summedSize - realSize + sizeGap = self.GetBestVirtualSize().x - realSize + paddedName = selection + + maxFromContent = self.mainFrame.GetTextExtent(paddedName).x + sizeGap + maxLength = min(maxFromContent, maxOverallLength) + paddingOccured = False + while self.mainFrame.GetTextExtent(' ' + paddedName).x <= maxLength: + paddingOccured = True + paddedName = ' ' + paddedName + charIDRef = int(self.charChoice.GetClientData(ind)) + pyfalog.error('wwwww') + pyfalog.error(paddedName) + pyfalog.error(self.mainFrame.GetTextExtent(paddedName).x) + pyfalog.error(maxFromContent) + pyfalog.error(maxOverallLength) + pyfalog.error('\n') + pyfalog.error(self.charChoice.GetContainingSizer().GetSize().x) + pyfalog.error(realSize) + pyfalog.error(self.GetBestSize().x) + pyfalog.error(self.GetBestVirtualSize().x) + pyfalog.error('\n') + pyfalog.error(summedSizeO) + pyfalog.error(summedSize) + pyfalog.error( + self.charChoice.GetSize().x if 'charChoice' in dir(self) \ + and self.charChoice is not None and 'GetSize' in dir(self.charChoice) else 0 + ) + pyfalog.error( + self.charCache.GetSize().x if 'charCache' in dir(self) \ + and self.charCache is not None and 'GetSize' in dir(self.charCache) else 0 + ) + pyfalog.error(charIDRef) + pyfalog.error(ind) + pyfalog.error(list(self.charChoice.GetItems())) + ### + import re + for i in range(len(self.charChoice.GetItems())): + origStr = list(self.charChoice.GetItems())[i] + idStore = int(self.charChoice.GetClientData(i)) + self.charChoice.Delete(i) + trimmedStr = '' + for n in range(len(origStr)): + if trimmedStr is not '' or origStr[n] != ' ': + trimmedStr += origStr[n] + possibleName = trimmedStr#re.split(" *", origStr) + pyfalog.error('uuu') + pyfalog.error(possibleName) + self.charChoice.Insert(possibleName, i, idStore) + + if paddingOccured: + self.charChoice.Delete(ind) + pyfalog.error(list(self.charChoice.GetItems())) + self.charChoice.Insert(paddedName, ind, charIDRef) + self.charChoice.Select(ind) + pyfalog.error(list(self.charChoice.GetItems())) + pyfalog.error(int(self.charChoice.GetClientData(ind))) + pyfalog.error('wwwww') + def refreshCharacterList(self, event=None): choice = self.charChoice sChar = Character.getInstance() @@ -128,10 +221,30 @@ class CharacterSelection(wx.Panel): choice.Clear() charList = sorted(sChar.getCharacterList(), key=lambda c: (not c.ro, c.name)) picked = False - + from logbook import Logger + pyfalog = Logger(__name__) + maxOverallLength = max(map(lambda c: self.mainFrame.GetTextExtent(c.name).x, charList)) + maxOverallLength = max(self.mainFrame.GetTextExtent("\u2015 Open Character Editor \u2015").x, maxOverallLength) + #summedSize = sum([ + # self.btnRefresh.GetSize().x if 'btnRefresh' in dir(self) else 0, + # self.skillReqsStaticBitmap.GetSize().x if 'skillReqsStaticBitmap' in dir(self) else 0, + # self.mainFrame.GetTextExtent("Character: ").x, + # self.charCache.GetSize().x if 'charCache' in dir(self) and self.charCache is not None else 0, + # ]) + #realSize = self.GetSize().x + #sizeGap = summedSize - realSize for char in charList: - currId = choice.Append(char.name, char.ID) + paddedName = char.name + #maxFromContent = self.mainFrame.GetTextExtent(paddedName).x + self.mainFrame.GetTextExtent("Character: ").x + #maxFromContent = self.mainFrame.GetTextExtent(paddedName).x + sizeGap + #maxLength = min(maxFromContent, maxOverallLength) + #while self.mainFrame.GetTextExtent(paddedName).x < maxLength: + # paddedName = ' ' + paddedName + #currId = choice.Append(str(maxFromContent) + ' ' + \ + # str(self.mainFrame.GetTextExtent(paddedName).x) + ' ' + str(maxLength), char.ID) + currId = choice.Append(paddedName, char.ID) if char.ID == activeChar: + self.padChoice(currId) choice.SetSelection(currId) self.charChanged(None) picked = True @@ -173,16 +286,27 @@ class CharacterSelection(wx.Panel): if charID == -1: # revert to previous character + self.padChoice(self.charCache) + pyfalog.error('GGG') self.charChoice.SetSelection(self.charCache) + pyfalog.error('GGG') self.mainFrame.showCharacterEditor(event) + pyfalog.error('GGG') return - + self.padChoice(self.charChoice.GetCurrentSelection()) + fitID = self.mainFrame.getActiveFit() + charID = self.getActiveCharacter() + pyfalog.error(self.getActiveCharacter()) self.toggleRefreshButton() + pyfalog.error('RRR') sFit = Fit.getInstance() sFit.changeChar(fitID, charID) self.charCache = self.charChoice.GetCurrentSelection() + pyfalog.error('RRR') + pyfalog.error(fitID) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) + pyfalog.error('RRR') def toggleRefreshButton(self): charID = self.getActiveCharacter() @@ -199,6 +323,8 @@ class CharacterSelection(wx.Panel): for i in range(numItems): id_ = choice.GetClientData(i) if id_ == charID: + print((list(choice.GetItems())[0])) + self.padChoice(i) choice.SetSelection(i) return True diff --git a/gui/itemStats.py b/gui/itemStats.py index 6a75b543d..3768780e2 100644 --- a/gui/itemStats.py +++ b/gui/itemStats.py @@ -102,7 +102,7 @@ class ItemStatsDialog(wx.Dialog): if "wxGTK" in wx.PlatformInfo: self.closeBtn = wx.Button(self, wx.ID_ANY, "Close", wx.DefaultPosition, wx.DefaultSize, 0) self.mainSizer.Add(self.closeBtn, 0, wx.ALL | wx.ALIGN_RIGHT, 5) - self.closeBtn.Bind(wx.EVT_BUTTON, self.closeEvent) + self.closeBtn.Bind(wx.EVT_BUTTON, (lambda e: self.Close())) self.SetSizer(self.mainSizer) diff --git a/service/fit.py b/service/fit.py index dccb58e5e..4772f87af 100644 --- a/service/fit.py +++ b/service/fit.py @@ -33,7 +33,7 @@ from eos.saveddata.fighter import Fighter as es_Fighter from eos.saveddata.implant import Implant as es_Implant from eos.saveddata.ship import Ship as es_Ship from eos.saveddata.module import Module as es_Module, State, Slot -from eos.saveddata.fit import Fit as FitType +from eos.saveddata.fit import Fit as FitType, ImplantLocation from service.character import Character from service.damagePattern import DamagePattern from service.settings import SettingsProvider @@ -60,6 +60,7 @@ class Fit(object): self.dirtyFitIDs = set() serviceFittingDefaultOptions = { + "useCharecterImplantsByDefault": True, "useGlobalCharacter": False, "useGlobalDamagePattern": False, "defaultCharacter": self.character.ID, @@ -147,6 +148,9 @@ class Fit(object): fit.targetResists = self.targetResists fit.character = self.character fit.booster = self.booster + fit.implantLocation = ImplantLocation.CHARACTER if\ + self.serviceFittingOptions["useCharecterImplantsByDefault"] else\ + ImplantLocation.FIT eos.db.save(fit) self.recalc(fit) return fit.ID From f624528ce5579a5d2c5b84503917c634c1a2d38f Mon Sep 17 00:00:00 2001 From: Maru Maru Date: Wed, 11 Jul 2018 02:50:50 -0400 Subject: [PATCH 15/32] trivial line movement --- .../pyfaGeneralPreferences.py | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/gui/builtinPreferenceViews/pyfaGeneralPreferences.py b/gui/builtinPreferenceViews/pyfaGeneralPreferences.py index 6dc9b8ecb..920ee2654 100644 --- a/gui/builtinPreferenceViews/pyfaGeneralPreferences.py +++ b/gui/builtinPreferenceViews/pyfaGeneralPreferences.py @@ -34,14 +34,14 @@ class PFGeneralPref(PreferenceView): self.m_staticline1 = wx.StaticLine(panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL) mainSizer.Add(self.m_staticline1, 0, wx.EXPAND | wx.TOP | wx.BOTTOM, 5) - self.cbDefaultCharImplants = wx.CheckBox(panel, wx.ID_ANY, "Have new fits default to character implants", - wx.DefaultPosition, wx.DefaultSize, 0) - mainSizer.Add(self.cbDefaultCharImplants, 0, wx.ALL | wx.EXPAND, 5) - self.cbGlobalChar = wx.CheckBox(panel, wx.ID_ANY, "Use global character", wx.DefaultPosition, wx.DefaultSize, 0) mainSizer.Add(self.cbGlobalChar, 0, wx.ALL | wx.EXPAND, 5) + self.cbDefaultCharImplants = wx.CheckBox(panel, wx.ID_ANY, "Use character implants by default for new fits", + wx.DefaultPosition, wx.DefaultSize, 0) + mainSizer.Add(self.cbDefaultCharImplants, 0, wx.ALL | wx.EXPAND, 5) + self.cbGlobalDmgPattern = wx.CheckBox(panel, wx.ID_ANY, "Use global damage pattern", wx.DefaultPosition, wx.DefaultSize, 0) mainSizer.Add(self.cbGlobalDmgPattern, 0, wx.ALL | wx.EXPAND, 5) @@ -122,8 +122,8 @@ class PFGeneralPref(PreferenceView): self.sFit = Fit.getInstance() - self.cbDefaultCharImplants.SetValue(self.sFit.serviceFittingOptions["useCharecterImplantsByDefault"]) self.cbGlobalChar.SetValue(self.sFit.serviceFittingOptions["useGlobalCharacter"]) + self.cbDefaultCharImplants.SetValue(self.sFit.serviceFittingOptions["useCharecterImplantsByDefault"]) self.cbGlobalDmgPattern.SetValue(self.sFit.serviceFittingOptions["useGlobalDamagePattern"]) self.cbFitColorSlots.SetValue(self.sFit.serviceFittingOptions["colorFitBySlot"] or False) self.cbRackSlots.SetValue(self.sFit.serviceFittingOptions["rackSlots"] or False) @@ -140,8 +140,8 @@ class PFGeneralPref(PreferenceView): self.cbShowShipBrowserTooltip.SetValue(self.sFit.serviceFittingOptions["showShipBrowserTooltip"]) self.intDelay.SetValue(self.sFit.serviceFittingOptions["marketSearchDelay"]) - self.cbDefaultCharImplants.Bind(wx.EVT_CHECKBOX, self.OnCBDefaultCharImplantsStateChange) self.cbGlobalChar.Bind(wx.EVT_CHECKBOX, self.OnCBGlobalCharStateChange) + self.cbDefaultCharImplants.Bind(wx.EVT_CHECKBOX, self.OnCBDefaultCharImplantsStateChange) self.cbGlobalDmgPattern.Bind(wx.EVT_CHECKBOX, self.OnCBGlobalDmgPatternStateChange) self.cbFitColorSlots.Bind(wx.EVT_CHECKBOX, self.onCBGlobalColorBySlot) self.cbRackSlots.Bind(wx.EVT_CHECKBOX, self.onCBGlobalRackSlots) @@ -189,14 +189,14 @@ class PFGeneralPref(PreferenceView): wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) event.Skip() - def OnCBDefaultCharImplantsStateChange(self, event): - self.sFit.serviceFittingOptions["useCharecterImplantsByDefault"] = self.cbDefaultCharImplants.GetValue() - event.Skip() - def OnCBGlobalCharStateChange(self, event): self.sFit.serviceFittingOptions["useGlobalCharacter"] = self.cbGlobalChar.GetValue() event.Skip() + def OnCBDefaultCharImplantsStateChange(self, event): + self.sFit.serviceFittingOptions["useCharecterImplantsByDefault"] = self.cbDefaultCharImplants.GetValue() + event.Skip() + def OnCBGlobalDmgPatternStateChange(self, event): self.sFit.serviceFittingOptions["useGlobalDamagePattern"] = self.cbGlobalDmgPattern.GetValue() event.Skip() From 4be78db73807d2a5ebc5308d68e1c736d7fb64a2 Mon Sep 17 00:00:00 2001 From: MaruMaruOO Date: Mon, 16 Jul 2018 06:25:56 -0400 Subject: [PATCH 16/32] Added additional data to efs exports moduleNames and moved it to service.efsPort --- gui/mainFrame.py | 3 +-- savedata/efs_export_base_fits.py | 2 +- savedata/efs_export_pyfa_fits.py | 2 +- savedata/makeAndDiffCheck.sh | 2 +- efs_stat_export.py => service/efsPort.py | 18 +++++++++++++++++- 5 files changed, 21 insertions(+), 6 deletions(-) rename efs_stat_export.py => service/efsPort.py (97%) diff --git a/gui/mainFrame.py b/gui/mainFrame.py index 3458cd6d0..dc0162d69 100644 --- a/gui/mainFrame.py +++ b/gui/mainFrame.py @@ -77,10 +77,9 @@ from eos.modifiedAttributeDict import ModifiedAttributeDict from eos.db.saveddata.loadDefaultDatabaseValues import DefaultDatabaseValues from eos.db.saveddata.queries import getFit as db_getFit from service.port import Port, IPortUser +from service.efsPort import parseNeededFitDetails as exportEfsStats from service.settings import HTMLExportSettings -from efs_stat_export import parseNeededFitDetails as exportEfsStats - from time import gmtime, strftime import threading diff --git a/savedata/efs_export_base_fits.py b/savedata/efs_export_base_fits.py index a4fa8404d..9ebb026d8 100644 --- a/savedata/efs_export_base_fits.py +++ b/savedata/efs_export_base_fits.py @@ -78,7 +78,7 @@ eos.db.saveddata_meta.create_all() import json from service.fit import Fit -from efs_stat_export import parseNeededFitDetails +from service.efsPort import parseNeededFitDetails from sqlalchemy import Column, String, Integer, ForeignKey, Boolean, Table from sqlalchemy.orm import relation, mapper, synonym, deferred diff --git a/savedata/efs_export_pyfa_fits.py b/savedata/efs_export_pyfa_fits.py index 749fdc1d4..5484b097d 100644 --- a/savedata/efs_export_pyfa_fits.py +++ b/savedata/efs_export_pyfa_fits.py @@ -19,7 +19,7 @@ import eos.db if not os.path.exists(config.savePath): os.mkdir(config.savePath) -from efs_stat_export import parseNeededFitDetails +from service.efsPort import parseNeededFitDetails def exportPyfaFits(opts): nameReq = '' diff --git a/savedata/makeAndDiffCheck.sh b/savedata/makeAndDiffCheck.sh index 84ddd89a5..c1aee9dc3 100755 --- a/savedata/makeAndDiffCheck.sh +++ b/savedata/makeAndDiffCheck.sh @@ -51,5 +51,5 @@ if [[ $EXPECTERRORS == True ]] ; then else diff -s --color=always ../shipJSON.js ~/.pyfa/shipJSON.js | grep -m 3 --color '' diff -s --color=always ../shipBaseJSON.js ~/.pyfa/shipBaseJSON.js | grep -m 3 --color '' -/home/stock/scripts/Pyfa/.tox/pep8/bin/flake8 --exclude=.svn,CVS,.bzr,.hg,.git,__pycache__,venv,tests,.tox,build,dist,__init__.py,floatspin.py --ignore=E121,E126,E127,E128,E203,E731,F401,E722,E741 efs_stat_export.py --max-line-length=165 +/home/stock/scripts/Pyfa/.tox/pep8/bin/flake8 --exclude=.svn,CVS,.bzr,.hg,.git,__pycache__,venv,tests,.tox,build,dist,__init__.py,floatspin.py --ignore=E121,E126,E127,E128,E203,E731,F401,E722,E741 service/efsPort.py --max-line-length=165 fi diff --git a/efs_stat_export.py b/service/efsPort.py similarity index 97% rename from efs_stat_export.py rename to service/efsPort.py index a8e50f7f4..a5d47ad41 100755 --- a/efs_stat_export.py +++ b/service/efsPort.py @@ -247,11 +247,27 @@ def getModuleNames(fit): moduleNames.append('Implants:') for implant in fit.implants: moduleNames.append(implant.item.name) + if len(fit.boosters) > 0: + moduleNames.append('') + moduleNames.append('Boosters:') + for booster in fit.boosters: + moduleNames.append(booster.item.name) if len(fit.commandFits) > 0: moduleNames.append('') moduleNames.append('Command Fits:') for commandFit in fit.commandFits: moduleNames.append(commandFit.name) + if len(fit.projectedModules) > 0: + moduleNames.append('') + moduleNames.append('Projected Modules:') + for mod in fit.projectedModules: + moduleNames.append(mod.item.name) + + if fit.character.name != "All 5": + moduleNames.append('') + moduleNames.append('Character:') + moduleNames.append(fit.character.name) + return moduleNames @@ -595,7 +611,7 @@ def parseNeededFitDetails(fit, groupID): 'maxTargetRange': fit.maxTargetRange, 'scanStrength': fit.scanStrength, 'weaponDPS': fit.weaponDPS, 'alignTime': fit.alignTime, 'signatureRadius': fitModAttr['signatureRadius'], 'weapons': weaponSystems, 'scanRes': fitModAttr['scanResolution'], - 'projectedModules': fit.projectedModules, 'capUsed': fit.capUsed, 'capRecharge': fit.capRecharge, + 'capUsed': fit.capUsed, 'capRecharge': fit.capRecharge, 'rigSlots': fitModAttr['rigSlots'], 'lowSlots': fitModAttr['lowSlots'], 'midSlots': fitModAttr['medSlots'], 'highSlots': fitModAttr['hiSlots'], 'turretSlots': fitModAttr['turretSlotsLeft'], 'launcherSlots': fitModAttr['launcherSlotsLeft'], From b1f1db1bee65ff63df8d96a795d4750accdba088 Mon Sep 17 00:00:00 2001 From: MaruMaruOO Date: Tue, 17 Jul 2018 02:45:00 -0400 Subject: [PATCH 17/32] Change service.efsPort to a class structure for consistancy. --- gui/mainFrame.py | 4 +- savedata/efs_export_base_fits.py | 4 +- savedata/efs_export_pyfa_fits.py | 4 +- service/efsPort.py | 1145 +++++++++++++++--------------- 4 files changed, 576 insertions(+), 581 deletions(-) diff --git a/gui/mainFrame.py b/gui/mainFrame.py index dc0162d69..9bd02feee 100644 --- a/gui/mainFrame.py +++ b/gui/mainFrame.py @@ -77,7 +77,7 @@ from eos.modifiedAttributeDict import ModifiedAttributeDict from eos.db.saveddata.loadDefaultDatabaseValues import DefaultDatabaseValues from eos.db.saveddata.queries import getFit as db_getFit from service.port import Port, IPortUser -from service.efsPort import parseNeededFitDetails as exportEfsStats +from service.efsPort import EfsPort from service.settings import HTMLExportSettings from time import gmtime, strftime @@ -729,7 +729,7 @@ class MainFrame(wx.Frame): def clipboardEfs(self): fit = db_getFit(self.getActiveFit()) - toClipboard(exportEfsStats(fit, 0)) + toClipboard(EfsPort.exportEfs(fit, 0)) def importFromClipboard(self, event): clipboard = fromClipboard() diff --git a/savedata/efs_export_base_fits.py b/savedata/efs_export_base_fits.py index 9ebb026d8..1682ab716 100644 --- a/savedata/efs_export_base_fits.py +++ b/savedata/efs_export_base_fits.py @@ -78,7 +78,7 @@ eos.db.saveddata_meta.create_all() import json from service.fit import Fit -from service.efsPort import parseNeededFitDetails +from service.efsPort import EfsPort from sqlalchemy import Column, String, Integer, ForeignKey, Boolean, Table from sqlalchemy.orm import relation, mapper, synonym, deferred @@ -250,6 +250,6 @@ def setFitFromString(dnaString, fitName, groupID) : fitL.addCommandFit(fit.ID, shieldLinkShip) fitL.addCommandFit(fit.ID, skirmishLinkShip) fitL.addCommandFit(fit.ID, infoLinkShip) - jsonStr = parseNeededFitDetails(fit, groupID) + jsonStr = EfsPort.exportEfs(fit, groupID) Fit.deleteFit(fitID) return jsonStr diff --git a/savedata/efs_export_pyfa_fits.py b/savedata/efs_export_pyfa_fits.py index 5484b097d..9388f8ad6 100644 --- a/savedata/efs_export_pyfa_fits.py +++ b/savedata/efs_export_pyfa_fits.py @@ -19,7 +19,7 @@ import eos.db if not os.path.exists(config.savePath): os.mkdir(config.savePath) -from service.efsPort import parseNeededFitDetails +from service.efsPort import EfsPort def exportPyfaFits(opts): nameReq = '' @@ -48,7 +48,7 @@ def exportPyfaFits(opts): n += 1 name = fit.ship.name + ': ' + fit.name if n >= skipTill and nameReq in name: - stats = parseNeededFitDetails(fit, 0) + stats = EfsPort.exportEfs(fit, 0) output.write(stats) output.write(',\n') output.write(']);\nexport {shipJSON};') diff --git a/service/efsPort.py b/service/efsPort.py index a5d47ad41..25f6fffa3 100755 --- a/service/efsPort.py +++ b/service/efsPort.py @@ -4,11 +4,10 @@ import platform import re import sys import traceback -from math import log - +import json import eos.db -import json +from math import log from service.fit import Fit from service.market import Market from eos.enum import Enum @@ -17,616 +16,612 @@ from eos.saveddata.drone import Drone from eos.effectHandlerHelpers import HandledList from eos.db import gamedata_session, getItemsByCategory, getCategory, getAttributeInfo, getGroup from eos.gamedata import Category, Group, Item, Traits, Attribute, Effect, ItemEffect - +from logbook import Logger +pyfalog = Logger(__name__) eos.db.saveddata_meta.create_all() class RigSize(Enum): - # Matches to item attribute 'rigSize' on ship and rig items + # Matches to item attribute "rigSize" on ship and rig items SMALL = 1 MEDIUM = 2 LARGE = 3 CAPITAL = 4 -def attrDirectMap(values, target, source): - for val in values: - target[val] = source.itemModifiedAttributes[val] +class EfsPort(): + wepTestSet = {} + @staticmethod + def attrDirectMap(values, target, source): + for val in values: + target[val] = source.itemModifiedAttributes[val] -def getT2MwdSpeed(fit, fitL): - fitID = fit.ID - propID = None - shipHasMedSlots = fit.ship.itemModifiedAttributes['medSlots'] > 0 - shipPower = fit.ship.itemModifiedAttributes['powerOutput'] - # Monitors have a 99% reduction to prop mod power requirements - if fit.ship.name == 'Monitor': - shipPower *= 100 - rigSize = fit.ship.itemModifiedAttributes['rigSize'] - if not shipHasMedSlots: - return None + @staticmethod + def getT2MwdSpeed(fit, fitL): + fitID = fit.ID + propID = None + shipHasMedSlots = fit.ship.itemModifiedAttributes["medSlots"] > 0 + shipPower = fit.ship.itemModifiedAttributes["powerOutput"] + # Monitors have a 99% reduction to prop mod power requirements + if fit.ship.name == "Monitor": + shipPower *= 100 + rigSize = fit.ship.itemModifiedAttributes["rigSize"] + if not shipHasMedSlots: + return None - filterVal = Item.groupID == getGroup('Propulsion Module').ID - propMods = gamedata_session.query(Item).options().filter(filterVal).all() - mapPropData = lambda propName: \ - next(map(lambda propMod: {'id': propMod.typeID, 'powerReq': propMod.attributes['power'].value}, - (filter(lambda mod: mod.name == propName, propMods)))) - mwd5mn = mapPropData('5MN Microwarpdrive II') - mwd50mn = mapPropData('50MN Microwarpdrive II') - mwd500mn = mapPropData('500MN Microwarpdrive II') - mwd50000mn = mapPropData('50000MN Microwarpdrive II') - if rigSize == RigSize.SMALL or rigSize is None: - propID = mwd5mn['id'] if shipPower > mwd5mn['powerReq'] else None - elif rigSize == RigSize.MEDIUM: - propID = mwd50mn['id'] if shipPower > mwd50mn['powerReq'] else mwd5mn['id'] - elif rigSize == RigSize.LARGE: - propID = mwd500mn['id'] if shipPower > mwd500mn['powerReq'] else mwd50mn['id'] - elif rigSize == RigSize.CAPITAL: - propID = mwd50000mn['id'] if shipPower > mwd50000mn['powerReq'] else mwd500mn['id'] + filterVal = Item.groupID == getGroup("Propulsion Module").ID + propMods = gamedata_session.query(Item).options().filter(filterVal).all() + mapPropData = lambda propName: \ + next(map(lambda propMod: {"id": propMod.typeID, "powerReq": propMod.attributes["power"].value}, + (filter(lambda mod: mod.name == propName, propMods)))) + mwd5mn = mapPropData("5MN Microwarpdrive II") + mwd50mn = mapPropData("50MN Microwarpdrive II") + mwd500mn = mapPropData("500MN Microwarpdrive II") + mwd50000mn = mapPropData("50000MN Microwarpdrive II") + if rigSize == RigSize.SMALL or rigSize is None: + propID = mwd5mn["id"] if shipPower > mwd5mn["powerReq"] else None + elif rigSize == RigSize.MEDIUM: + propID = mwd50mn["id"] if shipPower > mwd50mn["powerReq"] else mwd5mn["id"] + elif rigSize == RigSize.LARGE: + propID = mwd500mn["id"] if shipPower > mwd500mn["powerReq"] else mwd50mn["id"] + elif rigSize == RigSize.CAPITAL: + propID = mwd50000mn["id"] if shipPower > mwd50000mn["powerReq"] else mwd500mn["id"] - if propID is None: - return None - fitL.appendModule(fitID, propID) - fitL.recalc(fit) - fit = eos.db.getFit(fitID) - mwdPropSpeed = fit.maxSpeed - mwdPosition = list(filter(lambda mod: mod.item and mod.item.ID == propID, fit.modules))[0].position - fitL.removeModule(fitID, mwdPosition) - fitL.recalc(fit) - fit = eos.db.getFit(fitID) - return mwdPropSpeed - - -def getPropData(fit, fitL): - fitID = fit.ID - propGroupId = getGroup('Propulsion Module').ID - propMods = filter(lambda mod: mod.item and mod.item.groupID == propGroupId, fit.modules) - activePropWBloomFilter = lambda mod: mod.state > 0 and 'signatureRadiusBonus' in mod.item.attributes - propWithBloom = next(filter(activePropWBloomFilter, propMods), None) - if propWithBloom is not None: - oldPropState = propWithBloom.state - propWithBloom.state = 0 + if propID is None: + return None + fitL.appendModule(fitID, propID) fitL.recalc(fit) fit = eos.db.getFit(fitID) - sp = fit.maxSpeed - sig = fit.ship.itemModifiedAttributes['signatureRadius'] - propWithBloom.state = oldPropState + mwdPropSpeed = fit.maxSpeed + mwdPosition = list(filter(lambda mod: mod.item and mod.item.ID == propID, fit.modules))[0].position + fitL.removeModule(fitID, mwdPosition) fitL.recalc(fit) fit = eos.db.getFit(fitID) - return {'usingMWD': True, 'unpropedSpeed': sp, 'unpropedSig': sig} - return { - 'usingMWD': False, - 'unpropedSpeed': fit.maxSpeed, - 'unpropedSig': fit.ship.itemModifiedAttributes['signatureRadius'] - } + return mwdPropSpeed - -def getOutgoingProjectionData(fit): - # This is a subset of module groups capable of projection and a superset of those currently used by efs - modGroupNames = [ - 'Remote Shield Booster', 'Warp Scrambler', 'Stasis Web', 'Remote Capacitor Transmitter', - 'Energy Nosferatu', 'Energy Neutralizer', 'Burst Jammer', 'ECM', 'Sensor Dampener', - 'Weapon Disruptor', 'Remote Armor Repairer', 'Target Painter', 'Remote Hull Repairer', - 'Burst Projectors', 'Warp Disrupt Field Generator', 'Armor Resistance Shift Hardener', - 'Target Breaker', 'Micro Jump Drive', 'Ship Modifiers', 'Stasis Grappler', - 'Ancillary Remote Shield Booster', 'Ancillary Remote Armor Repairer', - 'Titan Phenomena Generator', 'Non-Repeating Hardeners' - ] - modGroupIds = list(map(lambda s: getGroup(s).ID, modGroupNames)) - modGroupData = dict(map(lambda name, gid: (name, {'name': name, 'id': gid}), - modGroupNames, modGroupIds)) - projectedMods = list(filter(lambda mod: mod.item and mod.item.groupID in modGroupIds, fit.modules)) - projections = [] - for mod in projectedMods: - stats = {} - if mod.item.groupID in [modGroupData['Stasis Web']['id'], modGroupData['Stasis Grappler']['id']]: - stats['type'] = 'Stasis Web' - stats['optimal'] = mod.itemModifiedAttributes['maxRange'] - attrDirectMap(['duration', 'speedFactor'], stats, mod) - elif mod.item.groupID == modGroupData['Weapon Disruptor']['id']: - stats['type'] = 'Weapon Disruptor' - stats['optimal'] = mod.itemModifiedAttributes['maxRange'] - stats['falloff'] = mod.itemModifiedAttributes['falloffEffectiveness'] - attrDirectMap([ - 'trackingSpeedBonus', 'maxRangeBonus', 'falloffBonus', 'aoeCloudSizeBonus', - 'aoeVelocityBonus', 'missileVelocityBonus', 'explosionDelayBonus' - ], stats, mod) - elif mod.item.groupID == modGroupData['Energy Nosferatu']['id']: - stats['type'] = 'Energy Nosferatu' - attrDirectMap(['powerTransferAmount', 'energyNeutralizerSignatureResolution'], stats, mod) - elif mod.item.groupID == modGroupData['Energy Neutralizer']['id']: - stats['type'] = 'Energy Neutralizer' - attrDirectMap([ - 'energyNeutralizerSignatureResolution', 'entityCapacitorLevelModifierSmall', - 'entityCapacitorLevelModifierMedium', 'entityCapacitorLevelModifierLarge', - 'energyNeutralizerAmount' - ], stats, mod) - elif mod.item.groupID in [modGroupData['Remote Shield Booster']['id'], - modGroupData['Ancillary Remote Shield Booster']['id']]: - stats['type'] = 'Remote Shield Booster' - attrDirectMap(['shieldBonus'], stats, mod) - elif mod.item.groupID in [modGroupData['Remote Armor Repairer']['id'], - modGroupData['Ancillary Remote Armor Repairer']['id']]: - stats['type'] = 'Remote Armor Repairer' - attrDirectMap(['armorDamageAmount'], stats, mod) - elif mod.item.groupID == modGroupData['Warp Scrambler']['id']: - stats['type'] = 'Warp Scrambler' - attrDirectMap(['activationBlockedStrenght', 'warpScrambleStrength'], stats, mod) - elif mod.item.groupID == modGroupData['Target Painter']['id']: - stats['type'] = 'Target Painter' - attrDirectMap(['signatureRadiusBonus'], stats, mod) - elif mod.item.groupID == modGroupData['Sensor Dampener']['id']: - stats['type'] = 'Sensor Dampener' - attrDirectMap(['maxTargetRangeBonus', 'scanResolutionBonus'], stats, mod) - elif mod.item.groupID == modGroupData['ECM']['id']: - stats['type'] = 'ECM' - attrDirectMap([ - 'scanGravimetricStrengthBonus', 'scanMagnetometricStrengthBonus', - 'scanRadarStrengthBonus', 'scanLadarStrengthBonus', - ], stats, mod) - elif mod.item.groupID == modGroupData['Burst Jammer']['id']: - stats['type'] = 'Burst Jammer' - mod.itemModifiedAttributes['maxRange'] = mod.itemModifiedAttributes['ecmBurstRange'] - attrDirectMap([ - 'scanGravimetricStrengthBonus', 'scanMagnetometricStrengthBonus', - 'scanRadarStrengthBonus', 'scanLadarStrengthBonus', - ], stats, mod) - elif mod.item.groupID == modGroupData['Micro Jump Drive']['id']: - stats['type'] = 'Micro Jump Drive' - mod.itemModifiedAttributes['maxRange'] = 0 - attrDirectMap(['moduleReactivationDelay'], stats, mod) - if mod.itemModifiedAttributes['maxRange'] is None: - print(mod.item.name) - print(mod.itemModifiedAttributes.items()) - raise ValueError('Projected module lacks a maxRange') - stats['optimal'] = mod.itemModifiedAttributes['maxRange'] - stats['falloff'] = mod.itemModifiedAttributes['falloffEffectiveness'] or 0 - attrDirectMap(['duration', 'capacitorNeed'], stats, mod) - projections.append(stats) - return projections - - -def getModuleNames(fit): - moduleNames = [] - highSlotNames = [] - midSlotNames = [] - lowSlotNames = [] - rigSlotNames = [] - miscSlotNames = [] # subsystems ect - for mod in fit.modules: - if mod.slot == 3: - modSlotNames = highSlotNames - elif mod.slot == 2: - modSlotNames = midSlotNames - elif mod.slot == 1: - modSlotNames = lowSlotNames - elif mod.slot == 4: - modSlotNames = rigSlotNames - elif mod.slot == 5: - modSlotNames = miscSlotNames - try: - if mod.item is not None: - if mod.charge is not None: - modSlotNames.append(mod.item.name + ': ' + mod.charge.name) - else: - modSlotNames.append(mod.item.name) - else: - modSlotNames.append('Empty Slot') - except: - print(vars(mod)) - print('could not find name for module') - print(fit.modules) - for modInfo in [ - ['High Slots:'], highSlotNames, ['', 'Med Slots:'], midSlotNames, - ['', 'Low Slots:'], lowSlotNames, ['', 'Rig Slots:'], rigSlotNames - ]: - moduleNames.extend(modInfo) - - if len(miscSlotNames) > 0: - moduleNames.append('') - moduleNames.append('Subsystems:') - moduleNames.extend(miscSlotNames) - droneNames = [] - fighterNames = [] - for drone in fit.drones: - if drone.amountActive > 0: - droneNames.append("%s x%s" % (drone.item.name, drone.amount)) - for fighter in fit.fighters: - if fighter.amountActive > 0: - fighterNames.append("%s x%s" % (fighter.item.name, fighter.amountActive)) - if len(droneNames) > 0: - moduleNames.append('') - moduleNames.append('Drones:') - moduleNames.extend(droneNames) - if len(fighterNames) > 0: - moduleNames.append('') - moduleNames.append('Fighters:') - moduleNames.extend(fighterNames) - if len(fit.implants) > 0: - moduleNames.append('') - moduleNames.append('Implants:') - for implant in fit.implants: - moduleNames.append(implant.item.name) - if len(fit.boosters) > 0: - moduleNames.append('') - moduleNames.append('Boosters:') - for booster in fit.boosters: - moduleNames.append(booster.item.name) - if len(fit.commandFits) > 0: - moduleNames.append('') - moduleNames.append('Command Fits:') - for commandFit in fit.commandFits: - moduleNames.append(commandFit.name) - if len(fit.projectedModules) > 0: - moduleNames.append('') - moduleNames.append('Projected Modules:') - for mod in fit.projectedModules: - moduleNames.append(mod.item.name) - - if fit.character.name != "All 5": - moduleNames.append('') - moduleNames.append('Character:') - moduleNames.append(fit.character.name) - - return moduleNames - - -def getFighterAbilityData(fighterAttr, fighter, baseRef): - baseRefDam = baseRef + 'Damage' - abilityName = 'RegularAttack' if baseRef == 'fighterAbilityAttackMissile' else 'MissileAttack' - rangeSuffix = 'RangeOptimal' if baseRef == 'fighterAbilityAttackMissile' else 'Range' - reductionRef = baseRef if baseRef == 'fighterAbilityAttackMissile' else baseRefDam - damageReductionFactor = log(fighterAttr[reductionRef + 'ReductionFactor']) / log(fighterAttr[reductionRef + 'ReductionSensitivity']) - damTypes = ['EM', 'Therm', 'Exp', 'Kin'] - abBaseDamage = sum(map(lambda damType: fighterAttr[baseRefDam + damType], damTypes)) - abDamage = abBaseDamage * fighterAttr[baseRefDam + 'Multiplier'] - return { - 'name': abilityName, 'volley': abDamage * fighter.amountActive, 'explosionRadius': fighterAttr[baseRef + 'ExplosionRadius'], - 'explosionVelocity': fighterAttr[baseRef + 'ExplosionVelocity'], 'optimal': fighterAttr[baseRef + rangeSuffix], - 'damageReductionFactor': damageReductionFactor, 'rof': fighterAttr[baseRef + 'Duration'], - } - - -def getWeaponSystemData(fit): - weaponSystems = [] - groups = {} - for mod in fit.modules: - if mod.dps > 0: - # Group weapon + ammo combinations that occur more than once - keystr = str(mod.itemID) + '-' + str(mod.chargeID) - if keystr in groups: - groups[keystr][1] += 1 - else: - groups[keystr] = [mod, 1] - for wepGroup in groups.values(): - stats = wepGroup[0] - n = wepGroup[1] - tracking = 0 - maxVelocity = 0 - explosionDelay = 0 - damageReductionFactor = 0 - explosionRadius = 0 - explosionVelocity = 0 - aoeFieldRange = 0 - if stats.hardpoint == Hardpoint.TURRET: - tracking = stats.itemModifiedAttributes['trackingSpeed'] - typeing = 'Turret' - name = stats.item.name + ', ' + stats.charge.name - # Bombs share most attributes with missiles despite not needing the hardpoint - elif stats.hardpoint == Hardpoint.MISSILE or 'Bomb Launcher' in stats.item.name: - maxVelocity = stats.chargeModifiedAttributes['maxVelocity'] - explosionDelay = stats.chargeModifiedAttributes['explosionDelay'] - damageReductionFactor = stats.chargeModifiedAttributes['aoeDamageReductionFactor'] - explosionRadius = stats.chargeModifiedAttributes['aoeCloudSize'] - explosionVelocity = stats.chargeModifiedAttributes['aoeVelocity'] - typeing = 'Missile' - name = stats.item.name + ', ' + stats.charge.name - elif stats.hardpoint == Hardpoint.NONE: - aoeFieldRange = stats.itemModifiedAttributes['empFieldRange'] - # This also covers non-bomb weapons with dps values and no hardpoints, most notably targeted doomsdays. - typeing = 'SmartBomb' - name = stats.item.name - statDict = { - 'dps': stats.dps * n, 'capUse': stats.capUse * n, 'falloff': stats.falloff, - 'type': typeing, 'name': name, 'optimal': stats.maxRange, - 'numCharges': stats.numCharges, 'numShots': stats.numShots, 'reloadTime': stats.reloadTime, - 'cycleTime': stats.cycleTime, 'volley': stats.volley * n, 'tracking': tracking, - 'maxVelocity': maxVelocity, 'explosionDelay': explosionDelay, 'damageReductionFactor': damageReductionFactor, - 'explosionRadius': explosionRadius, 'explosionVelocity': explosionVelocity, 'aoeFieldRange': aoeFieldRange + @staticmethod + def getPropData(fit, fitL): + fitID = fit.ID + propGroupId = getGroup("Propulsion Module").ID + propMods = filter(lambda mod: mod.item and mod.item.groupID == propGroupId, fit.modules) + activePropWBloomFilter = lambda mod: mod.state > 0 and "signatureRadiusBonus" in mod.item.attributes + propWithBloom = next(filter(activePropWBloomFilter, propMods), None) + if propWithBloom is not None: + oldPropState = propWithBloom.state + propWithBloom.state = 0 + fitL.recalc(fit) + fit = eos.db.getFit(fitID) + sp = fit.maxSpeed + sig = fit.ship.itemModifiedAttributes["signatureRadius"] + propWithBloom.state = oldPropState + fitL.recalc(fit) + fit = eos.db.getFit(fitID) + return {"usingMWD": True, "unpropedSpeed": sp, "unpropedSig": sig} + return { + "usingMWD": False, + "unpropedSpeed": fit.maxSpeed, + "unpropedSig": fit.ship.itemModifiedAttributes["signatureRadius"] } - weaponSystems.append(statDict) - for drone in fit.drones: - if drone.dps[0] > 0 and drone.amountActive > 0: - droneAttr = drone.itemModifiedAttributes - # Drones are using the old tracking formula for trackingSpeed. This updates it to match turrets. - newTracking = droneAttr['trackingSpeed'] / (droneAttr['optimalSigRadius'] / 40000) + + @staticmethod + def getOutgoingProjectionData(fit): + # This is a subset of module groups capable of projection and a superset of those currently used by efs + modGroupNames = [ + "Remote Shield Booster", "Warp Scrambler", "Stasis Web", "Remote Capacitor Transmitter", + "Energy Nosferatu", "Energy Neutralizer", "Burst Jammer", "ECM", "Sensor Dampener", + "Weapon Disruptor", "Remote Armor Repairer", "Target Painter", "Remote Hull Repairer", + "Burst Projectors", "Warp Disrupt Field Generator", "Armor Resistance Shift Hardener", + "Target Breaker", "Micro Jump Drive", "Ship Modifiers", "Stasis Grappler", + "Ancillary Remote Shield Booster", "Ancillary Remote Armor Repairer", + "Titan Phenomena Generator", "Non-Repeating Hardeners" + ] + modGroupIds = list(map(lambda s: getGroup(s).ID, modGroupNames)) + modGroupData = dict(map(lambda name, gid: (name, {"name": name, "id": gid}), + modGroupNames, modGroupIds)) + projectedMods = list(filter(lambda mod: mod.item and mod.item.groupID in modGroupIds, fit.modules)) + projections = [] + for mod in projectedMods: + stats = {} + if mod.item.groupID in [modGroupData["Stasis Web"]["id"], modGroupData["Stasis Grappler"]["id"]]: + stats["type"] = "Stasis Web" + stats["optimal"] = mod.itemModifiedAttributes["maxRange"] + EfsPort.attrDirectMap(["duration", "speedFactor"], stats, mod) + elif mod.item.groupID == modGroupData["Weapon Disruptor"]["id"]: + stats["type"] = "Weapon Disruptor" + stats["optimal"] = mod.itemModifiedAttributes["maxRange"] + stats["falloff"] = mod.itemModifiedAttributes["falloffEffectiveness"] + EfsPort.attrDirectMap([ + "trackingSpeedBonus", "maxRangeBonus", "falloffBonus", "aoeCloudSizeBonus", + "aoeVelocityBonus", "missileVelocityBonus", "explosionDelayBonus" + ], stats, mod) + elif mod.item.groupID == modGroupData["Energy Nosferatu"]["id"]: + stats["type"] = "Energy Nosferatu" + EfsPort.attrDirectMap(["powerTransferAmount", "energyNeutralizerSignatureResolution"], stats, mod) + elif mod.item.groupID == modGroupData["Energy Neutralizer"]["id"]: + stats["type"] = "Energy Neutralizer" + EfsPort.attrDirectMap([ + "energyNeutralizerSignatureResolution", "entityCapacitorLevelModifierSmall", + "entityCapacitorLevelModifierMedium", "entityCapacitorLevelModifierLarge", + "energyNeutralizerAmount" + ], stats, mod) + elif mod.item.groupID in [modGroupData["Remote Shield Booster"]["id"], + modGroupData["Ancillary Remote Shield Booster"]["id"]]: + stats["type"] = "Remote Shield Booster" + EfsPort.attrDirectMap(["shieldBonus"], stats, mod) + elif mod.item.groupID in [modGroupData["Remote Armor Repairer"]["id"], + modGroupData["Ancillary Remote Armor Repairer"]["id"]]: + stats["type"] = "Remote Armor Repairer" + EfsPort.attrDirectMap(["armorDamageAmount"], stats, mod) + elif mod.item.groupID == modGroupData["Warp Scrambler"]["id"]: + stats["type"] = "Warp Scrambler" + EfsPort.attrDirectMap(["activationBlockedStrenght", "warpScrambleStrength"], stats, mod) + elif mod.item.groupID == modGroupData["Target Painter"]["id"]: + stats["type"] = "Target Painter" + EfsPort.attrDirectMap(["signatureRadiusBonus"], stats, mod) + elif mod.item.groupID == modGroupData["Sensor Dampener"]["id"]: + stats["type"] = "Sensor Dampener" + EfsPort.attrDirectMap(["maxTargetRangeBonus", "scanResolutionBonus"], stats, mod) + elif mod.item.groupID == modGroupData["ECM"]["id"]: + stats["type"] = "ECM" + EfsPort.attrDirectMap([ + "scanGravimetricStrengthBonus", "scanMagnetometricStrengthBonus", + "scanRadarStrengthBonus", "scanLadarStrengthBonus", + ], stats, mod) + elif mod.item.groupID == modGroupData["Burst Jammer"]["id"]: + stats["type"] = "Burst Jammer" + mod.itemModifiedAttributes["maxRange"] = mod.itemModifiedAttributes["ecmBurstRange"] + EfsPort.attrDirectMap([ + "scanGravimetricStrengthBonus", "scanMagnetometricStrengthBonus", + "scanRadarStrengthBonus", "scanLadarStrengthBonus", + ], stats, mod) + elif mod.item.groupID == modGroupData["Micro Jump Drive"]["id"]: + stats["type"] = "Micro Jump Drive" + mod.itemModifiedAttributes["maxRange"] = 0 + EfsPort.attrDirectMap(["moduleReactivationDelay"], stats, mod) + if mod.itemModifiedAttributes["maxRange"] is None: + pyfalog.error("Projected module {0} has no maxRange".format(mod.item.name)) + stats["optimal"] = mod.itemModifiedAttributes["maxRange"] or 0 + stats["falloff"] = mod.itemModifiedAttributes["falloffEffectiveness"] or 0 + EfsPort.attrDirectMap(["duration", "capacitorNeed"], stats, mod) + projections.append(stats) + return projections + + @staticmethod + def getModuleNames(fit): + moduleNames = [] + highSlotNames = [] + midSlotNames = [] + lowSlotNames = [] + rigSlotNames = [] + miscSlotNames = [] # subsystems ect + for mod in fit.modules: + if mod.slot == 3: + modSlotNames = highSlotNames + elif mod.slot == 2: + modSlotNames = midSlotNames + elif mod.slot == 1: + modSlotNames = lowSlotNames + elif mod.slot == 4: + modSlotNames = rigSlotNames + elif mod.slot == 5: + modSlotNames = miscSlotNames + try: + if mod.item is not None: + if mod.charge is not None: + modSlotNames.append(mod.item.name + ": " + mod.charge.name) + else: + modSlotNames.append(mod.item.name) + else: + modSlotNames.append("Empty Slot") + except: + pyfalog.error("Could not find name for module {0}".format(vars(mod))) + for modInfo in [ + ["High Slots:"], highSlotNames, ["", "Med Slots:"], midSlotNames, + ["", "Low Slots:"], lowSlotNames, ["", "Rig Slots:"], rigSlotNames + ]: + moduleNames.extend(modInfo) + + if len(miscSlotNames) > 0: + moduleNames.append("") + moduleNames.append("Subsystems:") + moduleNames.extend(miscSlotNames) + droneNames = [] + fighterNames = [] + for drone in fit.drones: + if drone.amountActive > 0: + droneNames.append("%s x%s" % (drone.item.name, drone.amount)) + for fighter in fit.fighters: + if fighter.amountActive > 0: + fighterNames.append("%s x%s" % (fighter.item.name, fighter.amountActive)) + if len(droneNames) > 0: + moduleNames.append("") + moduleNames.append("Drones:") + moduleNames.extend(droneNames) + if len(fighterNames) > 0: + moduleNames.append("") + moduleNames.append("Fighters:") + moduleNames.extend(fighterNames) + if len(fit.implants) > 0: + moduleNames.append("") + moduleNames.append("Implants:") + for implant in fit.implants: + moduleNames.append(implant.item.name) + if len(fit.boosters) > 0: + moduleNames.append("") + moduleNames.append("Boosters:") + for booster in fit.boosters: + moduleNames.append(booster.item.name) + if len(fit.commandFits) > 0: + moduleNames.append("") + moduleNames.append("Command Fits:") + for commandFit in fit.commandFits: + moduleNames.append(commandFit.name) + if len(fit.projectedModules) > 0: + moduleNames.append("") + moduleNames.append("Projected Modules:") + for mod in fit.projectedModules: + moduleNames.append(mod.item.name) + + if fit.character.name != "All 5": + moduleNames.append("") + moduleNames.append("Character:") + moduleNames.append(fit.character.name) + + return moduleNames + + @staticmethod + def getFighterAbilityData(fighterAttr, fighter, baseRef): + baseRefDam = baseRef + "Damage" + abilityName = "RegularAttack" if baseRef == "fighterAbilityAttackMissile" else "MissileAttack" + rangeSuffix = "RangeOptimal" if baseRef == "fighterAbilityAttackMissile" else "Range" + reductionRef = baseRef if baseRef == "fighterAbilityAttackMissile" else baseRefDam + damageReductionFactor = log(fighterAttr[reductionRef + "ReductionFactor"]) / log(fighterAttr[reductionRef + "ReductionSensitivity"]) + damTypes = ["EM", "Therm", "Exp", "Kin"] + abBaseDamage = sum(map(lambda damType: fighterAttr[baseRefDam + damType], damTypes)) + abDamage = abBaseDamage * fighterAttr[baseRefDam + "Multiplier"] + return { + "name": abilityName, "volley": abDamage * fighter.amountActive, "explosionRadius": fighterAttr[baseRef + "ExplosionRadius"], + "explosionVelocity": fighterAttr[baseRef + "ExplosionVelocity"], "optimal": fighterAttr[baseRef + rangeSuffix], + "damageReductionFactor": damageReductionFactor, "rof": fighterAttr[baseRef + "Duration"], + } + + @staticmethod + def getWeaponSystemData(fit): + weaponSystems = [] + groups = {} + for mod in fit.modules: + if mod.dps > 0: + # Group weapon + ammo combinations that occur more than once + keystr = str(mod.itemID) + "-" + str(mod.chargeID) + if keystr in groups: + groups[keystr][1] += 1 + else: + groups[keystr] = [mod, 1] + for wepGroup in groups.values(): + stats = wepGroup[0] + n = wepGroup[1] + tracking = 0 + maxVelocity = 0 + explosionDelay = 0 + damageReductionFactor = 0 + explosionRadius = 0 + explosionVelocity = 0 + aoeFieldRange = 0 + if stats.hardpoint == Hardpoint.TURRET: + tracking = stats.itemModifiedAttributes["trackingSpeed"] + typeing = "Turret" + name = stats.item.name + ", " + stats.charge.name + # Bombs share most attributes with missiles despite not needing the hardpoint + elif stats.hardpoint == Hardpoint.MISSILE or "Bomb Launcher" in stats.item.name: + maxVelocity = stats.chargeModifiedAttributes["maxVelocity"] + explosionDelay = stats.chargeModifiedAttributes["explosionDelay"] + damageReductionFactor = stats.chargeModifiedAttributes["aoeDamageReductionFactor"] + explosionRadius = stats.chargeModifiedAttributes["aoeCloudSize"] + explosionVelocity = stats.chargeModifiedAttributes["aoeVelocity"] + typeing = "Missile" + name = stats.item.name + ", " + stats.charge.name + elif stats.hardpoint == Hardpoint.NONE: + aoeFieldRange = stats.itemModifiedAttributes["empFieldRange"] + # This also covers non-bomb weapons with dps values and no hardpoints, most notably targeted doomsdays. + typeing = "SmartBomb" + name = stats.item.name statDict = { - 'dps': drone.dps[0], 'cycleTime': drone.cycleTime, 'type': 'Drone', - 'optimal': drone.maxRange, 'name': drone.item.name, 'falloff': drone.falloff, - 'maxSpeed': droneAttr['maxVelocity'], 'tracking': newTracking, - 'volley': drone.dps[1] + "dps": stats.dps * n, "capUse": stats.capUse * n, "falloff": stats.falloff, + "type": typeing, "name": name, "optimal": stats.maxRange, + "numCharges": stats.numCharges, "numShots": stats.numShots, "reloadTime": stats.reloadTime, + "cycleTime": stats.cycleTime, "volley": stats.volley * n, "tracking": tracking, + "maxVelocity": maxVelocity, "explosionDelay": explosionDelay, "damageReductionFactor": damageReductionFactor, + "explosionRadius": explosionRadius, "explosionVelocity": explosionVelocity, "aoeFieldRange": aoeFieldRange } weaponSystems.append(statDict) - for fighter in fit.fighters: - if fighter.dps[0] > 0 and fighter.amountActive > 0: - fighterAttr = fighter.itemModifiedAttributes - abilities = [] - if 'fighterAbilityAttackMissileDamageEM' in fighterAttr: - baseRef = 'fighterAbilityAttackMissile' - ability = getFighterAbilityData(fighterAttr, fighter, baseRef) - abilities.append(ability) - if 'fighterAbilityMissilesDamageEM' in fighterAttr: - baseRef = 'fighterAbilityMissiles' - ability = getFighterAbilityData(fighterAttr, fighter, baseRef) - abilities.append(ability) - statDict = { - 'dps': fighter.dps[0], 'type': 'Fighter', 'name': fighter.item.name, - 'maxSpeed': fighterAttr['maxVelocity'], 'abilities': abilities, - 'ehp': fighterAttr['shieldCapacity'] / 0.8875 * fighter.amountActive, - 'volley': fighter.dps[1], 'signatureRadius': fighterAttr['signatureRadius'] - } - weaponSystems.append(statDict) - return weaponSystems + for drone in fit.drones: + if drone.dps[0] > 0 and drone.amountActive > 0: + droneAttr = drone.itemModifiedAttributes + # Drones are using the old tracking formula for trackingSpeed. This updates it to match turrets. + newTracking = droneAttr["trackingSpeed"] / (droneAttr["optimalSigRadius"] / 40000) + statDict = { + "dps": drone.dps[0], "cycleTime": drone.cycleTime, "type": "Drone", + "optimal": drone.maxRange, "name": drone.item.name, "falloff": drone.falloff, + "maxSpeed": droneAttr["maxVelocity"], "tracking": newTracking, + "volley": drone.dps[1] + } + weaponSystems.append(statDict) + for fighter in fit.fighters: + if fighter.dps[0] > 0 and fighter.amountActive > 0: + fighterAttr = fighter.itemModifiedAttributes + abilities = [] + if "fighterAbilityAttackMissileDamageEM" in fighterAttr: + baseRef = "fighterAbilityAttackMissile" + ability = EfsPort.getFighterAbilityData(fighterAttr, fighter, baseRef) + abilities.append(ability) + if "fighterAbilityMissilesDamageEM" in fighterAttr: + baseRef = "fighterAbilityMissiles" + ability = EfsPort.getFighterAbilityData(fighterAttr, fighter, baseRef) + abilities.append(ability) + statDict = { + "dps": fighter.dps[0], "type": "Fighter", "name": fighter.item.name, + "maxSpeed": fighterAttr["maxVelocity"], "abilities": abilities, + "ehp": fighterAttr["shieldCapacity"] / 0.8875 * fighter.amountActive, + "volley": fighter.dps[1], "signatureRadius": fighterAttr["signatureRadius"] + } + weaponSystems.append(statDict) + return weaponSystems + @staticmethod + def getTestSet(setType): + def getT2ItemsWhere(additionalFilter, mustBeOffensive=False, category="Module"): + # Used to obtain a smaller subset of items while still containing examples of each group. + T2_META_LEVEL = 5 + metaLevelAttrID = getAttributeInfo("metaLevel").attributeID + categoryID = getCategory(category).categoryID + result = gamedata_session.query(Item).join(ItemEffect, Group, Attribute).\ + filter( + additionalFilter, + Attribute.attributeID == metaLevelAttrID, + Attribute.value == T2_META_LEVEL, + Group.categoryID == categoryID, + ).all() + if mustBeOffensive: + result = filter(lambda t: t.offensive is True, result) + return list(result) -wepTestSet = {} + def getChargeType(item, setType): + if setType == "turret": + return str(item.attributes["chargeGroup1"].value) + "-" + str(item.attributes["chargeSize"].value) + return str(item.attributes["chargeGroup1"].value) + if setType in EfsPort.wepTestSet.keys(): + return EfsPort.wepTestSet[setType] + else: + EfsPort.wepTestSet[setType] = [] + modSet = EfsPort.wepTestSet[setType] -def getTestSet(setType): - def GetT2ItemsWhere(additionalFilter, mustBeOffensive=False, category='Module'): - # Used to obtain a smaller subset of items while still containing examples of each group. - T2_META_LEVEL = 5 - metaLevelAttrID = getAttributeInfo('metaLevel').attributeID - categoryID = getCategory(category).categoryID - result = gamedata_session.query(Item).join(ItemEffect, Group, Attribute).\ - filter( - additionalFilter, - Attribute.attributeID == metaLevelAttrID, - Attribute.value == T2_META_LEVEL, - Group.categoryID == categoryID, - ).all() - if mustBeOffensive: - result = filter(lambda t: t.offensive is True, result) - return list(result) + if setType == "drone": + ilist = getT2ItemsWhere(True, True, "Drone") + for item in ilist: + drone = Drone(item) + drone.amount = 1 + drone.amountActive = 1 + drone.itemModifiedAttributes.parent = drone + modSet.append(drone) + return modSet - def getChargeType(item, setType): - if setType == 'turret': - return str(item.attributes['chargeGroup1'].value) + '-' + str(item.attributes['chargeSize'].value) - return str(item.attributes['chargeGroup1'].value) - - if setType in wepTestSet.keys(): - return wepTestSet[setType] - else: - wepTestSet[setType] = [] - modSet = wepTestSet[setType] - - if setType == 'drone': - ilist = GetT2ItemsWhere(True, True, 'Drone') + turretFittedEffectID = gamedata_session.query(Effect).filter(Effect.name == "turretFitted").first().effectID + launcherFittedEffectID = gamedata_session.query(Effect).filter(Effect.name == "launcherFitted").first().effectID + if setType == "launcher": + effectFilter = ItemEffect.effectID == launcherFittedEffectID + reqOff = False + else: + effectFilter = ItemEffect.effectID == turretFittedEffectID + reqOff = True + ilist = getT2ItemsWhere(effectFilter, reqOff) + previousChargeTypes = [] + # Get modules from item list for item in ilist: - drone = Drone(item) - drone.amount = 1 - drone.amountActive = 1 - drone.itemModifiedAttributes.parent = drone - modSet.append(drone) + chargeType = getChargeType(item, setType) + # Only add turrets if we don"t already have one with the same size and ammo type. + if setType == "launcher" or chargeType not in previousChargeTypes: + previousChargeTypes.append(chargeType) + mod = Module(item) + modSet.append(mod) + + mkt = Market.getInstance() + # Due to typed missile damage bonuses we"ll need to add extra launchers to cover all four types. + additionalLaunchers = [] + for mod in modSet: + clist = list(gamedata_session.query(Item).options(). + filter(Item.groupID == mod.itemModifiedAttributes["chargeGroup1"]).all()) + mods = [mod] + charges = [clist[0]] + if setType == "launcher": + # We don"t want variations of missiles we already have + prevCharges = list(mkt.getVariationsByItems(charges)) + testCharges = [] + for charge in clist: + if charge not in prevCharges: + testCharges.append(charge) + prevCharges += mkt.getVariationsByItems([charge]) + for c in testCharges: + charges.append(c) + additionalLauncher = Module(mod.item) + mods.append(additionalLauncher) + for i in range(len(mods)): + mods[i].charge = charges[i] + mods[i].reloadForce = True + mods[i].state = 2 + if setType == "launcher" and i > 0: + additionalLaunchers.append(mods[i]) + modSet += additionalLaunchers return modSet - turretFittedEffectID = gamedata_session.query(Effect).filter(Effect.name == 'turretFitted').first().effectID - launcherFittedEffectID = gamedata_session.query(Effect).filter(Effect.name == 'launcherFitted').first().effectID - if setType == 'launcher': - effectFilter = ItemEffect.effectID == launcherFittedEffectID - reqOff = False - else: - effectFilter = ItemEffect.effectID == turretFittedEffectID - reqOff = True - ilist = GetT2ItemsWhere(effectFilter, reqOff) - previousChargeTypes = [] - # Get modules from item list - for item in ilist: - chargeType = getChargeType(item, setType) - # Only add turrets if we don't already have one with the same size and ammo type. - if setType == 'launcher' or chargeType not in previousChargeTypes: - previousChargeTypes.append(chargeType) - mod = Module(item) - modSet.append(mod) + @staticmethod + def getWeaponBonusMultipliers(fit): + def sumDamage(attr): + totalDamage = 0 + for damageType in ["emDamage", "thermalDamage", "kineticDamage", "explosiveDamage"]: + if attr[damageType] is not None: + totalDamage += attr[damageType] + return totalDamage - mkt = Market.getInstance() - # Due to typed missile damage bonuses we'll need to add extra launchers to cover all four types. - additionalLaunchers = [] - for mod in modSet: - clist = list(gamedata_session.query(Item).options(). - filter(Item.groupID == mod.itemModifiedAttributes['chargeGroup1']).all()) - mods = [mod] - charges = [clist[0]] - if setType == 'launcher': - # We don't want variations of missiles we already have - prevCharges = list(mkt.getVariationsByItems(charges)) - testCharges = [] - for charge in clist: - if charge not in prevCharges: - testCharges.append(charge) - prevCharges += mkt.getVariationsByItems([charge]) - for c in testCharges: - charges.append(c) - additionalLauncher = Module(mod.item) - mods.append(additionalLauncher) - for i in range(len(mods)): - mods[i].charge = charges[i] - mods[i].reloadForce = True - mods[i].state = 2 - if setType == 'launcher' and i > 0: - additionalLaunchers.append(mods[i]) - modSet += additionalLaunchers - return modSet + def getCurrentMultipliers(tf): + fitMultipliers = {} + getDroneMulti = lambda d: sumDamage(d.itemModifiedAttributes) * d.itemModifiedAttributes["damageMultiplier"] + fitMultipliers["drones"] = list(map(getDroneMulti, tf.drones)) + getFitTurrets = lambda f: filter(lambda mod: mod.hardpoint == Hardpoint.TURRET, f.modules) + getTurretMulti = lambda mod: mod.itemModifiedAttributes["damageMultiplier"] / mod.cycleTime + fitMultipliers["turrets"] = list(map(getTurretMulti, getFitTurrets(tf))) -def getWeaponBonusMultipliers(fit): - def sumDamage(attr): - totalDamage = 0 - for damageType in ['emDamage', 'thermalDamage', 'kineticDamage', 'explosiveDamage']: - if attr[damageType] is not None: - totalDamage += attr[damageType] - return totalDamage + getFitLaunchers = lambda f: filter(lambda mod: mod.hardpoint == Hardpoint.MISSILE, f.modules) + getLauncherMulti = lambda mod: sumDamage(mod.chargeModifiedAttributes) / mod.cycleTime + fitMultipliers["launchers"] = list(map(getLauncherMulti, getFitLaunchers(tf))) + return fitMultipliers - def getCurrentMultipliers(tf): - fitMultipliers = {} - getDroneMulti = lambda d: sumDamage(d.itemModifiedAttributes) * d.itemModifiedAttributes['damageMultiplier'] - fitMultipliers['drones'] = list(map(getDroneMulti, tf.drones)) - - getFitTurrets = lambda f: filter(lambda mod: mod.hardpoint == Hardpoint.TURRET, f.modules) - getTurretMulti = lambda mod: mod.itemModifiedAttributes['damageMultiplier'] / mod.cycleTime - fitMultipliers['turrets'] = list(map(getTurretMulti, getFitTurrets(tf))) - - getFitLaunchers = lambda f: filter(lambda mod: mod.hardpoint == Hardpoint.MISSILE, f.modules) - getLauncherMulti = lambda mod: sumDamage(mod.chargeModifiedAttributes) / mod.cycleTime - fitMultipliers['launchers'] = list(map(getLauncherMulti, getFitLaunchers(tf))) - return fitMultipliers - - multipliers = {'turret': 1, 'launcher': 1, 'droneBandwidth': 1} - drones = getTestSet('drone') - launchers = getTestSet('launcher') - turrets = getTestSet('turret') - for weaponTypeSet in [turrets, launchers, drones]: - for mod in weaponTypeSet: - mod.owner = fit - turrets = list(filter(lambda mod: mod.itemModifiedAttributes['damageMultiplier'], turrets)) - launchers = list(filter(lambda mod: sumDamage(mod.chargeModifiedAttributes), launchers)) - # Since the effect modules are fairly opaque a mock test fit is used to test the impact of traits. - tf = Fit.getInstance() - tf.modules = HandledList(turrets + launchers) - tf.character = fit.character - tf.ship = fit.ship - tf.drones = HandledList(drones) - tf.fighters = HandledList([]) - tf.boosters = HandledList([]) - tf.extraAttributes = fit.extraAttributes - tf.mode = fit.mode - preTraitMultipliers = getCurrentMultipliers(tf) - for effect in fit.ship.item.effects.values(): - if effect._Effect__effectModule is not None: - effect.handler(tf, tf.ship, []) - # Factor in mode effects for T3 Destroyers - if fit.mode is not None: - for effect in fit.mode.item.effects.values(): + multipliers = {"turret": 1, "launcher": 1, "droneBandwidth": 1} + drones = EfsPort.getTestSet("drone") + launchers = EfsPort.getTestSet("launcher") + turrets = EfsPort.getTestSet("turret") + for weaponTypeSet in [turrets, launchers, drones]: + for mod in weaponTypeSet: + mod.owner = fit + turrets = list(filter(lambda mod: mod.itemModifiedAttributes["damageMultiplier"], turrets)) + launchers = list(filter(lambda mod: sumDamage(mod.chargeModifiedAttributes), launchers)) + # Since the effect modules are fairly opaque a mock test fit is used to test the impact of traits. + tf = Fit.getInstance() + tf.modules = HandledList(turrets + launchers) + tf.character = fit.character + tf.ship = fit.ship + tf.drones = HandledList(drones) + tf.fighters = HandledList([]) + tf.boosters = HandledList([]) + tf.extraAttributes = fit.extraAttributes + tf.mode = fit.mode + preTraitMultipliers = getCurrentMultipliers(tf) + for effect in fit.ship.item.effects.values(): if effect._Effect__effectModule is not None: - effect.handler(tf, fit.mode, []) - if fit.ship.item.groupID == getGroup('Strategic Cruiser').ID: - subSystems = list(filter(lambda mod: mod.slot == Slot.SUBSYSTEM and mod.item, fit.modules)) - for sub in subSystems: - for effect in sub.item.effects.values(): + effect.handler(tf, tf.ship, []) + # Factor in mode effects for T3 Destroyers + if fit.mode is not None: + for effect in fit.mode.item.effects.values(): if effect._Effect__effectModule is not None: - effect.handler(tf, sub, []) - postTraitMultipliers = getCurrentMultipliers(tf) - getMaxRatio = lambda dictA, dictB, key: max(map(lambda a, b: b / a, dictA[key], dictB[key])) - multipliers['turret'] = round(getMaxRatio(preTraitMultipliers, postTraitMultipliers, 'turrets'), 6) - multipliers['launcher'] = round(getMaxRatio(preTraitMultipliers, postTraitMultipliers, 'launchers'), 6) - multipliers['droneBandwidth'] = round(getMaxRatio(preTraitMultipliers, postTraitMultipliers, 'drones'), 6) - tf.recalc(fit) - return multipliers + effect.handler(tf, fit.mode, []) + if fit.ship.item.groupID == getGroup("Strategic Cruiser").ID: + subSystems = list(filter(lambda mod: mod.slot == Slot.SUBSYSTEM and mod.item, fit.modules)) + for sub in subSystems: + for effect in sub.item.effects.values(): + if effect._Effect__effectModule is not None: + effect.handler(tf, sub, []) + postTraitMultipliers = getCurrentMultipliers(tf) + getMaxRatio = lambda dictA, dictB, key: max(map(lambda a, b: b / a, dictA[key], dictB[key])) + multipliers["turret"] = round(getMaxRatio(preTraitMultipliers, postTraitMultipliers, "turrets"), 6) + multipliers["launcher"] = round(getMaxRatio(preTraitMultipliers, postTraitMultipliers, "launchers"), 6) + multipliers["droneBandwidth"] = round(getMaxRatio(preTraitMultipliers, postTraitMultipliers, "drones"), 6) + tf.recalc(fit) + return multipliers + @staticmethod + def getShipSize(groupID): + # Size groupings are somewhat arbitrary but allow for a more managable number of top level groupings in a tree structure. + frigateGroupNames = ["Frigate", "Shuttle", "Corvette", "Assault Frigate", "Covert Ops", "Interceptor", + "Stealth Bomber", "Electronic Attack Ship", "Expedition Frigate", "Logistics Frigate"] + destroyerGroupNames = ["Destroyer", "Interdictor", "Tactical Destroyer", "Command Destroyer"] + cruiserGroupNames = ["Cruiser", "Heavy Assault Cruiser", "Logistics", "Force Recon Ship", + "Heavy Interdiction Cruiser", "Combat Recon Ship", "Strategic Cruiser"] + bcGroupNames = ["Combat Battlecruiser", "Command Ship", "Attack Battlecruiser"] + bsGroupNames = ["Battleship", "Elite Battleship", "Black Ops", "Marauder"] + capitalGroupNames = ["Titan", "Dreadnought", "Freighter", "Carrier", "Supercarrier", + "Capital Industrial Ship", "Jump Freighter", "Force Auxiliary"] + indyGroupNames = ["Industrial", "Deep Space Transport", "Blockade Runner", + "Mining Barge", "Exhumer", "Industrial Command Ship"] + miscGroupNames = ["Capsule", "Prototype Exploration Ship"] + shipSizes = [ + {"name": "Frigate", "groupIDs": map(lambda s: getGroup(s).ID, frigateGroupNames)}, + {"name": "Destroyer", "groupIDs": map(lambda s: getGroup(s).ID, destroyerGroupNames)}, + {"name": "Cruiser", "groupIDs": map(lambda s: getGroup(s).ID, cruiserGroupNames)}, + {"name": "Battlecruiser", "groupIDs": map(lambda s: getGroup(s).ID, bcGroupNames)}, + {"name": "Battleship", "groupIDs": map(lambda s: getGroup(s).ID, bsGroupNames)}, + {"name": "Capital", "groupIDs": map(lambda s: getGroup(s).ID, capitalGroupNames)}, + {"name": "Industrial", "groupIDs": map(lambda s: getGroup(s).ID, indyGroupNames)}, + {"name": "Misc", "groupIDs": map(lambda s: getGroup(s).ID, miscGroupNames)} + ] + for size in shipSizes: + if groupID in size["groupIDs"]: + return size["name"] + sizeNotFoundMsg = "ShipSize not found for groupID: " + str(groupID) + return sizeNotFoundMsg -def getShipSize(groupID): - # Size groupings are somewhat arbitrary but allow for a more managable number of top level groupings in a tree structure. - frigateGroupNames = ['Frigate', 'Shuttle', 'Corvette', 'Assault Frigate', 'Covert Ops', 'Interceptor', - 'Stealth Bomber', 'Electronic Attack Ship', 'Expedition Frigate', 'Logistics Frigate'] - destroyerGroupNames = ['Destroyer', 'Interdictor', 'Tactical Destroyer', 'Command Destroyer'] - cruiserGroupNames = ['Cruiser', 'Heavy Assault Cruiser', 'Logistics', 'Force Recon Ship', - 'Heavy Interdiction Cruiser', 'Combat Recon Ship', 'Strategic Cruiser'] - bcGroupNames = ['Combat Battlecruiser', 'Command Ship', 'Attack Battlecruiser'] - bsGroupNames = ['Battleship', 'Elite Battleship', 'Black Ops', 'Marauder'] - capitalGroupNames = ['Titan', 'Dreadnought', 'Freighter', 'Carrier', 'Supercarrier', - 'Capital Industrial Ship', 'Jump Freighter', 'Force Auxiliary'] - indyGroupNames = ['Industrial', 'Deep Space Transport', 'Blockade Runner', - 'Mining Barge', 'Exhumer', 'Industrial Command Ship'] - miscGroupNames = ['Capsule', 'Prototype Exploration Ship'] - shipSizes = [ - {'name': 'Frigate', 'groupIDs': map(lambda s: getGroup(s).ID, frigateGroupNames)}, - {'name': 'Destroyer', 'groupIDs': map(lambda s: getGroup(s).ID, destroyerGroupNames)}, - {'name': 'Cruiser', 'groupIDs': map(lambda s: getGroup(s).ID, cruiserGroupNames)}, - {'name': 'Battlecruiser', 'groupIDs': map(lambda s: getGroup(s).ID, bcGroupNames)}, - {'name': 'Battleship', 'groupIDs': map(lambda s: getGroup(s).ID, bsGroupNames)}, - {'name': 'Capital', 'groupIDs': map(lambda s: getGroup(s).ID, capitalGroupNames)}, - {'name': 'Industrial', 'groupIDs': map(lambda s: getGroup(s).ID, indyGroupNames)}, - {'name': 'Misc', 'groupIDs': map(lambda s: getGroup(s).ID, miscGroupNames)} - ] - for size in shipSizes: - if groupID in size['groupIDs']: - return size['name'] - sizeNotFoundMsg = 'ShipSize not found for groupID: ' + str(groupID) - print(sizeNotFoundMsg) - return sizeNotFoundMsg + @staticmethod + def exportEfs(fit, groupID): + includeShipTypeData = groupID > 0 + fitID = fit.ID + if includeShipTypeData: + fitName = fit.name + else: + fitName = fit.ship.name + ": " + fit.name + pyfalog.info("Creating Eve Fleet Simulator data for: " + fit.name) + fitL = Fit.getInstance() + fitL.recalc(fit) + fit = eos.db.getFit(fitID) + fitModAttr = fit.ship.itemModifiedAttributes + propData = EfsPort.getPropData(fit, fitL) + mwdPropSpeed = fit.maxSpeed + if includeShipTypeData: + mwdPropSpeed = EfsPort.getT2MwdSpeed(fit, fitL) + projections = EfsPort.getOutgoingProjectionData(fit) + moduleNames = EfsPort.getModuleNames(fit) + weaponSystems = EfsPort.getWeaponSystemData(fit) - -def parseNeededFitDetails(fit, groupID): - includeShipTypeData = groupID > 0 - fitID = fit.ID - if includeShipTypeData: - fitName = fit.name - else: - fitName = fit.ship.name + ': ' + fit.name - print('') - print('name: ' + fit.name) - fitL = Fit.getInstance() - fitL.recalc(fit) - fit = eos.db.getFit(fitID) - fitModAttr = fit.ship.itemModifiedAttributes - propData = getPropData(fit, fitL) - mwdPropSpeed = fit.maxSpeed - if includeShipTypeData: - mwdPropSpeed = getT2MwdSpeed(fit, fitL) - projections = getOutgoingProjectionData(fit) - moduleNames = getModuleNames(fit) - weaponSystems = getWeaponSystemData(fit) - - turretSlots = fitModAttr['turretSlotsLeft'] if fitModAttr['turretSlotsLeft'] is not None else 0 - launcherSlots = fitModAttr['launcherSlotsLeft'] if fitModAttr['launcherSlotsLeft'] is not None else 0 - droneBandwidth = fitModAttr['droneBandwidth'] if fitModAttr['droneBandwidth'] is not None else 0 - weaponBonusMultipliers = getWeaponBonusMultipliers(fit) - effectiveTurretSlots = round(turretSlots * weaponBonusMultipliers['turret'], 2) - effectiveLauncherSlots = round(launcherSlots * weaponBonusMultipliers['launcher'], 2) - effectiveDroneBandwidth = round(droneBandwidth * weaponBonusMultipliers['droneBandwidth'], 2) - # Assume a T2 siege module for dreads - if groupID == getGroup('Dreadnought').ID: - effectiveTurretSlots *= 9.4 - effectiveLauncherSlots *= 15 - hullResonance = { - 'exp': fitModAttr['explosiveDamageResonance'], 'kin': fitModAttr['kineticDamageResonance'], - 'therm': fitModAttr['thermalDamageResonance'], 'em': fitModAttr['emDamageResonance'] - } - armorResonance = { - 'exp': fitModAttr['armorExplosiveDamageResonance'], 'kin': fitModAttr['armorKineticDamageResonance'], - 'therm': fitModAttr['armorThermalDamageResonance'], 'em': fitModAttr['armorEmDamageResonance'] - } - shieldResonance = { - 'exp': fitModAttr['shieldExplosiveDamageResonance'], 'kin': fitModAttr['shieldKineticDamageResonance'], - 'therm': fitModAttr['shieldThermalDamageResonance'], 'em': fitModAttr['shieldEmDamageResonance'] - } - resonance = {'hull': hullResonance, 'armor': armorResonance, 'shield': shieldResonance} - shipSize = getShipSize(groupID) - - try: - dataDict = { - 'name': fitName, 'ehp': fit.ehp, 'droneDPS': fit.droneDPS, - 'droneVolley': fit.droneVolley, 'hp': fit.hp, 'maxTargets': fit.maxTargets, - 'maxSpeed': fit.maxSpeed, 'weaponVolley': fit.weaponVolley, 'totalVolley': fit.totalVolley, - 'maxTargetRange': fit.maxTargetRange, 'scanStrength': fit.scanStrength, - 'weaponDPS': fit.weaponDPS, 'alignTime': fit.alignTime, 'signatureRadius': fitModAttr['signatureRadius'], - 'weapons': weaponSystems, 'scanRes': fitModAttr['scanResolution'], - 'capUsed': fit.capUsed, 'capRecharge': fit.capRecharge, - 'rigSlots': fitModAttr['rigSlots'], 'lowSlots': fitModAttr['lowSlots'], - 'midSlots': fitModAttr['medSlots'], 'highSlots': fitModAttr['hiSlots'], - 'turretSlots': fitModAttr['turretSlotsLeft'], 'launcherSlots': fitModAttr['launcherSlotsLeft'], - 'powerOutput': fitModAttr['powerOutput'], 'cpuOutput': fitModAttr['cpuOutput'], - 'rigSize': fitModAttr['rigSize'], 'effectiveTurrets': effectiveTurretSlots, - 'effectiveLaunchers': effectiveLauncherSlots, 'effectiveDroneBandwidth': effectiveDroneBandwidth, - 'resonance': resonance, 'typeID': fit.shipID, 'groupID': groupID, 'shipSize': shipSize, - 'droneControlRange': fitModAttr['droneControlRange'], 'mass': fitModAttr['mass'], - 'moduleNames': moduleNames, 'projections': projections, - 'unpropedSpeed': propData['unpropedSpeed'], 'unpropedSig': propData['unpropedSig'], - 'usingMWD': propData['usingMWD'], 'mwdPropSpeed': mwdPropSpeed + turretSlots = fitModAttr["turretSlotsLeft"] if fitModAttr["turretSlotsLeft"] is not None else 0 + launcherSlots = fitModAttr["launcherSlotsLeft"] if fitModAttr["launcherSlotsLeft"] is not None else 0 + droneBandwidth = fitModAttr["droneBandwidth"] if fitModAttr["droneBandwidth"] is not None else 0 + weaponBonusMultipliers = EfsPort.getWeaponBonusMultipliers(fit) + effectiveTurretSlots = round(turretSlots * weaponBonusMultipliers["turret"], 2) + effectiveLauncherSlots = round(launcherSlots * weaponBonusMultipliers["launcher"], 2) + effectiveDroneBandwidth = round(droneBandwidth * weaponBonusMultipliers["droneBandwidth"], 2) + # Assume a T2 siege module for dreads + if groupID == getGroup("Dreadnought").ID: + effectiveTurretSlots *= 9.4 + effectiveLauncherSlots *= 15 + hullResonance = { + "exp": fitModAttr["explosiveDamageResonance"], "kin": fitModAttr["kineticDamageResonance"], + "therm": fitModAttr["thermalDamageResonance"], "em": fitModAttr["emDamageResonance"] } - except TypeError: - print('Error parsing fit:' + str(fit)) - print(TypeError) - dataDict = {'name': fitName + 'Fit could not be correctly parsed'} - export = json.dumps(dataDict, skipkeys=True) - return export + armorResonance = { + "exp": fitModAttr["armorExplosiveDamageResonance"], "kin": fitModAttr["armorKineticDamageResonance"], + "therm": fitModAttr["armorThermalDamageResonance"], "em": fitModAttr["armorEmDamageResonance"] + } + shieldResonance = { + "exp": fitModAttr["shieldExplosiveDamageResonance"], "kin": fitModAttr["shieldKineticDamageResonance"], + "therm": fitModAttr["shieldThermalDamageResonance"], "em": fitModAttr["shieldEmDamageResonance"] + } + resonance = {"hull": hullResonance, "armor": armorResonance, "shield": shieldResonance} + shipSize = EfsPort.getShipSize(groupID) + + try: + dataDict = { + "name": fitName, "ehp": fit.ehp, "droneDPS": fit.droneDPS, + "droneVolley": fit.droneVolley, "hp": fit.hp, "maxTargets": fit.maxTargets, + "maxSpeed": fit.maxSpeed, "weaponVolley": fit.weaponVolley, "totalVolley": fit.totalVolley, + "maxTargetRange": fit.maxTargetRange, "scanStrength": fit.scanStrength, + "weaponDPS": fit.weaponDPS, "alignTime": fit.alignTime, "signatureRadius": fitModAttr["signatureRadius"], + "weapons": weaponSystems, "scanRes": fitModAttr["scanResolution"], + "capUsed": fit.capUsed, "capRecharge": fit.capRecharge, + "rigSlots": fitModAttr["rigSlots"], "lowSlots": fitModAttr["lowSlots"], + "midSlots": fitModAttr["medSlots"], "highSlots": fitModAttr["hiSlots"], + "turretSlots": fitModAttr["turretSlotsLeft"], "launcherSlots": fitModAttr["launcherSlotsLeft"], + "powerOutput": fitModAttr["powerOutput"], "cpuOutput": fitModAttr["cpuOutput"], + "rigSize": fitModAttr["rigSize"], "effectiveTurrets": effectiveTurretSlots, + "effectiveLaunchers": effectiveLauncherSlots, "effectiveDroneBandwidth": effectiveDroneBandwidth, + "resonance": resonance, "typeID": fit.shipID, "groupID": groupID, "shipSize": shipSize, + "droneControlRange": fitModAttr["droneControlRange"], "mass": fitModAttr["mass"], + "moduleNames": moduleNames, "projections": projections, + "unpropedSpeed": propData["unpropedSpeed"], "unpropedSig": propData["unpropedSig"], + "usingMWD": propData["usingMWD"], "mwdPropSpeed": mwdPropSpeed + } + except TypeError: + pyfalog.error("Error parsing fit:" + str(fit)) + pyfalog.error(TypeError) + dataDict = {"name": fitName + "Fit could not be correctly parsed"} + export = json.dumps(dataDict, skipkeys=True) + return export From ebac100e38f5109324c6db4a733512f52070d95a Mon Sep 17 00:00:00 2001 From: MaruMaruOO Date: Tue, 17 Jul 2018 04:22:40 -0400 Subject: [PATCH 18/32] Adjusted EFS to clipboard tooltip --- gui/copySelectDialog.py | 2 +- service/efsPort.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gui/copySelectDialog.py b/gui/copySelectDialog.py index 7f6ec1da8..b74c93b3f 100644 --- a/gui/copySelectDialog.py +++ b/gui/copySelectDialog.py @@ -43,7 +43,7 @@ class CopySelectDialog(wx.Dialog): CopySelectDialog.copyFormatDna: "A one-line text format", CopySelectDialog.copyFormatEsi: "A JSON format used for EVE CREST", CopySelectDialog.copyFormatMultiBuy: "MultiBuy text format", - CopySelectDialog.copyFormatEfs: u"EFS json stats format"} + CopySelectDialog.copyFormatEfs: "JSON data format used by EFS"} selector = wx.RadioBox(self, wx.ID_ANY, label="Copy to the clipboard using:", choices=copyFormats, style=wx.RA_SPECIFY_ROWS) selector.Bind(wx.EVT_RADIOBOX, self.Selected) diff --git a/service/efsPort.py b/service/efsPort.py index 25f6fffa3..31b9fbf91 100755 --- a/service/efsPort.py +++ b/service/efsPort.py @@ -596,7 +596,7 @@ class EfsPort(): "therm": fitModAttr["shieldThermalDamageResonance"], "em": fitModAttr["shieldEmDamageResonance"] } resonance = {"hull": hullResonance, "armor": armorResonance, "shield": shieldResonance} - shipSize = EfsPort.getShipSize(groupID) + shipSize = EfsPort.getShipSize(fit.ship.item.groupID) try: dataDict = { From c0096fc0163a657c3ab939c3ca778a3bbcc5c8d9 Mon Sep 17 00:00:00 2001 From: MaruMaruOO Date: Tue, 17 Jul 2018 20:46:15 -0400 Subject: [PATCH 19/32] Revert irrelevent changes compared to master --- .gitignore | 3 - gui/characterSelection.py | 138 ++------------------------------------ 2 files changed, 6 insertions(+), 135 deletions(-) diff --git a/.gitignore b/.gitignore index 7dc223640..a9eb5e25c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,3 @@ -#Fit and ship export data generated by efs_stat_export.py -*JSON.js - #Python specific *.pyc diff --git a/gui/characterSelection.py b/gui/characterSelection.py index b6b034a4c..051ce69b4 100644 --- a/gui/characterSelection.py +++ b/gui/characterSelection.py @@ -45,15 +45,8 @@ class CharacterSelection(wx.Panel): # cache current selection to fall back in case we choose to open char editor self.charCache = None - #self.charChoice = wx.Choice(self) - #self.charChoice.Append('blarg') - #self.charChoice = wx.Choice(self, wx.ID_ANY, wx.Point(-1,0), wx.DefaultSize, [], style=0, validator=wx.DefaultValidator, name='welp') - self.charChoice = wx.ComboBox( - self, id=wx.ID_ANY, value="", pos=wx.DefaultPosition, - size=wx.DefaultSize, choices=[], style=wx.CB_READONLY, validator=wx.DefaultValidator, - name='welp' - ) - mainSizer.Add(self.charChoice, 1, wx.ALIGN_RIGHT | wx.RIGHT | wx.LEFT, 3) + self.charChoice = wx.Choice(self) + mainSizer.Add(self.charChoice, 1, wx.ALIGN_CENTER_VERTICAL | wx.RIGHT | wx.LEFT, 3) self.refreshCharacterList() @@ -81,8 +74,7 @@ class CharacterSelection(wx.Panel): self.skillReqsStaticBitmap.Bind(wx.EVT_RIGHT_UP, self.OnContextMenu) - #self.Bind(wx.EVT_CHOICE, self.charChanged) - self.Bind(wx.EVT_COMBOBOX, self.charChanged) + self.Bind(wx.EVT_CHOICE, self.charChanged) self.mainFrame.Bind(GE.CHAR_LIST_UPDATED, self.refreshCharacterList) self.mainFrame.Bind(GE.FIT_CHANGED, self.fitChanged) @@ -128,91 +120,6 @@ class CharacterSelection(wx.Panel): selection = self.charChoice.GetCurrentSelection() return self.charChoice.GetClientData(selection) if selection is not -1 else None - def padChoice(self, ind): - return; - from logbook import Logger - pyfalog = Logger(__name__) - #sChar = Character.getInstance() - #activeChar = self.getActiveCharacter() - #charList = sorted(sChar.getCharacterList(), key=lambda c: (not c.ro, c.name)) - charList = list(self.charChoice.GetItems()) - selection = charList[ind] - maxOverallLength = max(map(lambda c: self.mainFrame.GetTextExtent(c).x, charList)) - maxOverallLength = max(self.mainFrame.GetTextExtent("\u2015 Open Character Editor \u2015").x, maxOverallLength) - summedSizeO = sum([ - self.btnRefresh.GetSize().x if 'btnRefresh' in dir(self) else 0, - self.skillReqsStaticBitmap.GetSize().x if 'skillReqsStaticBitmap' in dir(self) else 0, - self.mainFrame.GetTextExtent("Character: ").x, - self.charChoice.GetSize().x if 'charChoice' in dir(self) \ - and self.charChoice is not None and 'GetSize' in dir(self.charChoice) else 0, - ]) - summedSize = sum([ - self.btnRefresh.GetSize().x if 'btnRefresh' in dir(self) else 0, - self.skillReqsStaticBitmap.GetSize().x if 'skillReqsStaticBitmap' in dir(self) else 0, - self.mainFrame.GetTextExtent("Character: ").x, - self.charCache.GetSize().x if 'charCache' in dir(self) \ - and self.charCache is not None and 'GetSize' in dir(self.charCache) else 0 - ]) - realSize = self.GetSize().x - #sizeGap = summedSize - realSize - sizeGap = self.GetBestVirtualSize().x - realSize - paddedName = selection - - maxFromContent = self.mainFrame.GetTextExtent(paddedName).x + sizeGap - maxLength = min(maxFromContent, maxOverallLength) - paddingOccured = False - while self.mainFrame.GetTextExtent(' ' + paddedName).x <= maxLength: - paddingOccured = True - paddedName = ' ' + paddedName - charIDRef = int(self.charChoice.GetClientData(ind)) - pyfalog.error('wwwww') - pyfalog.error(paddedName) - pyfalog.error(self.mainFrame.GetTextExtent(paddedName).x) - pyfalog.error(maxFromContent) - pyfalog.error(maxOverallLength) - pyfalog.error('\n') - pyfalog.error(self.charChoice.GetContainingSizer().GetSize().x) - pyfalog.error(realSize) - pyfalog.error(self.GetBestSize().x) - pyfalog.error(self.GetBestVirtualSize().x) - pyfalog.error('\n') - pyfalog.error(summedSizeO) - pyfalog.error(summedSize) - pyfalog.error( - self.charChoice.GetSize().x if 'charChoice' in dir(self) \ - and self.charChoice is not None and 'GetSize' in dir(self.charChoice) else 0 - ) - pyfalog.error( - self.charCache.GetSize().x if 'charCache' in dir(self) \ - and self.charCache is not None and 'GetSize' in dir(self.charCache) else 0 - ) - pyfalog.error(charIDRef) - pyfalog.error(ind) - pyfalog.error(list(self.charChoice.GetItems())) - ### - import re - for i in range(len(self.charChoice.GetItems())): - origStr = list(self.charChoice.GetItems())[i] - idStore = int(self.charChoice.GetClientData(i)) - self.charChoice.Delete(i) - trimmedStr = '' - for n in range(len(origStr)): - if trimmedStr is not '' or origStr[n] != ' ': - trimmedStr += origStr[n] - possibleName = trimmedStr#re.split(" *", origStr) - pyfalog.error('uuu') - pyfalog.error(possibleName) - self.charChoice.Insert(possibleName, i, idStore) - - if paddingOccured: - self.charChoice.Delete(ind) - pyfalog.error(list(self.charChoice.GetItems())) - self.charChoice.Insert(paddedName, ind, charIDRef) - self.charChoice.Select(ind) - pyfalog.error(list(self.charChoice.GetItems())) - pyfalog.error(int(self.charChoice.GetClientData(ind))) - pyfalog.error('wwwww') - def refreshCharacterList(self, event=None): choice = self.charChoice sChar = Character.getInstance() @@ -221,30 +128,10 @@ class CharacterSelection(wx.Panel): choice.Clear() charList = sorted(sChar.getCharacterList(), key=lambda c: (not c.ro, c.name)) picked = False - from logbook import Logger - pyfalog = Logger(__name__) - maxOverallLength = max(map(lambda c: self.mainFrame.GetTextExtent(c.name).x, charList)) - maxOverallLength = max(self.mainFrame.GetTextExtent("\u2015 Open Character Editor \u2015").x, maxOverallLength) - #summedSize = sum([ - # self.btnRefresh.GetSize().x if 'btnRefresh' in dir(self) else 0, - # self.skillReqsStaticBitmap.GetSize().x if 'skillReqsStaticBitmap' in dir(self) else 0, - # self.mainFrame.GetTextExtent("Character: ").x, - # self.charCache.GetSize().x if 'charCache' in dir(self) and self.charCache is not None else 0, - # ]) - #realSize = self.GetSize().x - #sizeGap = summedSize - realSize + for char in charList: - paddedName = char.name - #maxFromContent = self.mainFrame.GetTextExtent(paddedName).x + self.mainFrame.GetTextExtent("Character: ").x - #maxFromContent = self.mainFrame.GetTextExtent(paddedName).x + sizeGap - #maxLength = min(maxFromContent, maxOverallLength) - #while self.mainFrame.GetTextExtent(paddedName).x < maxLength: - # paddedName = ' ' + paddedName - #currId = choice.Append(str(maxFromContent) + ' ' + \ - # str(self.mainFrame.GetTextExtent(paddedName).x) + ' ' + str(maxLength), char.ID) - currId = choice.Append(paddedName, char.ID) + currId = choice.Append(char.name, char.ID) if char.ID == activeChar: - self.padChoice(currId) choice.SetSelection(currId) self.charChanged(None) picked = True @@ -286,27 +173,16 @@ class CharacterSelection(wx.Panel): if charID == -1: # revert to previous character - self.padChoice(self.charCache) - pyfalog.error('GGG') self.charChoice.SetSelection(self.charCache) - pyfalog.error('GGG') self.mainFrame.showCharacterEditor(event) - pyfalog.error('GGG') return - self.padChoice(self.charChoice.GetCurrentSelection()) - fitID = self.mainFrame.getActiveFit() - charID = self.getActiveCharacter() - pyfalog.error(self.getActiveCharacter()) + self.toggleRefreshButton() - pyfalog.error('RRR') sFit = Fit.getInstance() sFit.changeChar(fitID, charID) self.charCache = self.charChoice.GetCurrentSelection() - pyfalog.error('RRR') - pyfalog.error(fitID) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) - pyfalog.error('RRR') def toggleRefreshButton(self): charID = self.getActiveCharacter() @@ -323,8 +199,6 @@ class CharacterSelection(wx.Panel): for i in range(numItems): id_ = choice.GetClientData(i) if id_ == charID: - print((list(choice.GetItems())[0])) - self.padChoice(i) choice.SetSelection(i) return True From 682607c31f75401ec9d8f83b42c4e13017420502 Mon Sep 17 00:00:00 2001 From: MaruMaruOO Date: Tue, 17 Jul 2018 21:01:26 -0400 Subject: [PATCH 20/32] Remove local build files not intended for git --- savedata/efs_export_all_fits.py | 0 savedata/efs_export_base_fits.py | 255 ---------------------------- savedata/efs_export_pyfa_fits.py | 55 ------ savedata/efs_process_html_export.py | 60 ------- savedata/efs_util.py | 212 ----------------------- savedata/makeAndDiffCheck.sh | 55 ------ 6 files changed, 637 deletions(-) delete mode 100644 savedata/efs_export_all_fits.py delete mode 100644 savedata/efs_export_base_fits.py delete mode 100644 savedata/efs_export_pyfa_fits.py delete mode 100644 savedata/efs_process_html_export.py delete mode 100644 savedata/efs_util.py delete mode 100755 savedata/makeAndDiffCheck.sh diff --git a/savedata/efs_export_all_fits.py b/savedata/efs_export_all_fits.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/savedata/efs_export_base_fits.py b/savedata/efs_export_base_fits.py deleted file mode 100644 index 1682ab716..000000000 --- a/savedata/efs_export_base_fits.py +++ /dev/null @@ -1,255 +0,0 @@ -import inspect -import os -import platform -import re -import sys -import traceback -from optparse import AmbiguousOptionError, BadOptionError, OptionParser - -from logbook import CRITICAL, DEBUG, ERROR, FingersCrossedHandler, INFO, Logger, NestedSetup, NullHandler, StreamHandler, TimedRotatingFileHandler, WARNING, \ - __version__ as logbook_version - -sys.path.append(os.getcwd()) -import config - -from math import log - -try: - import wxversion -except ImportError: - wxversion = None - -try: - import sqlalchemy -except ImportError: - sqlalchemy = None - -pyfalog = Logger(__name__) - -class PassThroughOptionParser(OptionParser): - - def _process_args(self, largs, rargs, values): - while rargs: - try: - OptionParser._process_args(self, largs, rargs, values) - except (BadOptionError, AmbiguousOptionError) as e: - pyfalog.error("Bad startup option passed.") - largs.append(e.opt_str) - -usage = "usage: %prog [--root]" -parser = PassThroughOptionParser(usage=usage) -parser.add_option("-r", "--root", action="store_true", dest="rootsavedata", help="if you want pyfa to store its data in root folder, use this option", default=False) -parser.add_option("-w", "--wx28", action="store_true", dest="force28", help="Force usage of wxPython 2.8", default=False) -parser.add_option("-d", "--debug", action="store_true", dest="debug", help="Set logger to debug level.", default=False) -parser.add_option("-t", "--title", action="store", dest="title", help="Set Window Title", default=None) -parser.add_option("-s", "--savepath", action="store", dest="savepath", help="Set the folder for savedata", default=None) -parser.add_option("-l", "--logginglevel", action="store", dest="logginglevel", help="Set desired logging level [Critical|Error|Warning|Info|Debug]", default="Error") - -(options, args) = parser.parse_args() - -if options.rootsavedata is True: - config.saveInRoot = True - -config.debug = options.debug - -config.defPaths(options.savepath) - -try: - import requests - config.requestsVersion = requests.__version__ -except ImportError: - raise PreCheckException("Cannot import requests. You can download requests from https://pypi.python.org/pypi/requests.") - -import eos.db - -#if config.saVersion[0] > 0 or config.saVersion[1] >= 7: - # <0.7 doesn't have support for events ;_; (mac-deprecated) -config.sa_events = True -import eos.events - - # noinspection PyUnresolvedReferences -import service.prefetch # noqa: F401 - - # Make sure the saveddata db exists -if not os.path.exists(config.savePath): - os.mkdir(config.savePath) - -eos.db.saveddata_meta.create_all() - -import json -from service.fit import Fit -from service.efsPort import EfsPort - -from sqlalchemy import Column, String, Integer, ForeignKey, Boolean, Table -from sqlalchemy.orm import relation, mapper, synonym, deferred -from eos.db import gamedata_session -from eos.db import gamedata_meta -from eos.db.gamedata.metaGroup import metatypes_table, items_table -from eos.db.gamedata.group import groups_table - -from eos.gamedata import AlphaClone, Attribute, Category, Group, Item, MarketGroup, \ - MetaGroup, AttributeInfo, MetaData, Effect, ItemEffect, Traits -from eos.db.gamedata.traits import traits_table -from eos.saveddata.mode import Mode - -def exportBaseShips(opts): - nameReq = '' - if opts: - if opts.search: - nameReq = opts.search - if opts.outputpath: - basePath = opts.outputpath - elif opts.savepath: - basePath = opts.savepath - else: - basePath = config.savePath + os.sep - else: - basePath = config.savePath + os.sep - if basePath[len(basePath) - 1] != os.sep: - basePath = basePath + os.sep - outputBaseline = open(basePath + 'shipBaseJSON.js', 'w') - outputBaseline.write('let shipBaseJSON = JSON.stringify([') - shipCata = eos.db.getItemsByCategory('Ship') - baseLimit = 1000 - baseN = 0 - for ship in iter(shipCata): - if baseN < baseLimit and nameReq in ship.name: - print(ship.name) - print(ship.groupID) - dna = str(ship.ID) - if ship.groupID == 963: - stats = t3cGetStatSet(dna, ship.name, ship.groupID, ship.raceID) - elif ship.groupID == 1305: - stats = t3dGetStatSet(dna, ship.name, ship.groupID, ship.raceID) - else: - stats = setFitFromString(dna, ship.name, ship.groupID) - outputBaseline.write(stats) - outputBaseline.write(',\n') - baseN += 1 - outputBaseline.write(']);\nexport {shipBaseJSON};') - outputBaseline.close() - -def t3dGetStatSet(dnaString, shipName, groupID, raceID): - t3dModeGroupFilter = Group.groupID == 1306 - data = list(gamedata_session.query(Group).options().filter(t3dModeGroupFilter).all()) - #Normally we would filter this via the raceID, - #Unfortunately somebody fat fingered the Jackdaw modes raceIDs as 4 (Amarr) not 1 (Caldari) - # t3dModes = list(filter(lambda mode: mode.raceID == raceID, data[0].items)) #Line for if/when they fix it - t3dModes = list(filter(lambda mode: shipName in mode.name, data[0].items)) - shipModeData = '' - n = 0 - while n < len(t3dModes): - dna = dnaString + ':' + str(t3dModes[n].ID) + ';1' - #Don't add the new line for the last mode - if n < len(t3dModes) - 1: - shipModeData += setFitFromString(dna, t3dModes[n].name, groupID) + ',\n' - else: - shipModeData += setFitFromString(dna, t3dModes[n].name, groupID) - n += 1 - return shipModeData - -def t3cGetStatSet(dnaString, shipName, groupID, raceID): - subsystemFilter = Group.categoryID == 32 - data = list(gamedata_session.query(Group).options().filter(subsystemFilter).all()) - # multi dimension array to hold the t3c subsystems as ss[index of subsystem type][index subsystem item] - ss = [[], [], [], []] - s = 0 - while s < 4: - ss[s] = list(filter(lambda subsystem: subsystem.raceID == raceID, data[s].items)) - s += 1 - print(shipName) - print(ss) - shipPermutationData = '' - n = 0 - a = 0 - while a < 3: - b = 0 - while b < 3: - c = 0 - while c < 3: - d = 0 - while d < 3: - dna = dnaString + ':' + str(ss[0][a].ID) \ - + ';1:' + str(ss[1][b].ID) + ';1:' + str(ss[2][c].ID) \ - + ';1:' + str(ss[3][d].ID) + ';1' - #Don't add the new line for the last permutation - if a == 2 and b == 2 and c == 2 and d == 2: - shipPermutationData += setFitFromString(dna, shipName, groupID) - else: - shipPermutationData += setFitFromString(dna, shipName, groupID) + ',\n' - d += 1 - n += 1 - c += 1 - b += 1 - a += 1 - print(str(n) + ' subsystem conbinations for ' + shipName) - return shipPermutationData -try: - armorLinkShip = eos.db.searchFits('armor links')[0] - infoLinkShip = eos.db.searchFits('information links')[0] - shieldLinkShip = eos.db.searchFits('shield links')[0] - skirmishLinkShip = eos.db.searchFits('skirmish links')[0] -except: - armorLinkShip = None - infoLinkShip = None - shieldLinkShip = None - skirmishLinkShip = None - -def setFitFromString(dnaString, fitName, groupID) : - if armorLinkShip == None: - print('Cannot find correct link fits for base calculations') - return '' - modArray = dnaString.split(':') - fitL = Fit() - fitID = fitL.newFit(int(modArray[0]), fitName) - fit = eos.db.getFit(fitID) - ammoArray = [] - n = -1 - for mod in iter(modArray): - n = n + 1 - if n > 0: - modSp = mod.split(';') - if len(modSp) == 2: - k = 0 - while k < int(modSp[1]): - k = k + 1 - itemID = int(modSp[0]) - item = eos.db.getItem(int(modSp[0]), eager=("attributes", "group.category")) - cat = item.category.name - print(cat) - if cat == 'Drone': - fitL.addDrone(fitID, itemID, int(modSp[1]), recalc=False) - k += int(modSp[1]) - if cat == 'Fighter': - fitL.addFighter(fitID, itemID, recalc=False) - k += 100 - if fitL.isAmmo(int(modSp[0])): - k += 100 - ammoArray.append(int(modSp[0])); - # Set mode if module is a mode on a t3d - if item.groupID == 1306 and groupID == 1305: - fitL.setMode(fitID, Mode(item)) - else: - fitL.appendModule(fitID, int(modSp[0])) - fit = eos.db.getFit(fitID) - for ammo in iter(ammoArray): - fitL.setAmmo(fitID, ammo, list(filter(lambda mod: str(mod).find('name') > 0, fit.modules))) - if len(fit.drones) > 0: - fit.drones[0].amountActive = fit.drones[0].amount - eos.db.commit() - for fighter in iter(fit.fighters): - for ability in fighter.abilities: - if ability.effect.handlerName == u'fighterabilityattackm' and ability.active == True: - for abilityAltRef in fighter.abilities: - if abilityAltRef.effect.isImplemented: - abilityAltRef.active = True - fitL.recalc(fit) - fit = eos.db.getFit(fitID) - print(list(filter(lambda mod: mod.item and mod.item.groupID in [1189, 658], fit.modules))) - fitL.addCommandFit(fit.ID, armorLinkShip) - fitL.addCommandFit(fit.ID, shieldLinkShip) - fitL.addCommandFit(fit.ID, skirmishLinkShip) - fitL.addCommandFit(fit.ID, infoLinkShip) - jsonStr = EfsPort.exportEfs(fit, groupID) - Fit.deleteFit(fitID) - return jsonStr diff --git a/savedata/efs_export_pyfa_fits.py b/savedata/efs_export_pyfa_fits.py deleted file mode 100644 index 9388f8ad6..000000000 --- a/savedata/efs_export_pyfa_fits.py +++ /dev/null @@ -1,55 +0,0 @@ -import inspect -import os -import platform -import re -import sys -import traceback - -sys.path.append(os.getcwd()) -import config -from pyfa import options - -if options.rootsavedata is True: - config.saveInRoot = True -config.debug = options.debug -config.defPaths(options.savepath) - -import eos.db -# Make sure the saveddata db exists -if not os.path.exists(config.savePath): - os.mkdir(config.savePath) - -from service.efsPort import EfsPort - -def exportPyfaFits(opts): - nameReq = '' - if opts: - if opts.search: - nameReq = opts.search - if opts.outputpath: - basePath = opts.outputpath - elif opts.savepath: - basePath = opts.savepath - else: - basePath = config.savePath + os.sep - else: - basePath = config.savePath + os.sep - if basePath[len(basePath) - 1] != os.sep: - basePath = basePath + os.sep - output = open(basePath + 'shipJSON.js', 'w') - output.write('let shipJSON = JSON.stringify([') - #The current storage system isn't going to hold more than 2500 fits as local browser storage is limited - limit = 2500 - skipTill = 0 - n = 0 - fitList = eos.db.getFitList() - for fit in fitList: - if limit == None or n < limit: - n += 1 - name = fit.ship.name + ': ' + fit.name - if n >= skipTill and nameReq in name: - stats = EfsPort.exportEfs(fit, 0) - output.write(stats) - output.write(',\n') - output.write(']);\nexport {shipJSON};') - output.close() diff --git a/savedata/efs_process_html_export.py b/savedata/efs_process_html_export.py deleted file mode 100644 index 8e48bda3c..000000000 --- a/savedata/efs_process_html_export.py +++ /dev/null @@ -1,60 +0,0 @@ -from efs_export_base_fits import * - -def efsFitsFromHTMLExport(opts): - if opts: - if opts.outputpath: - basePath = opts.outputpath - elif opts.savepath: - basePath = opts.savepath - else: - basePath = config.savePath + os.sep - else: - basePath = config.savePath + os.sep - if basePath[len(basePath) - 1] != os.sep: - basePath = basePath + os.sep - output = open(basePath + 'shipJSON.js', 'w') - output.write('let shipJSON = JSON.stringify([') - try: - with open('pyfaFits.html'): - fileLocation = 'pyfaFits.html' - except: - try: - d = config.savePath + os.sep + 'pyfaFits.html' - print(d) - with open(d): - fileLocation = d - except: - fileLocation = None; - limit = 10000 - n = 0 - skipTill = 0 - nameReq = '' - minimalExport = True - if fileLocation != None: - with open(fileLocation) as f: - for fullLine in f: - if limit == None or n < limit: - if n <= 1 and '' in fullLine: - minimalExport = False - n += 1 - fullIndex = fullLine.find('data-dna="') - minimalIndex = fullLine.find('/dna/') - if fullIndex >= 0: - startInd = fullLine.find('data-dna="') + 10 - elif minimalIndex >= 0 and minimalExport: - startInd = fullLine.find('/dna/') + 5 - else: - startInd = -1 - print(startInd) - if startInd >= 0: - line = fullLine[startInd:len(fullLine)] - endInd = line.find('::') - dna = line[0:endInd] - name = line[line.find('>') + 1:line.find('<')] - if n >= skipTill and nameReq in name: - print('name: ' + name + ' DNA: ' + dna + fullLine) - stats = setFitFromString(dna, name, 0) - output.write(stats) - output.write(',\n') - output.write(']);\nexport {shipJSON};') - output.close() diff --git a/savedata/efs_util.py b/savedata/efs_util.py deleted file mode 100644 index e52ee82bd..000000000 --- a/savedata/efs_util.py +++ /dev/null @@ -1,212 +0,0 @@ -from optparse import AmbiguousOptionError, BadOptionError, OptionParser - -class PassThroughOptionParser(OptionParser): - - def _process_args(self, largs, rargs, values): - while rargs: - try: - OptionParser._process_args(self, largs, rargs, values) - except (BadOptionError, AmbiguousOptionError) as e: - pyfalog.error("Bad startup option passed.") - largs.append(e.opt_str) - -usage = "usage: %prog [options]" -parser = PassThroughOptionParser(usage=usage) -parser.add_option( - "-f", "--exportfits", action="store_true", dest="exportfits", \ - help="Export this copy of pyfa's local fits to a shipJSON file that Eve Fleet Simulator can import from", \ - default=False) -parser.add_option( - "-b", "--exportbaseships", action="store_true", dest="exportbaseships", \ - help="Export ship stats to a shipBaseJSON file used by Eve Fleet Simulator", \ - default=False) -parser.add_option( - "-c", "--convertfitsfromhtml", action="store_true", dest="convertfitsfromhtml", \ - help="Convert an exported pyfaFits.html file to a shipJSON file that Eve Fleet Simulator can import from\n" - + " Note this process loses data like fleet boosters as the DNA format exported by to html contains limited data", \ - default=False) -parser.add_option("-s", "--savepath", action="store", dest="savepath", - help="Set the folder for savedata", default=None) -parser.add_option( - "-o", "--outputpath", action="store", dest="outputpath", - help="Output directory, defaults to the savepath", default=None) -parser.add_option( - '-i', "--search", action="store", dest="search", - help="Ignore ships and fits that don't contain the searched string", default=None) - - -(options, args) = parser.parse_args() - -if options.exportfits: - from efs_export_pyfa_fits import exportPyfaFits - exportPyfaFits(options) - -if options.exportbaseships: - from efs_export_base_fits import exportBaseShips - exportBaseShips(options) - -if options.convertfitsfromhtml: - from efs_process_html_export import efsFitsFromHTMLExport - efsFitsFromHTMLExport(options) - -#stuff bellow this point is purely scrap diagnostic stuff and should not be public (as it's scrawl) -def printGroupData(): - from eos.db import gamedata_session - from eos.gamedata import Group, Category - filterVal = Group.categoryID == 6 - data = gamedata_session.query(Group).options().list(filter(filterVal).all()) - for group in data: - print(group.groupName + ' groupID: ' + str(group.groupID)) - return '' - -def printSizeData(): - from eos.db import gamedata_session - from eos.gamedata import Group - filterVal = Group.categoryID == 6 - data = gamedata_session.query(Group).options().filter(filterVal).all() - ships = gamedata_session.query(Group).options().filter(filterVal) - print(data) - print(vars(data[0])) - - shipSizes = ['Frigate', 'Destroyer', 'Cruiser', 'Battlecruiser', 'Battleship', 'Capital', 'Industrial', 'Misc'] - groupSets = [ - [25, 31, 237, 324, 830, 831, 834, 893, 1283, 1527], - [420, 541, 1305, 1534], - [26, 358, 832, 833, 894, 906, 963], - [419, 540, 1201], - [27, 381, 898, 900], - [30, 485, 513, 547, 659, 883, 902, 1538], - [28, 380, 1202, 463, 543, 941], - [29, 1022] - ] - i = 0 - while i < 8: - groupNames = '\'' + shipSizes[i] + '\': {\'name\': \'' + shipSizes[i] + '\', \'groupIDs\': groupIDFromGroupName([' - for gid in groupSets[i]: - if gid is not groupSets[i][0]: - groupNames = groupNames + '\', ' - groupNames = groupNames + '\'' + list(filter(lambda gr: gr.groupID == gid, data))[0].groupName - print(groupNames + '\'], data)}') - i = i + 1 - projectedModGroupIds = [ - 41, 52, 65, 67, 68, 71, 80, 201, 208, 291, 325, 379, 585, - 842, 899, 1150, 1154, 1189, 1306, 1672, 1697, 1698, 1815, 1894 - ] - from eos.db import gamedata_session - from eos.gamedata import Group - data = gamedata_session.query(Group).all() - groupNames = '' - for gid in projectedModGroupIds: - if gid is not projectedModGroupIds[0]: - groupNames = groupNames + '\', ' - print(gid) - groupNames = groupNames + '\'' + list(filter(lambda gr: gr.groupID == gid, data))[0].groupName - print(groupNames + '\'') - -def wepMultisFromTraitText(fit): - filterVal = Traits.typeID == fit.shipID - data = gamedata_session.query(Traits).options().filter(filterVal).all() - roleBonusMode = False - if len(data) == 0: - return multipliers - d = data[0] - s1 = str(vars(d)) - ds = s1.encode(encoding="utf-8", errors="ignore") - #print(ds) - previousTypedBonus = 0 - previousDroneTypeBonus = 0 - for bonusText in data[0].traitText.splitlines(): - bonusText = bonusText.lower() - if 'per skill level' in bonusText: - roleBonusMode = False - if 'role bonus' in bonusText or 'misc bonus' in bonusText: - roleBonusMode = True - multi = 1 - if 'damage' in bonusText and not any(e in bonusText for e in ['control', 'heat']): - splitText = bonusText.split('%') - if (float(splitText[0]) > 0) is False: - print('damage bonus split did not parse correctly!') - print(float(splitText[0])) - if roleBonusMode: - addedMulti = float(splitText[0]) - else: - addedMulti = float(splitText[0]) * 5 - if any(e in bonusText for e in [' em', 'thermal', 'kinetic', 'explosive']): - if addedMulti > previousTypedBonus: - previousTypedBonus = addedMulti - else: - addedMulti = 0 - if any(e in bonusText for e in ['heavy drone', 'medium drone', 'light drone', 'sentry drone']): - if addedMulti > previousDroneTypeBonus: - previousDroneTypeBonus = addedMulti - else: - addedMulti = 0 - multi = 1 + (addedMulti / 100) - elif 'rate of fire' in bonusText: - splitText = bonusText.split('%') - if (float(splitText[0]) > 0) is False: - print('rate of fire bonus split did not parse correctly!') - print(float(splitText[0])) - if roleBonusMode: - rofMulti = float(splitText[0]) - else: - rofMulti = float(splitText[0]) * 5 - multi = 1 / (1 - (rofMulti / 100)) - if multi > 1: - if 'drone' in bonusText.lower(): - multipliers['droneBandwidth'] *= multi - elif 'turret' in bonusText.lower(): - multipliers['turret'] *= multi - elif any(e in bonusText for e in ['missile', 'torpedo']): - multipliers['launcher'] *= multi - - -def examDiff(ai, bi, attr=False): - print('') - print('A:' + str(ai)) - print('B:' + str(bi)) - a = dict(map(lambda k: (k, getattr(ai, k)), dir(ai))) - b = dict(map(lambda k: (k, getattr(bi, k)), dir(bi))) - try: - print(a.keys()) - print('A:' + str(a)) - print(b.keys()) - print('B:' + str(b)) - print('A exclusive keys:') - for key in filter(lambda k: k not in b.keys(), a.keys()): - print(key) - print('B exclusive keys:') - for key in filter(lambda k: k not in a.keys(), b.keys()): - print(key) - print('A key/value pairs where B is None:') - for key in filter(lambda k: k in b.keys() and b[k] == None and a[k] != None, a.keys()): - print(key) - print(a[key]) - print('B key/value pairs where A is None:') - for key in filter(lambda k: k in a.keys() and a[k] == None and b[k] != None, b.keys()): - print(key) - print(b[key]) - except Exception as e: - if attr == True: - print('Could not print itemModifiedAttributes for a or b') - print(e) - else: - print('Checking itemModifiedAttributes diff') - examDiff(ai.itemModifiedAttributes, bi.itemModifiedAttributes, True) - if attr == False: - print('Checking itemModifiedAttributes diff') - examDiff(ai.itemModifiedAttributes, bi.itemModifiedAttributes, True) - print('') - -def groupIDFromGroupName(names, data=None): - # Group data can optionally be passed to the function to improve preformace with repeated calls. - if data is None: - data = gamedata_session.query(Group).all() - returnSingle = False - if not isinstance(names, list): - names = [names] - returnSingle = True - gidList = list(map(lambda incGroup: incGroup.groupID, (filter(lambda group: group.groupName in names, data)))) - if returnSingle: - return gidList[0] - return gidList diff --git a/savedata/makeAndDiffCheck.sh b/savedata/makeAndDiffCheck.sh deleted file mode 100755 index c1aee9dc3..000000000 --- a/savedata/makeAndDiffCheck.sh +++ /dev/null @@ -1,55 +0,0 @@ -#!/bin/bash -if [[ $2 == -v ]] ; then - MUTE=False -else - MUTE=TRUE -fi -EXPECTERRORS=False -if [[ $3 == --search ]] ; then - if [[ $5 == --expect-errors ]] ; then - EXPECTERRORS=True - fi -else - if [[ $3 == --expect-errors ]] ; then - EXPECTERRORS=True - fi -fi -if [[ $1 == -f ]] ; then - if [[ $MUTE == TRUE ]] ; then - python3opt savedata/efs_util.py\ -f | grep awgahwogfa - else - python3opt savedata/efs_util.py\ -f\ --search=$4 - fi -elif [[ $1 == -b ]] ; then - if [[ $MUTE == TRUE ]] ; then - python3opt savedata/efs_util.py\ -b | grep awgahwogfa - else - python3opt savedata/efs_util.py\ -b\ --search=$4 - fi -elif [[ $1 == -u ]] ; then - if [[ $MUTE == TRUE ]] ; then - python3opt savedata/efs_util.py\ -b\ -f\ -o\ .. | grep awgahwogfa - else - python3opt savedata/efs_util.py\ -b\ -f\ -o\ .. - fi -elif [[ $1 == -a ]] ; then - if [[ $MUTE == TRUE ]] ; then - python3opt savedata/efs_util.py\ -b\ -f | grep awgahwogfa - else - python3opt savedata/efs_util.py\ -b\ -f\ --search=$4 - fi -else - echo Defaulting to fits and base ships.\n - if [[ $MUTE == TRUE ]] ; then - python3opt savedata/efs_util.py\ -b\ -f | grep awgahwogfa - else - python3opt savedata/efs_util.py\ -b\ -f\ --search=$4 - fi -fi -if [[ $EXPECTERRORS == True ]] ; then - echo Expecting non standard output, this should only be used for testing -else -diff -s --color=always ../shipJSON.js ~/.pyfa/shipJSON.js | grep -m 3 --color '' -diff -s --color=always ../shipBaseJSON.js ~/.pyfa/shipBaseJSON.js | grep -m 3 --color '' -/home/stock/scripts/Pyfa/.tox/pep8/bin/flake8 --exclude=.svn,CVS,.bzr,.hg,.git,__pycache__,venv,tests,.tox,build,dist,__init__.py,floatspin.py --ignore=E121,E126,E127,E128,E203,E731,F401,E722,E741 service/efsPort.py --max-line-length=165 -fi From a6a0831123746158842cc83011fb023579ddf868 Mon Sep 17 00:00:00 2001 From: MaruMaruOO Date: Tue, 17 Jul 2018 21:03:39 -0400 Subject: [PATCH 21/32] Removed uneeded file --- savedata/getmods.py | 88 --------------------------------------------- 1 file changed, 88 deletions(-) delete mode 100644 savedata/getmods.py diff --git a/savedata/getmods.py b/savedata/getmods.py deleted file mode 100644 index 16ef06103..000000000 --- a/savedata/getmods.py +++ /dev/null @@ -1,88 +0,0 @@ -# -*- coding: utf-8 -*- -#!/usr/bin/env python -if __name__ == "__main__": - import argparse - import json - import os.path - import sys - sys.path.append(os.getcwd()) - - from eos import * - from eos.data.data_handler import JsonDataHandler - from eos.const.eos import * - - json_path = r"/path/to/Phobos/dump" - - parser = argparse.ArgumentParser(description="Figure out what actually effect does") - parser.add_argument("-e", "--effect", type=str, required=True, help="effect name") - args = parser.parse_args() - - # open a few files to get human-readable names for data (EOS strictly works with numerical identifiers) - with open(os.path.join(json_path, "dgmattribs.json"), mode='r', encoding="utf8") as file: - dgmattribs = json.load(file) - - with open(os.path.join(json_path, 'dgmeffects.json'), mode='r', encoding="utf8") as file: - dgmeffects = json.load(file) - - with open(os.path.join(json_path, 'invtypes.json'), mode='r', encoding="utf8") as file: - invtypes = json.load(file) - - with open(os.path.join(json_path, 'invgroups.json'), mode='r', encoding="utf8") as file: - invgroups = json.load(file) - - attr_id_name = {} - attr_id_penalized = {} - for row in dgmattribs: - attr_id_name[row['attributeID']] = row['attributeName'] - attr_id_penalized[row['attributeID']] = 'not penalized' if row['stackable'] else 'penalized' - - effect_id_name = {} - for row in dgmeffects: - effect_id_name[row['effectID']] = row['effectName'] - if row['effectName'] == args.effect: - effect_id = row['effectID'] - break - - type_id_name = {} - for _, row in invtypes.items(): - name = row.get("typeName_en-us", None) - if name: - type_id_name[row['typeID']] = name - - group_id_name = {} - for _, row in invgroups.items(): - group_id_name[row['groupID']] = row['groupName_en-us'] - - data_handler = JsonDataHandler(json_path) # Folder with Phobos data dump - cache_handler = JsonCacheHandler(os.path.join(json_path, "cache", "eos_tq.json.bz2")) - SourceManager.add('evedata', data_handler, cache_handler, make_default=True) - - effect = cache_handler.get_effect(effect_id) - modifiers = effect.modifiers - mod_counter = 1 - indent = ' ' - print('effect {}.py (id: {}) - build status is {}'.format(args.effect.lower(), effect_id, EffectBuildStatus(effect.build_status).name)) - for modifier in modifiers: - print('{}Modifier {}:'.format(indent, mod_counter)) - print('{0}{0}state: {1}'.format(indent, State(modifier.state).name)) - print('{0}{0}scope: {1}'.format(indent, Scope(modifier.scope).name)) - print('{0}{0}srcattr: {1} {2}'.format(indent, attr_id_name[modifier.src_attr], modifier.src_attr)) - print('{0}{0}operator: {1} {2}'.format(indent, Operator(modifier.operator).name, modifier.operator)) - print('{0}{0}tgtattr: {1} ({2}) {3}'.format( - indent, - attr_id_name[modifier.tgt_attr], - attr_id_penalized[modifier.tgt_attr],modifier.tgt_attr) - ) - print('{0}{0}location: {1}'.format(indent, Domain(modifier.domain).name)) - try: - filter_type = FilterType(modifier.filter_type).name - except ValueError: - filter_type = None - print('{0}{0}filter type: {1}'.format(indent, filter_type)) - if modifier.filter_type is None or modifier.filter_type in (FilterType.all_, FilterType.skill_self): - pass - elif modifier.filter_type == FilterType.skill: - print('{0}{0}filter value: {1}'.format(indent, type_id_name[modifier.filter_value])) - elif modifier.filter_type == FilterType.group: - print('{0}{0}filter value: {1}'.format(indent, group_id_name[modifier.filter_value])) - mod_counter += 1 From 6be77646fcf063bd3ef39d6d5189d9a556fd9239 Mon Sep 17 00:00:00 2001 From: MaruMaruOO Date: Tue, 17 Jul 2018 22:32:30 -0400 Subject: [PATCH 22/32] Linting for consistancy --- service/efsPort.py | 37 ++++++++++++++++++++----------------- service/fit.py | 1 - 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/service/efsPort.py b/service/efsPort.py index 31b9fbf91..5bc5e5632 100755 --- a/service/efsPort.py +++ b/service/efsPort.py @@ -38,7 +38,7 @@ class EfsPort(): target[val] = source.itemModifiedAttributes[val] @staticmethod - def getT2MwdSpeed(fit, fitL): + def getT2MwdSpeed(fit, sFit): fitID = fit.ID propID = None shipHasMedSlots = fit.ship.itemModifiedAttributes["medSlots"] > 0 @@ -70,18 +70,18 @@ class EfsPort(): if propID is None: return None - fitL.appendModule(fitID, propID) - fitL.recalc(fit) + sFit.appendModule(fitID, propID) + sFit.recalc(fit) fit = eos.db.getFit(fitID) mwdPropSpeed = fit.maxSpeed mwdPosition = list(filter(lambda mod: mod.item and mod.item.ID == propID, fit.modules))[0].position - fitL.removeModule(fitID, mwdPosition) - fitL.recalc(fit) + sFit.removeModule(fitID, mwdPosition) + sFit.recalc(fit) fit = eos.db.getFit(fitID) return mwdPropSpeed @staticmethod - def getPropData(fit, fitL): + def getPropData(fit, sFit): fitID = fit.ID propGroupId = getGroup("Propulsion Module").ID propMods = filter(lambda mod: mod.item and mod.item.groupID == propGroupId, fit.modules) @@ -90,12 +90,12 @@ class EfsPort(): if propWithBloom is not None: oldPropState = propWithBloom.state propWithBloom.state = 0 - fitL.recalc(fit) + sFit.recalc(fit) fit = eos.db.getFit(fitID) sp = fit.maxSpeed sig = fit.ship.itemModifiedAttributes["signatureRadius"] propWithBloom.state = oldPropState - fitL.recalc(fit) + sFit.recalc(fit) fit = eos.db.getFit(fitID) return {"usingMWD": True, "unpropedSpeed": sp, "unpropedSig": sig} return { @@ -426,7 +426,7 @@ class EfsPort(): mod = Module(item) modSet.append(mod) - mkt = Market.getInstance() + sMkt = Market.getInstance() # Due to typed missile damage bonuses we"ll need to add extra launchers to cover all four types. additionalLaunchers = [] for mod in modSet: @@ -436,12 +436,12 @@ class EfsPort(): charges = [clist[0]] if setType == "launcher": # We don"t want variations of missiles we already have - prevCharges = list(mkt.getVariationsByItems(charges)) + prevCharges = list(sMkt.getVariationsByItems(charges)) testCharges = [] for charge in clist: if charge not in prevCharges: testCharges.append(charge) - prevCharges += mkt.getVariationsByItems([charge]) + prevCharges += sMkt.getVariationsByItems([charge]) for c in testCharges: charges.append(c) additionalLauncher = Module(mod.item) @@ -488,7 +488,10 @@ class EfsPort(): turrets = list(filter(lambda mod: mod.itemModifiedAttributes["damageMultiplier"], turrets)) launchers = list(filter(lambda mod: sumDamage(mod.chargeModifiedAttributes), launchers)) # Since the effect modules are fairly opaque a mock test fit is used to test the impact of traits. - tf = Fit.getInstance() + # standin class used to prevent . notation causing issues internally + class standin(): + pass + tf = standin() tf.modules = HandledList(turrets + launchers) tf.character = fit.character tf.ship = fit.ship @@ -517,7 +520,7 @@ class EfsPort(): multipliers["turret"] = round(getMaxRatio(preTraitMultipliers, postTraitMultipliers, "turrets"), 6) multipliers["launcher"] = round(getMaxRatio(preTraitMultipliers, postTraitMultipliers, "launchers"), 6) multipliers["droneBandwidth"] = round(getMaxRatio(preTraitMultipliers, postTraitMultipliers, "drones"), 6) - tf.recalc(fit) + Fit.getInstance().recalc(fit) return multipliers @staticmethod @@ -560,14 +563,14 @@ class EfsPort(): else: fitName = fit.ship.name + ": " + fit.name pyfalog.info("Creating Eve Fleet Simulator data for: " + fit.name) - fitL = Fit.getInstance() - fitL.recalc(fit) + sFit = Fit.getInstance() + sFit.recalc(fit) fit = eos.db.getFit(fitID) fitModAttr = fit.ship.itemModifiedAttributes - propData = EfsPort.getPropData(fit, fitL) + propData = EfsPort.getPropData(fit, sFit) mwdPropSpeed = fit.maxSpeed if includeShipTypeData: - mwdPropSpeed = EfsPort.getT2MwdSpeed(fit, fitL) + mwdPropSpeed = EfsPort.getT2MwdSpeed(fit, sFit) projections = EfsPort.getOutgoingProjectionData(fit) moduleNames = EfsPort.getModuleNames(fit) weaponSystems = EfsPort.getWeaponSystemData(fit) diff --git a/service/fit.py b/service/fit.py index 26913846c..122de2fa6 100644 --- a/service/fit.py +++ b/service/fit.py @@ -60,7 +60,6 @@ class Fit(object): self.dirtyFitIDs = set() serviceFittingDefaultOptions = { - "useCharecterImplantsByDefault": True, "useGlobalCharacter": False, "useCharacterImplantsByDefault": True, "useGlobalDamagePattern": False, From c054a2d80d0409a21a602dad55d6f7ad8e23cb63 Mon Sep 17 00:00:00 2001 From: MaruMaruOO Date: Tue, 17 Jul 2018 23:09:39 -0400 Subject: [PATCH 23/32] Trivial lint --- service/efsPort.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/service/efsPort.py b/service/efsPort.py index 5bc5e5632..1b325c6d8 100755 --- a/service/efsPort.py +++ b/service/efsPort.py @@ -488,7 +488,7 @@ class EfsPort(): turrets = list(filter(lambda mod: mod.itemModifiedAttributes["damageMultiplier"], turrets)) launchers = list(filter(lambda mod: sumDamage(mod.chargeModifiedAttributes), launchers)) # Since the effect modules are fairly opaque a mock test fit is used to test the impact of traits. - # standin class used to prevent . notation causing issues internally + # standin class used to prevent . notation causing issues when used as an arg class standin(): pass tf = standin() From 38726675e1f509dcf5c2a5f8fad28da943025118 Mon Sep 17 00:00:00 2001 From: MaruMaruOO Date: Mon, 23 Jul 2018 20:28:53 -0400 Subject: [PATCH 24/32] Added disintegrator stats --- service/efsPort.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/service/efsPort.py b/service/efsPort.py index 1b325c6d8..2c4a4423e 100755 --- a/service/efsPort.py +++ b/service/efsPort.py @@ -332,7 +332,9 @@ class EfsPort(): "numCharges": stats.numCharges, "numShots": stats.numShots, "reloadTime": stats.reloadTime, "cycleTime": stats.cycleTime, "volley": stats.volley * n, "tracking": tracking, "maxVelocity": maxVelocity, "explosionDelay": explosionDelay, "damageReductionFactor": damageReductionFactor, - "explosionRadius": explosionRadius, "explosionVelocity": explosionVelocity, "aoeFieldRange": aoeFieldRange + "explosionRadius": explosionRadius, "explosionVelocity": explosionVelocity, "aoeFieldRange": aoeFieldRange, + "damageMultiplierBonusMax": stats.getModifiedItemAttr("damageMultiplierBonusMax"), + "damageMultiplierBonusPerCycle": stats.getModifiedItemAttr("damageMultiplierBonusPerCycle") } weaponSystems.append(statDict) for drone in fit.drones: From 03e325cdcbfc646930bc60d11864d27a2dcf0868 Mon Sep 17 00:00:00 2001 From: MaruMaruOO Date: Thu, 26 Jul 2018 11:23:39 -0400 Subject: [PATCH 25/32] Change efsPort.getOutgoingProjectionData to corectly use mod.item.group.name --- service/efsPort.py | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/service/efsPort.py b/service/efsPort.py index 2c4a4423e..189467cb1 100755 --- a/service/efsPort.py +++ b/service/efsPort.py @@ -116,18 +116,15 @@ class EfsPort(): "Ancillary Remote Shield Booster", "Ancillary Remote Armor Repairer", "Titan Phenomena Generator", "Non-Repeating Hardeners" ] - modGroupIds = list(map(lambda s: getGroup(s).ID, modGroupNames)) - modGroupData = dict(map(lambda name, gid: (name, {"name": name, "id": gid}), - modGroupNames, modGroupIds)) - projectedMods = list(filter(lambda mod: mod.item and mod.item.groupID in modGroupIds, fit.modules)) + projectedMods = list(filter(lambda mod: mod.item and mod.item.group.name in modGroupNames, fit.modules)) projections = [] for mod in projectedMods: stats = {} - if mod.item.groupID in [modGroupData["Stasis Web"]["id"], modGroupData["Stasis Grappler"]["id"]]: + if mod.item.group.name in ["Stasis Web", "Stasis Grappler"]: stats["type"] = "Stasis Web" stats["optimal"] = mod.itemModifiedAttributes["maxRange"] EfsPort.attrDirectMap(["duration", "speedFactor"], stats, mod) - elif mod.item.groupID == modGroupData["Weapon Disruptor"]["id"]: + elif mod.item.group.name == "Weapon Disruptor": stats["type"] = "Weapon Disruptor" stats["optimal"] = mod.itemModifiedAttributes["maxRange"] stats["falloff"] = mod.itemModifiedAttributes["falloffEffectiveness"] @@ -135,50 +132,50 @@ class EfsPort(): "trackingSpeedBonus", "maxRangeBonus", "falloffBonus", "aoeCloudSizeBonus", "aoeVelocityBonus", "missileVelocityBonus", "explosionDelayBonus" ], stats, mod) - elif mod.item.groupID == modGroupData["Energy Nosferatu"]["id"]: + elif mod.item.group.name == "Energy Nosferatu": stats["type"] = "Energy Nosferatu" EfsPort.attrDirectMap(["powerTransferAmount", "energyNeutralizerSignatureResolution"], stats, mod) - elif mod.item.groupID == modGroupData["Energy Neutralizer"]["id"]: + elif mod.item.group.name == "Energy Neutralizer": stats["type"] = "Energy Neutralizer" EfsPort.attrDirectMap([ "energyNeutralizerSignatureResolution", "entityCapacitorLevelModifierSmall", "entityCapacitorLevelModifierMedium", "entityCapacitorLevelModifierLarge", "energyNeutralizerAmount" ], stats, mod) - elif mod.item.groupID in [modGroupData["Remote Shield Booster"]["id"], - modGroupData["Ancillary Remote Shield Booster"]["id"]]: + elif mod.item.group.name in ["Remote Shield Booster", "Ancillary Remote Shield Booster"]: stats["type"] = "Remote Shield Booster" EfsPort.attrDirectMap(["shieldBonus"], stats, mod) - elif mod.item.groupID in [modGroupData["Remote Armor Repairer"]["id"], - modGroupData["Ancillary Remote Armor Repairer"]["id"]]: + elif mod.item.group.name in ["Remote Armor Repairer", "Ancillary Remote Armor Repairer"]: stats["type"] = "Remote Armor Repairer" EfsPort.attrDirectMap(["armorDamageAmount"], stats, mod) - elif mod.item.groupID == modGroupData["Warp Scrambler"]["id"]: + elif mod.item.group.name == "Warp Scrambler": stats["type"] = "Warp Scrambler" EfsPort.attrDirectMap(["activationBlockedStrenght", "warpScrambleStrength"], stats, mod) - elif mod.item.groupID == modGroupData["Target Painter"]["id"]: + elif mod.item.group.name == "Target Painter": stats["type"] = "Target Painter" EfsPort.attrDirectMap(["signatureRadiusBonus"], stats, mod) - elif mod.item.groupID == modGroupData["Sensor Dampener"]["id"]: + elif mod.item.group.name == "Sensor Dampener": stats["type"] = "Sensor Dampener" EfsPort.attrDirectMap(["maxTargetRangeBonus", "scanResolutionBonus"], stats, mod) - elif mod.item.groupID == modGroupData["ECM"]["id"]: + elif mod.item.group.name == "ECM": stats["type"] = "ECM" EfsPort.attrDirectMap([ "scanGravimetricStrengthBonus", "scanMagnetometricStrengthBonus", "scanRadarStrengthBonus", "scanLadarStrengthBonus", ], stats, mod) - elif mod.item.groupID == modGroupData["Burst Jammer"]["id"]: + elif mod.item.group.name == "Burst Jammer": stats["type"] = "Burst Jammer" mod.itemModifiedAttributes["maxRange"] = mod.itemModifiedAttributes["ecmBurstRange"] EfsPort.attrDirectMap([ "scanGravimetricStrengthBonus", "scanMagnetometricStrengthBonus", "scanRadarStrengthBonus", "scanLadarStrengthBonus", ], stats, mod) - elif mod.item.groupID == modGroupData["Micro Jump Drive"]["id"]: + elif mod.item.group.name == "Micro Jump Drive": stats["type"] = "Micro Jump Drive" mod.itemModifiedAttributes["maxRange"] = 0 EfsPort.attrDirectMap(["moduleReactivationDelay"], stats, mod) + else: + pyfalog.error("Projected module {0} lacks efs export implementation".format(mod.item.name)) if mod.itemModifiedAttributes["maxRange"] is None: pyfalog.error("Projected module {0} has no maxRange".format(mod.item.name)) stats["optimal"] = mod.itemModifiedAttributes["maxRange"] or 0 @@ -489,6 +486,7 @@ class EfsPort(): mod.owner = fit turrets = list(filter(lambda mod: mod.itemModifiedAttributes["damageMultiplier"], turrets)) launchers = list(filter(lambda mod: sumDamage(mod.chargeModifiedAttributes), launchers)) + # Since the effect modules are fairly opaque a mock test fit is used to test the impact of traits. # standin class used to prevent . notation causing issues when used as an arg class standin(): From 582a3893d1004be342b18e7e85626b40bdf947a0 Mon Sep 17 00:00:00 2001 From: MaruMaruOO Date: Thu, 26 Jul 2018 11:48:34 -0400 Subject: [PATCH 26/32] Removed unneeded initalization from efsPort --- service/efsPort.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/service/efsPort.py b/service/efsPort.py index 189467cb1..068fec254 100755 --- a/service/efsPort.py +++ b/service/efsPort.py @@ -18,7 +18,6 @@ from eos.db import gamedata_session, getItemsByCategory, getCategory, getAttribu from eos.gamedata import Category, Group, Item, Traits, Attribute, Effect, ItemEffect from logbook import Logger pyfalog = Logger(__name__) -eos.db.saveddata_meta.create_all() class RigSize(Enum): @@ -555,17 +554,14 @@ class EfsPort(): return sizeNotFoundMsg @staticmethod - def exportEfs(fit, groupID): - includeShipTypeData = groupID > 0 - fitID = fit.ID + def exportEfs(fit, typeNotFitFlag): + sFit = Fit.getInstance() + includeShipTypeData = typeNotFitFlag > 0 if includeShipTypeData: fitName = fit.name else: fitName = fit.ship.name + ": " + fit.name pyfalog.info("Creating Eve Fleet Simulator data for: " + fit.name) - sFit = Fit.getInstance() - sFit.recalc(fit) - fit = eos.db.getFit(fitID) fitModAttr = fit.ship.itemModifiedAttributes propData = EfsPort.getPropData(fit, sFit) mwdPropSpeed = fit.maxSpeed @@ -583,7 +579,7 @@ class EfsPort(): effectiveLauncherSlots = round(launcherSlots * weaponBonusMultipliers["launcher"], 2) effectiveDroneBandwidth = round(droneBandwidth * weaponBonusMultipliers["droneBandwidth"], 2) # Assume a T2 siege module for dreads - if groupID == getGroup("Dreadnought").ID: + if fit.ship.item.groupID == getGroup("Dreadnought").ID: effectiveTurretSlots *= 9.4 effectiveLauncherSlots *= 15 hullResonance = { @@ -616,7 +612,7 @@ class EfsPort(): "powerOutput": fitModAttr["powerOutput"], "cpuOutput": fitModAttr["cpuOutput"], "rigSize": fitModAttr["rigSize"], "effectiveTurrets": effectiveTurretSlots, "effectiveLaunchers": effectiveLauncherSlots, "effectiveDroneBandwidth": effectiveDroneBandwidth, - "resonance": resonance, "typeID": fit.shipID, "groupID": groupID, "shipSize": shipSize, + "resonance": resonance, "typeID": fit.shipID, "groupID": fit.ship.item.groupID, "shipSize": shipSize, "droneControlRange": fitModAttr["droneControlRange"], "mass": fitModAttr["mass"], "moduleNames": moduleNames, "projections": projections, "unpropedSpeed": propData["unpropedSpeed"], "unpropedSig": propData["unpropedSig"], From 4fc630d44e0ad5345a817a287b4098b20e7b5099 Mon Sep 17 00:00:00 2001 From: MaruMaruOO Date: Thu, 26 Jul 2018 12:02:04 -0400 Subject: [PATCH 27/32] Minor efsPort linting --- service/efsPort.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/service/efsPort.py b/service/efsPort.py index 068fec254..9dd236e7a 100755 --- a/service/efsPort.py +++ b/service/efsPort.py @@ -11,7 +11,7 @@ from math import log from service.fit import Fit from service.market import Market from eos.enum import Enum -from eos.saveddata.module import Hardpoint, Slot, Module +from eos.saveddata.module import Hardpoint, Slot, Module, State from eos.saveddata.drone import Drone from eos.effectHandlerHelpers import HandledList from eos.db import gamedata_session, getItemsByCategory, getCategory, getAttributeInfo, getGroup @@ -82,13 +82,12 @@ class EfsPort(): @staticmethod def getPropData(fit, sFit): fitID = fit.ID - propGroupId = getGroup("Propulsion Module").ID - propMods = filter(lambda mod: mod.item and mod.item.groupID == propGroupId, fit.modules) + propMods = filter(lambda mod: mod.item and mod.item.group.name == "Propulsion Module", fit.modules) activePropWBloomFilter = lambda mod: mod.state > 0 and "signatureRadiusBonus" in mod.item.attributes propWithBloom = next(filter(activePropWBloomFilter, propMods), None) if propWithBloom is not None: oldPropState = propWithBloom.state - propWithBloom.state = 0 + propWithBloom.state = State.ONLINE sFit.recalc(fit) fit = eos.db.getFit(fitID) sp = fit.maxSpeed From bef8fbbc3aa67e7963bd52a5e3fb0b346e912839 Mon Sep 17 00:00:00 2001 From: MaruMaruOO Date: Thu, 26 Jul 2018 14:24:55 -0400 Subject: [PATCH 28/32] Used getModifiedItemAttr in efsPort to replace itemModifiedAttributes for consistancy --- service/efsPort.py | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/service/efsPort.py b/service/efsPort.py index 9dd236e7a..11c68bb4a 100755 --- a/service/efsPort.py +++ b/service/efsPort.py @@ -34,18 +34,18 @@ class EfsPort(): @staticmethod def attrDirectMap(values, target, source): for val in values: - target[val] = source.itemModifiedAttributes[val] + target[val] = source.getModifiedItemAttr(val) @staticmethod def getT2MwdSpeed(fit, sFit): fitID = fit.ID propID = None - shipHasMedSlots = fit.ship.itemModifiedAttributes["medSlots"] > 0 - shipPower = fit.ship.itemModifiedAttributes["powerOutput"] + shipHasMedSlots = fit.ship.getModifiedItemAttr("medSlots") > 0 + shipPower = fit.ship.getModifiedItemAttr("powerOutput") # Monitors have a 99% reduction to prop mod power requirements if fit.ship.name == "Monitor": shipPower *= 100 - rigSize = fit.ship.itemModifiedAttributes["rigSize"] + rigSize = fit.ship.getModifiedItemAttr("rigSize") if not shipHasMedSlots: return None @@ -91,7 +91,7 @@ class EfsPort(): sFit.recalc(fit) fit = eos.db.getFit(fitID) sp = fit.maxSpeed - sig = fit.ship.itemModifiedAttributes["signatureRadius"] + sig = fit.ship.getModifiedItemAttr("signatureRadius") propWithBloom.state = oldPropState sFit.recalc(fit) fit = eos.db.getFit(fitID) @@ -99,7 +99,7 @@ class EfsPort(): return { "usingMWD": False, "unpropedSpeed": fit.maxSpeed, - "unpropedSig": fit.ship.itemModifiedAttributes["signatureRadius"] + "unpropedSig": fit.ship.getModifiedItemAttr("signatureRadius") } @staticmethod @@ -117,15 +117,17 @@ class EfsPort(): projectedMods = list(filter(lambda mod: mod.item and mod.item.group.name in modGroupNames, fit.modules)) projections = [] for mod in projectedMods: + maxRangeDefault = 0 + falloffDefault = 0 stats = {} if mod.item.group.name in ["Stasis Web", "Stasis Grappler"]: stats["type"] = "Stasis Web" - stats["optimal"] = mod.itemModifiedAttributes["maxRange"] + stats["optimal"] = mod.getModifiedItemAttr("maxRange") EfsPort.attrDirectMap(["duration", "speedFactor"], stats, mod) elif mod.item.group.name == "Weapon Disruptor": stats["type"] = "Weapon Disruptor" - stats["optimal"] = mod.itemModifiedAttributes["maxRange"] - stats["falloff"] = mod.itemModifiedAttributes["falloffEffectiveness"] + stats["optimal"] = mod.getModifiedItemAttr("maxRange") + stats["falloff"] = mod.getModifiedItemAttr("falloffEffectiveness") EfsPort.attrDirectMap([ "trackingSpeedBonus", "maxRangeBonus", "falloffBonus", "aoeCloudSizeBonus", "aoeVelocityBonus", "missileVelocityBonus", "explosionDelayBonus" @@ -163,21 +165,20 @@ class EfsPort(): ], stats, mod) elif mod.item.group.name == "Burst Jammer": stats["type"] = "Burst Jammer" - mod.itemModifiedAttributes["maxRange"] = mod.itemModifiedAttributes["ecmBurstRange"] + maxRangeDefault = mod.getModifiedItemAttr("ecmBurstRange") EfsPort.attrDirectMap([ "scanGravimetricStrengthBonus", "scanMagnetometricStrengthBonus", "scanRadarStrengthBonus", "scanLadarStrengthBonus", ], stats, mod) elif mod.item.group.name == "Micro Jump Drive": stats["type"] = "Micro Jump Drive" - mod.itemModifiedAttributes["maxRange"] = 0 EfsPort.attrDirectMap(["moduleReactivationDelay"], stats, mod) else: pyfalog.error("Projected module {0} lacks efs export implementation".format(mod.item.name)) - if mod.itemModifiedAttributes["maxRange"] is None: + if mod.getModifiedItemAttr("maxRange", None) is None: pyfalog.error("Projected module {0} has no maxRange".format(mod.item.name)) - stats["optimal"] = mod.itemModifiedAttributes["maxRange"] or 0 - stats["falloff"] = mod.itemModifiedAttributes["falloffEffectiveness"] or 0 + stats["optimal"] = mod.getModifiedItemAttr("maxRange", maxRangeDefault) + stats["falloff"] = mod.getModifiedItemAttr("falloffEffectiveness", falloffDefault) EfsPort.attrDirectMap(["duration", "capacitorNeed"], stats, mod) projections.append(stats) return projections @@ -304,7 +305,7 @@ class EfsPort(): explosionVelocity = 0 aoeFieldRange = 0 if stats.hardpoint == Hardpoint.TURRET: - tracking = stats.itemModifiedAttributes["trackingSpeed"] + tracking = stats.getModifiedItemAttr("trackingSpeed") typeing = "Turret" name = stats.item.name + ", " + stats.charge.name # Bombs share most attributes with missiles despite not needing the hardpoint @@ -317,7 +318,7 @@ class EfsPort(): typeing = "Missile" name = stats.item.name + ", " + stats.charge.name elif stats.hardpoint == Hardpoint.NONE: - aoeFieldRange = stats.itemModifiedAttributes["empFieldRange"] + aoeFieldRange = stats.getModifiedItemAttr("empFieldRange") # This also covers non-bomb weapons with dps values and no hardpoints, most notably targeted doomsdays. typeing = "SmartBomb" name = stats.item.name @@ -428,7 +429,7 @@ class EfsPort(): additionalLaunchers = [] for mod in modSet: clist = list(gamedata_session.query(Item).options(). - filter(Item.groupID == mod.itemModifiedAttributes["chargeGroup1"]).all()) + filter(Item.groupID == mod.getModifiedItemAttr("chargeGroup1")).all()) mods = [mod] charges = [clist[0]] if setType == "launcher": @@ -463,11 +464,11 @@ class EfsPort(): def getCurrentMultipliers(tf): fitMultipliers = {} - getDroneMulti = lambda d: sumDamage(d.itemModifiedAttributes) * d.itemModifiedAttributes["damageMultiplier"] + getDroneMulti = lambda d: sumDamage(d.itemModifiedAttributes) * d.getModifiedItemAttr("damageMultiplier") fitMultipliers["drones"] = list(map(getDroneMulti, tf.drones)) getFitTurrets = lambda f: filter(lambda mod: mod.hardpoint == Hardpoint.TURRET, f.modules) - getTurretMulti = lambda mod: mod.itemModifiedAttributes["damageMultiplier"] / mod.cycleTime + getTurretMulti = lambda mod: mod.getModifiedItemAttr("damageMultiplier") / mod.cycleTime fitMultipliers["turrets"] = list(map(getTurretMulti, getFitTurrets(tf))) getFitLaunchers = lambda f: filter(lambda mod: mod.hardpoint == Hardpoint.MISSILE, f.modules) @@ -482,7 +483,7 @@ class EfsPort(): for weaponTypeSet in [turrets, launchers, drones]: for mod in weaponTypeSet: mod.owner = fit - turrets = list(filter(lambda mod: mod.itemModifiedAttributes["damageMultiplier"], turrets)) + turrets = list(filter(lambda mod: mod.getModifiedItemAttr("damageMultiplier"), turrets)) launchers = list(filter(lambda mod: sumDamage(mod.chargeModifiedAttributes), launchers)) # Since the effect modules are fairly opaque a mock test fit is used to test the impact of traits. From b7900b0b25d2be25268980470f865a0e419d0c19 Mon Sep 17 00:00:00 2001 From: MaruMaruOO Date: Thu, 26 Jul 2018 17:27:03 -0400 Subject: [PATCH 29/32] Change more efsPort syntax to use getters --- service/efsPort.py | 76 +++++++++++++++++++++++----------------------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/service/efsPort.py b/service/efsPort.py index 11c68bb4a..72c8b1310 100755 --- a/service/efsPort.py +++ b/service/efsPort.py @@ -272,14 +272,14 @@ class EfsPort(): abilityName = "RegularAttack" if baseRef == "fighterAbilityAttackMissile" else "MissileAttack" rangeSuffix = "RangeOptimal" if baseRef == "fighterAbilityAttackMissile" else "Range" reductionRef = baseRef if baseRef == "fighterAbilityAttackMissile" else baseRefDam - damageReductionFactor = log(fighterAttr[reductionRef + "ReductionFactor"]) / log(fighterAttr[reductionRef + "ReductionSensitivity"]) + damageReductionFactor = log(fighterAttr(reductionRef + "ReductionFactor")) / log(fighterAttr(reductionRef + "ReductionSensitivity")) damTypes = ["EM", "Therm", "Exp", "Kin"] - abBaseDamage = sum(map(lambda damType: fighterAttr[baseRefDam + damType], damTypes)) - abDamage = abBaseDamage * fighterAttr[baseRefDam + "Multiplier"] + abBaseDamage = sum(map(lambda damType: fighterAttr(baseRefDam + damType), damTypes)) + abDamage = abBaseDamage * fighterAttr(baseRefDam + "Multiplier") return { - "name": abilityName, "volley": abDamage * fighter.amountActive, "explosionRadius": fighterAttr[baseRef + "ExplosionRadius"], - "explosionVelocity": fighterAttr[baseRef + "ExplosionVelocity"], "optimal": fighterAttr[baseRef + rangeSuffix], - "damageReductionFactor": damageReductionFactor, "rof": fighterAttr[baseRef + "Duration"], + "name": abilityName, "volley": abDamage * fighter.amountActive, "explosionRadius": fighterAttr(baseRef + "ExplosionRadius"), + "explosionVelocity": fighterAttr(baseRef + "ExplosionVelocity"), "optimal": fighterAttr(baseRef + rangeSuffix), + "damageReductionFactor": damageReductionFactor, "rof": fighterAttr(baseRef + "Duration"), } @staticmethod @@ -310,11 +310,11 @@ class EfsPort(): name = stats.item.name + ", " + stats.charge.name # Bombs share most attributes with missiles despite not needing the hardpoint elif stats.hardpoint == Hardpoint.MISSILE or "Bomb Launcher" in stats.item.name: - maxVelocity = stats.chargeModifiedAttributes["maxVelocity"] - explosionDelay = stats.chargeModifiedAttributes["explosionDelay"] - damageReductionFactor = stats.chargeModifiedAttributes["aoeDamageReductionFactor"] - explosionRadius = stats.chargeModifiedAttributes["aoeCloudSize"] - explosionVelocity = stats.chargeModifiedAttributes["aoeVelocity"] + maxVelocity = stats.getModifiedChargeAttr("maxVelocity") + explosionDelay = stats.getModifiedChargeAttr("explosionDelay") + damageReductionFactor = stats.getModifiedChargeAttr("aoeDamageReductionFactor") + explosionRadius = stats.getModifiedChargeAttr("aoeCloudSize") + explosionVelocity = stats.getModifiedChargeAttr("aoeVelocity") typeing = "Missile" name = stats.item.name + ", " + stats.charge.name elif stats.hardpoint == Hardpoint.NONE: @@ -335,33 +335,33 @@ class EfsPort(): weaponSystems.append(statDict) for drone in fit.drones: if drone.dps[0] > 0 and drone.amountActive > 0: - droneAttr = drone.itemModifiedAttributes + droneAttr = drone.getModifiedItemAttr # Drones are using the old tracking formula for trackingSpeed. This updates it to match turrets. - newTracking = droneAttr["trackingSpeed"] / (droneAttr["optimalSigRadius"] / 40000) + newTracking = droneAttr("trackingSpeed") / (droneAttr("optimalSigRadius") / 40000) statDict = { "dps": drone.dps[0], "cycleTime": drone.cycleTime, "type": "Drone", "optimal": drone.maxRange, "name": drone.item.name, "falloff": drone.falloff, - "maxSpeed": droneAttr["maxVelocity"], "tracking": newTracking, + "maxSpeed": droneAttr("maxVelocity"), "tracking": newTracking, "volley": drone.dps[1] } weaponSystems.append(statDict) for fighter in fit.fighters: if fighter.dps[0] > 0 and fighter.amountActive > 0: - fighterAttr = fighter.itemModifiedAttributes + fighterAttr = fighter.getModifiedItemAttr abilities = [] - if "fighterAbilityAttackMissileDamageEM" in fighterAttr: + if "fighterAbilityAttackMissileDamageEM" in fighter.item.attributes.keys(): baseRef = "fighterAbilityAttackMissile" ability = EfsPort.getFighterAbilityData(fighterAttr, fighter, baseRef) abilities.append(ability) - if "fighterAbilityMissilesDamageEM" in fighterAttr: + if "fighterAbilityMissilesDamageEM" in fighter.item.attributes.keys(): baseRef = "fighterAbilityMissiles" ability = EfsPort.getFighterAbilityData(fighterAttr, fighter, baseRef) abilities.append(ability) statDict = { "dps": fighter.dps[0], "type": "Fighter", "name": fighter.item.name, - "maxSpeed": fighterAttr["maxVelocity"], "abilities": abilities, - "ehp": fighterAttr["shieldCapacity"] / 0.8875 * fighter.amountActive, - "volley": fighter.dps[1], "signatureRadius": fighterAttr["signatureRadius"] + "maxSpeed": fighterAttr("maxVelocity"), "abilities": abilities, + "ehp": fighterAttr("shieldCapacity") / 0.8875 * fighter.amountActive, + "volley": fighter.dps[1], "signatureRadius": fighterAttr("signatureRadius") } weaponSystems.append(statDict) return weaponSystems @@ -562,7 +562,7 @@ class EfsPort(): else: fitName = fit.ship.name + ": " + fit.name pyfalog.info("Creating Eve Fleet Simulator data for: " + fit.name) - fitModAttr = fit.ship.itemModifiedAttributes + fitModAttr = fit.ship.getModifiedItemAttr propData = EfsPort.getPropData(fit, sFit) mwdPropSpeed = fit.maxSpeed if includeShipTypeData: @@ -571,9 +571,9 @@ class EfsPort(): moduleNames = EfsPort.getModuleNames(fit) weaponSystems = EfsPort.getWeaponSystemData(fit) - turretSlots = fitModAttr["turretSlotsLeft"] if fitModAttr["turretSlotsLeft"] is not None else 0 - launcherSlots = fitModAttr["launcherSlotsLeft"] if fitModAttr["launcherSlotsLeft"] is not None else 0 - droneBandwidth = fitModAttr["droneBandwidth"] if fitModAttr["droneBandwidth"] is not None else 0 + turretSlots = fitModAttr("turretSlotsLeft") if fitModAttr("turretSlotsLeft") is not None else 0 + launcherSlots = fitModAttr("launcherSlotsLeft") if fitModAttr("launcherSlotsLeft") is not None else 0 + droneBandwidth = fitModAttr("droneBandwidth") if fitModAttr("droneBandwidth") is not None else 0 weaponBonusMultipliers = EfsPort.getWeaponBonusMultipliers(fit) effectiveTurretSlots = round(turretSlots * weaponBonusMultipliers["turret"], 2) effectiveLauncherSlots = round(launcherSlots * weaponBonusMultipliers["launcher"], 2) @@ -583,16 +583,16 @@ class EfsPort(): effectiveTurretSlots *= 9.4 effectiveLauncherSlots *= 15 hullResonance = { - "exp": fitModAttr["explosiveDamageResonance"], "kin": fitModAttr["kineticDamageResonance"], - "therm": fitModAttr["thermalDamageResonance"], "em": fitModAttr["emDamageResonance"] + "exp": fitModAttr("explosiveDamageResonance"), "kin": fitModAttr("kineticDamageResonance"), + "therm": fitModAttr("thermalDamageResonance"), "em": fitModAttr("emDamageResonance") } armorResonance = { - "exp": fitModAttr["armorExplosiveDamageResonance"], "kin": fitModAttr["armorKineticDamageResonance"], - "therm": fitModAttr["armorThermalDamageResonance"], "em": fitModAttr["armorEmDamageResonance"] + "exp": fitModAttr("armorExplosiveDamageResonance"), "kin": fitModAttr("armorKineticDamageResonance"), + "therm": fitModAttr("armorThermalDamageResonance"), "em": fitModAttr("armorEmDamageResonance") } shieldResonance = { - "exp": fitModAttr["shieldExplosiveDamageResonance"], "kin": fitModAttr["shieldKineticDamageResonance"], - "therm": fitModAttr["shieldThermalDamageResonance"], "em": fitModAttr["shieldEmDamageResonance"] + "exp": fitModAttr("shieldExplosiveDamageResonance"), "kin": fitModAttr("shieldKineticDamageResonance"), + "therm": fitModAttr("shieldThermalDamageResonance"), "em": fitModAttr("shieldEmDamageResonance") } resonance = {"hull": hullResonance, "armor": armorResonance, "shield": shieldResonance} shipSize = EfsPort.getShipSize(fit.ship.item.groupID) @@ -603,17 +603,17 @@ class EfsPort(): "droneVolley": fit.droneVolley, "hp": fit.hp, "maxTargets": fit.maxTargets, "maxSpeed": fit.maxSpeed, "weaponVolley": fit.weaponVolley, "totalVolley": fit.totalVolley, "maxTargetRange": fit.maxTargetRange, "scanStrength": fit.scanStrength, - "weaponDPS": fit.weaponDPS, "alignTime": fit.alignTime, "signatureRadius": fitModAttr["signatureRadius"], - "weapons": weaponSystems, "scanRes": fitModAttr["scanResolution"], + "weaponDPS": fit.weaponDPS, "alignTime": fit.alignTime, "signatureRadius": fitModAttr("signatureRadius"), + "weapons": weaponSystems, "scanRes": fitModAttr("scanResolution"), "capUsed": fit.capUsed, "capRecharge": fit.capRecharge, - "rigSlots": fitModAttr["rigSlots"], "lowSlots": fitModAttr["lowSlots"], - "midSlots": fitModAttr["medSlots"], "highSlots": fitModAttr["hiSlots"], - "turretSlots": fitModAttr["turretSlotsLeft"], "launcherSlots": fitModAttr["launcherSlotsLeft"], - "powerOutput": fitModAttr["powerOutput"], "cpuOutput": fitModAttr["cpuOutput"], - "rigSize": fitModAttr["rigSize"], "effectiveTurrets": effectiveTurretSlots, + "rigSlots": fitModAttr("rigSlots"), "lowSlots": fitModAttr("lowSlots"), + "midSlots": fitModAttr("medSlots"), "highSlots": fitModAttr("hiSlots"), + "turretSlots": fitModAttr("turretSlotsLeft"), "launcherSlots": fitModAttr("launcherSlotsLeft"), + "powerOutput": fitModAttr("powerOutput"), "cpuOutput": fitModAttr("cpuOutput"), + "rigSize": fitModAttr("rigSize"), "effectiveTurrets": effectiveTurretSlots, "effectiveLaunchers": effectiveLauncherSlots, "effectiveDroneBandwidth": effectiveDroneBandwidth, "resonance": resonance, "typeID": fit.shipID, "groupID": fit.ship.item.groupID, "shipSize": shipSize, - "droneControlRange": fitModAttr["droneControlRange"], "mass": fitModAttr["mass"], + "droneControlRange": fitModAttr("droneControlRange"), "mass": fitModAttr("mass"), "moduleNames": moduleNames, "projections": projections, "unpropedSpeed": propData["unpropedSpeed"], "unpropedSig": propData["unpropedSig"], "usingMWD": propData["usingMWD"], "mwdPropSpeed": mwdPropSpeed From c1405fa67527c824ec39635eaac5ce569faccdf2 Mon Sep 17 00:00:00 2001 From: MaruMaruOO Date: Thu, 26 Jul 2018 17:39:32 -0400 Subject: [PATCH 30/32] More getter swapping for efsPort --- service/efsPort.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/service/efsPort.py b/service/efsPort.py index 72c8b1310..8d7610ec0 100755 --- a/service/efsPort.py +++ b/service/efsPort.py @@ -458,13 +458,13 @@ class EfsPort(): def sumDamage(attr): totalDamage = 0 for damageType in ["emDamage", "thermalDamage", "kineticDamage", "explosiveDamage"]: - if attr[damageType] is not None: - totalDamage += attr[damageType] + if attr(damageType) is not None: + totalDamage += attr(damageType) return totalDamage def getCurrentMultipliers(tf): fitMultipliers = {} - getDroneMulti = lambda d: sumDamage(d.itemModifiedAttributes) * d.getModifiedItemAttr("damageMultiplier") + getDroneMulti = lambda d: sumDamage(d.getModifiedItemAttr) * d.getModifiedItemAttr("damageMultiplier") fitMultipliers["drones"] = list(map(getDroneMulti, tf.drones)) getFitTurrets = lambda f: filter(lambda mod: mod.hardpoint == Hardpoint.TURRET, f.modules) @@ -472,7 +472,7 @@ class EfsPort(): fitMultipliers["turrets"] = list(map(getTurretMulti, getFitTurrets(tf))) getFitLaunchers = lambda f: filter(lambda mod: mod.hardpoint == Hardpoint.MISSILE, f.modules) - getLauncherMulti = lambda mod: sumDamage(mod.chargeModifiedAttributes) / mod.cycleTime + getLauncherMulti = lambda mod: sumDamage(mod.getModifiedChargeAttr) / mod.cycleTime fitMultipliers["launchers"] = list(map(getLauncherMulti, getFitLaunchers(tf))) return fitMultipliers @@ -484,7 +484,7 @@ class EfsPort(): for mod in weaponTypeSet: mod.owner = fit turrets = list(filter(lambda mod: mod.getModifiedItemAttr("damageMultiplier"), turrets)) - launchers = list(filter(lambda mod: sumDamage(mod.chargeModifiedAttributes), launchers)) + launchers = list(filter(lambda mod: sumDamage(mod.getModifiedChargeAttr), launchers)) # Since the effect modules are fairly opaque a mock test fit is used to test the impact of traits. # standin class used to prevent . notation causing issues when used as an arg From 46e58ecba70ac8160a91e507392751d2e6285db1 Mon Sep 17 00:00:00 2001 From: MaruMaruOO Date: Fri, 27 Jul 2018 06:51:53 -0400 Subject: [PATCH 31/32] Add module typeIDs to data exported by efsPort --- service/efsPort.py | 102 +++++++++++++++++++++++++-------------------- 1 file changed, 57 insertions(+), 45 deletions(-) diff --git a/service/efsPort.py b/service/efsPort.py index 8d7610ec0..0e89d3ee7 100755 --- a/service/efsPort.py +++ b/service/efsPort.py @@ -183,88 +183,98 @@ class EfsPort(): projections.append(stats) return projections + # Note that unless padTypeIDs is True all 0s will be removed from modTypeIDs in the return. + # They always are added initally for the sake of brevity, as this option may not be retained long term. @staticmethod - def getModuleNames(fit): + def getModuleInfo(fit, padTypeIDs=False): moduleNames = [] - highSlotNames = [] - midSlotNames = [] - lowSlotNames = [] - rigSlotNames = [] - miscSlotNames = [] # subsystems ect + modTypeIDs = [] + moduleNameSets = {Slot.LOW: [], Slot.MED: [], Slot.HIGH: [], Slot.RIG: [], Slot.SUBSYSTEM: []} + modTypeIDSets = {Slot.LOW: [], Slot.MED: [], Slot.HIGH: [], Slot.RIG: [], Slot.SUBSYSTEM: []} for mod in fit.modules: - if mod.slot == 3: - modSlotNames = highSlotNames - elif mod.slot == 2: - modSlotNames = midSlotNames - elif mod.slot == 1: - modSlotNames = lowSlotNames - elif mod.slot == 4: - modSlotNames = rigSlotNames - elif mod.slot == 5: - modSlotNames = miscSlotNames try: if mod.item is not None: if mod.charge is not None: - modSlotNames.append(mod.item.name + ": " + mod.charge.name) + modTypeIDSets[mod.slot].append([mod.item.typeID, mod.charge.typeID]) + moduleNameSets[mod.slot].append(mod.item.name + ": " + mod.charge.name) else: - modSlotNames.append(mod.item.name) + modTypeIDSets[mod.slot].append(mod.item.typeID) + moduleNameSets[mod.slot].append(mod.item.name) else: - modSlotNames.append("Empty Slot") + modTypeIDSets[mod.slot].append(0) + moduleNameSets[mod.slot].append("Empty Slot") except: pyfalog.error("Could not find name for module {0}".format(vars(mod))) + for modInfo in [ - ["High Slots:"], highSlotNames, ["", "Med Slots:"], midSlotNames, - ["", "Low Slots:"], lowSlotNames, ["", "Rig Slots:"], rigSlotNames + ["High Slots:"], moduleNameSets[Slot.HIGH], ["", "Med Slots:"], moduleNameSets[Slot.MED], + ["", "Low Slots:"], moduleNameSets[Slot.LOW], ["", "Rig Slots:"], moduleNameSets[Slot.RIG] ]: moduleNames.extend(modInfo) + if len(moduleNameSets[Slot.SUBSYSTEM]) > 0: + moduleNames.extend(["", "Subsystems:"]) + moduleNames.extend(moduleNameSets[Slot.SUBSYSTEM]) + + for slotType in [Slot.HIGH, Slot.MED, Slot.LOW, Slot.RIG, Slot.SUBSYSTEM]: + if slotType is not Slot.SUBSYSTEM or len(modTypeIDSets[slotType]) > 0: + modTypeIDs.extend([0, 0] if slotType is not Slot.HIGH else [0]) + modTypeIDs.extend(modTypeIDSets[slotType]) - if len(miscSlotNames) > 0: - moduleNames.append("") - moduleNames.append("Subsystems:") - moduleNames.extend(miscSlotNames) droneNames = [] + droneIDs = [] fighterNames = [] + fighterIDs = [] for drone in fit.drones: if drone.amountActive > 0: + droneIDs.append(drone.item.typeID) droneNames.append("%s x%s" % (drone.item.name, drone.amount)) for fighter in fit.fighters: if fighter.amountActive > 0: + fighterIDs.append(fighter.item.typeID) fighterNames.append("%s x%s" % (fighter.item.name, fighter.amountActive)) if len(droneNames) > 0: - moduleNames.append("") - moduleNames.append("Drones:") + modTypeIDs.extend([0, 0]) + modTypeIDs.extend(droneIDs) + moduleNames.extend(["", "Drones:"]) moduleNames.extend(droneNames) if len(fighterNames) > 0: - moduleNames.append("") - moduleNames.append("Fighters:") + modTypeIDs.extend([0, 0]) + modTypeIDs.extend(fighterIDs) + moduleNames.extend(["", "Fighters:"]) moduleNames.extend(fighterNames) if len(fit.implants) > 0: - moduleNames.append("") - moduleNames.append("Implants:") + modTypeIDs.extend([0, 0]) + moduleNames.extend(["", "Implants:"]) for implant in fit.implants: + modTypeIDs.append(implant.item.typeID) moduleNames.append(implant.item.name) if len(fit.boosters) > 0: - moduleNames.append("") - moduleNames.append("Boosters:") + modTypeIDs.extend([0, 0]) + moduleNames.extend(["", "Boosters:"]) for booster in fit.boosters: + modTypeIDs.append(booster.item.typeID) moduleNames.append(booster.item.name) if len(fit.commandFits) > 0: - moduleNames.append("") - moduleNames.append("Command Fits:") + modTypeIDs.extend([0, 0]) + moduleNames.extend(["", "Command Fits:"]) for commandFit in fit.commandFits: + modTypeIDs.append(commandFit.ship.item.typeID) moduleNames.append(commandFit.name) if len(fit.projectedModules) > 0: - moduleNames.append("") - moduleNames.append("Projected Modules:") + modTypeIDs.extend([0, 0]) + moduleNames.extend(["", "Projected Modules:"]) for mod in fit.projectedModules: + modTypeIDs.append(mod.item.typeID) moduleNames.append(mod.item.name) if fit.character.name != "All 5": - moduleNames.append("") - moduleNames.append("Character:") + modTypeIDs.extend([0, 0, 0]) + moduleNames.extend(["", "Character:"]) moduleNames.append(fit.character.name) - - return moduleNames + if padTypeIDs is not True: + modTypeIDsUnpadded = [mod for mod in modTypeIDs if mod != 0] + modTypeIDs = modTypeIDsUnpadded + return {"moduleNames": moduleNames, "modTypeIDs": modTypeIDs} @staticmethod def getFighterAbilityData(fighterAttr, fighter, baseRef): @@ -568,7 +578,9 @@ class EfsPort(): if includeShipTypeData: mwdPropSpeed = EfsPort.getT2MwdSpeed(fit, sFit) projections = EfsPort.getOutgoingProjectionData(fit) - moduleNames = EfsPort.getModuleNames(fit) + modInfo = EfsPort.getModuleInfo(fit) + moduleNames = modInfo["moduleNames"] + modTypeIDs = modInfo["modTypeIDs"] weaponSystems = EfsPort.getWeaponSystemData(fit) turretSlots = fitModAttr("turretSlotsLeft") if fitModAttr("turretSlotsLeft") is not None else 0 @@ -579,7 +591,7 @@ class EfsPort(): effectiveLauncherSlots = round(launcherSlots * weaponBonusMultipliers["launcher"], 2) effectiveDroneBandwidth = round(droneBandwidth * weaponBonusMultipliers["droneBandwidth"], 2) # Assume a T2 siege module for dreads - if fit.ship.item.groupID == getGroup("Dreadnought").ID: + if fit.ship.item.group.name == "Dreadnought": effectiveTurretSlots *= 9.4 effectiveLauncherSlots *= 15 hullResonance = { @@ -614,9 +626,9 @@ class EfsPort(): "effectiveLaunchers": effectiveLauncherSlots, "effectiveDroneBandwidth": effectiveDroneBandwidth, "resonance": resonance, "typeID": fit.shipID, "groupID": fit.ship.item.groupID, "shipSize": shipSize, "droneControlRange": fitModAttr("droneControlRange"), "mass": fitModAttr("mass"), - "moduleNames": moduleNames, "projections": projections, "unpropedSpeed": propData["unpropedSpeed"], "unpropedSig": propData["unpropedSig"], - "usingMWD": propData["usingMWD"], "mwdPropSpeed": mwdPropSpeed + "usingMWD": propData["usingMWD"], "mwdPropSpeed": mwdPropSpeed, "projections": projections, + "modTypeIDs": modTypeIDs, "moduleNames": moduleNames } except TypeError: pyfalog.error("Error parsing fit:" + str(fit)) From d9827b445f022f56138a69bf6ef1ec4e2cd98cd4 Mon Sep 17 00:00:00 2001 From: MaruMaruOO Date: Fri, 27 Jul 2018 08:03:21 -0400 Subject: [PATCH 32/32] Add versioning data to EFS export --- service/efsPort.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/service/efsPort.py b/service/efsPort.py index 0e89d3ee7..d1dd394d9 100755 --- a/service/efsPort.py +++ b/service/efsPort.py @@ -8,6 +8,7 @@ import json import eos.db from math import log +from config import version as pyfaVersion from service.fit import Fit from service.market import Market from eos.enum import Enum @@ -30,6 +31,7 @@ class RigSize(Enum): class EfsPort(): wepTestSet = {} + version = 0.01 @staticmethod def attrDirectMap(values, target, source): @@ -608,7 +610,6 @@ class EfsPort(): } resonance = {"hull": hullResonance, "armor": armorResonance, "shield": shieldResonance} shipSize = EfsPort.getShipSize(fit.ship.item.groupID) - try: dataDict = { "name": fitName, "ehp": fit.ehp, "droneDPS": fit.droneDPS, @@ -628,7 +629,8 @@ class EfsPort(): "droneControlRange": fitModAttr("droneControlRange"), "mass": fitModAttr("mass"), "unpropedSpeed": propData["unpropedSpeed"], "unpropedSig": propData["unpropedSig"], "usingMWD": propData["usingMWD"], "mwdPropSpeed": mwdPropSpeed, "projections": projections, - "modTypeIDs": modTypeIDs, "moduleNames": moduleNames + "modTypeIDs": modTypeIDs, "moduleNames": moduleNames, + "pyfaVersion": pyfaVersion, "efsExportVersion": EfsPort.version } except TypeError: pyfalog.error("Error parsing fit:" + str(fit))