From 7d658c3f3de33ec2532a0116073fbd1f32b4a13f Mon Sep 17 00:00:00 2001 From: cwozniak Date: Fri, 11 Mar 2016 16:15:08 -0500 Subject: [PATCH 1/4] Fixed ewar on damage graphs, and added a quick formula for module falloff and applied it to Target Painters and Heavy Grapplers. --- eos/graph/fitDps.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/eos/graph/fitDps.py b/eos/graph/fitDps.py index 957f6778b..89da9587b 100644 --- a/eos/graph/fitDps.py +++ b/eos/graph/fitDps.py @@ -40,11 +40,14 @@ class FitDpsGraph(Graph): for mod in fit.modules: if not mod.isEmpty and mod.state >= State.ACTIVE: - if "ewTargetPaint" in mod.item.effects: - ew['signatureRadius'].append(1+(mod.getModifiedItemAttr("signatureRadiusBonus") / 100)) - if "decreaseTargetSpeed" in mod.item.effects: + if "remoteTargetPaintFalloff" in mod.item.effects: + ew['signatureRadius'].append(1+(mod.getModifiedItemAttr("signatureRadiusBonus") / 100) * self.calculateModuleMultiplier(mod, data)) + if "remoteWebifierFalloff" in mod.item.effects: if distance <= mod.getModifiedItemAttr("maxRange"): ew['velocity'].append(1+(mod.getModifiedItemAttr("speedFactor") / 100)) + elif mod.getModifiedItemAttr("falloffEffectiveness") > 0: + #I am affected by falloff + ew['velocity'].append(1+(mod.getModifiedItemAttr("speedFactor") / 100) * self.calculateModuleMultiplier(mod, data)) ew['signatureRadius'].sort(key=abssort) ew['velocity'].sort(key=abssort) @@ -122,3 +125,13 @@ class FitDpsGraph(Graph): rangeEq = ((max(0, distance - turretOptimal)) / turretFalloff) ** 2 return 0.5 ** (trackingEq + rangeEq) + + def calculateModuleMultiplier(self, mod, data): + #Simplified formula, we make some assumptions about the module + #This is basically the calculateTurretChanceToHit without tracking values + distance = data["distance"] * 1000 + turretOptimal = mod.maxRange + turretFalloff = mod.falloff + rangeEq = ((max(0, distance - turretOptimal)) / turretFalloff) ** 2 + + return 0.5 ** (rangeEq) From 94dc3117bc0cca2ed6f18a08f6390a93b7b608d7 Mon Sep 17 00:00:00 2001 From: aacn500 Date: Fri, 15 Apr 2016 22:14:29 +0100 Subject: [PATCH 2/4] Fix importing T3 cruisers #556 --- service/port.py | 152 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 114 insertions(+), 38 deletions(-) diff --git a/service/port.py b/service/port.py index 8f922ac8d..cc6d11d17 100644 --- a/service/port.py +++ b/service/port.py @@ -103,7 +103,7 @@ class Port(object): item['type']['id'] = cargo.item.ID item['type']['name'] = '' fit['items'].append(item) - + for drone in ofit.drones: item = nested_dict() item['flag'] = INV_FLAG_DRONEBAY @@ -128,7 +128,7 @@ class Port(object): else: return "XML", cls.importXml(string, callback) - # If JSON-style start, parse os CREST/JSON + # If JSON-style start, parse as CREST/JSON if firstLine[0] == '{': return "JSON", (cls.importCrest(string),) @@ -162,6 +162,8 @@ class Port(object): items = fit['items'] items.sort(key=lambda k: k['flag']) + + moduleList = [] for module in items: try: item = sMkt.getItem(module['type']['id'], eager="group.category") @@ -179,16 +181,26 @@ class Port(object): # When item can't be added to any slot (unknown item or just charge), ignore it except ValueError: continue - if m.fits(f): - m.owner = f + # Add subsystems before modules to make sure T3 cruisers have subsystems installed + if item.category.name == "Subsystem": + if m.fits(f): + f.modules.append(m) + else: if m.isValidState(State.ACTIVE): m.state = State.ACTIVE - f.modules.append(m) + moduleList.append(m) except: continue + # Recalc to get slot numbers correct for T3 cruisers + service.Fit.getInstance().recalc(f) + + for module in moduleList: + if module.fits(f): + f.modules.append(module) + return f @staticmethod @@ -208,6 +220,7 @@ class Port(object): logger.exception("Couldn't import ship data %r", [ logtransform(s) for s in info ]) return None + moduleList = [] for itemInfo in info[1:]: if itemInfo: itemID, amount = itemInfo.split(";") @@ -225,13 +238,27 @@ class Port(object): for i in xrange(int(amount)): try: m = Module(item) + except: + continue + # Add subsystems before modules to make sure T3 cruisers have subsystems installed + if item.category.name == "Subsystem": if m.fits(f): f.modules.append(m) - except: - pass - m.owner = f - if m.isValidState(State.ACTIVE): - m.state = State.ACTIVE + else: + m.owner = f + if m.isValidState(State.ACTIVE): + m.state = State.ACTIVE + moduleList.append(m) + + # Recalc to get slot numbers correct for T3 cruisers + service.Fit.getInstance().recalc(f) + + for module in moduleList: + if module.fits(f): + module.owner = f + if module.isValidState(State.ACTIVE): + module.state = State.ACTIVE + f.modules.append(module) return f @@ -262,6 +289,7 @@ class Port(object): # maintain map of drones and their quantities droneMap = {} cargoMap = {} + moduleList = [] for i in range(1, len(lines)): ammoName = None extraAmount = None @@ -310,28 +338,49 @@ class Port(object): cargoMap[modName] += extraAmount elif item.category.name == "Implant": fit.implants.append(Implant(item)) + # elif item.category.name == "Subsystem": + # try: + # subsystem = Module(item) + # except ValueError: + # continue + # + # if subsystem.fits(fit): + # fit.modules.append(subsystem) else: try: m = Module(item) except ValueError: continue - if ammoName: - try: - ammo = sMkt.getItem(ammoName) - if m.isValidCharge(ammo) and m.charge is None: - m.charge = ammo - except: - pass + # Add subsystems before modules to make sure T3 cruisers have subsystems installed + if item.category.name == "Subsystem": + if m.fits(fit): + fit.modules.append(m) + else: + if ammoName: + try: + ammo = sMkt.getItem(ammoName) + if m.isValidCharge(ammo) and m.charge is None: + m.charge = ammo + except: + pass - if m.fits(fit): - m.owner = fit if setOffline is True and m.isValidState(State.OFFLINE): m.state = State.OFFLINE elif m.isValidState(State.ACTIVE): m.state = State.ACTIVE - fit.modules.append(m) + moduleList.append(m) + # Recalc to get slot numbers correct for T3 cruisers + service.Fit.getInstance().recalc(fit) + + for m in moduleList: + if m.fits(fit): + m.owner = fit + if not m.isValidState(m.state): + print "Error: Module", m, "cannot have state", m.state + + fit.modules.append(m) for droneName in droneMap: d = Drone(sMkt.getItem(droneName)) @@ -388,6 +437,7 @@ class Port(object): # Assign ship to fitting f.ship = Ship(sMkt.getItem(shipname)) + moduleList = [] for x in range(1, len(fitLines)): line = fitLines[x] if not line: @@ -476,22 +526,35 @@ class Port(object): except: continue - # Create module and activate it if it's activable + # Create module m = Module(modItem) - m.owner = f - if m.isValidState(State.ACTIVE): - m.state = State.ACTIVE - # Add charge to mod if applicable, on any errors just don't add anything - if chargeName: - try: - chargeItem = sMkt.getItem(chargeName, eager="group.category") - if chargeItem.category.name == "Charge": - m.charge = chargeItem - except: - pass - # Append module to fit - if m.fits(f): - f.modules.append(m) + + # Add subsystems before modules to make sure T3 cruisers have subsystems installed + if modItem.category.name == "Subsystem": + if m.fits(f): + f.modules.append(m) + else: + m.owner = f + # Activate mod if it is activable + if m.isValidState(State.ACTIVE): + m.state = State.ACTIVE + # Add charge to mod if applicable, on any errors just don't add anything + if chargeName: + try: + chargeItem = sMkt.getItem(chargeName, eager="group.category") + if chargeItem.category.name == "Charge": + m.charge = chargeItem + except: + pass + # Append module to fit + moduleList.append(m) + + # Recalc to get slot numbers correct for T3 cruisers + service.Fit.getInstance().recalc(f) + + for module in moduleList: + if module.fits(f): + f.modules.append(module) # Append fit to list of fits fits.append(f) @@ -523,6 +586,7 @@ class Port(object): except: continue hardwares = fitting.getElementsByTagName("hardware") + moduleList = [] for hardware in hardwares: try: moduleName = hardware.getAttribute("type") @@ -548,16 +612,28 @@ class Port(object): # When item can't be added to any slot (unknown item or just charge), ignore it except ValueError: continue - if m.fits(f): - m.owner = f + # Add subsystems before modules to make sure T3 cruisers have subsystems installed + if item.category.name == "Subsystem": + if m.fits(f): + m.owner = f + f.modules.append(m) + else: if m.isValidState(State.ACTIVE): m.state = State.ACTIVE - f.modules.append(m) + moduleList.append(m) except KeyboardInterrupt: continue + # Recalc to get slot numbers correct for T3 cruisers + service.Fit.getInstance().recalc(f) + + for module in moduleList: + if module.fits(f): + module.owner = f + f.modules.append(module) + fits.append(f) if callback: wx.CallAfter(callback, None) From a7e6d3e969f795b77c75b4be09437513e05fbe83 Mon Sep 17 00:00:00 2001 From: Dullson Date: Sun, 17 Apr 2016 17:32:51 +0300 Subject: [PATCH 3/4] Feature: Ability to select between different online fitting tools while using HTML Export. --- .../pyfaHTMLExportPreferences.py | 25 ++++++++++++++++++- gui/utils/exportHtml.py | 10 ++++++-- service/settings.py | 8 +++++- 3 files changed, 39 insertions(+), 4 deletions(-) diff --git a/gui/builtinPreferenceViews/pyfaHTMLExportPreferences.py b/gui/builtinPreferenceViews/pyfaHTMLExportPreferences.py index e028ef478..1701e670b 100644 --- a/gui/builtinPreferenceViews/pyfaHTMLExportPreferences.py +++ b/gui/builtinPreferenceViews/pyfaHTMLExportPreferences.py @@ -14,9 +14,10 @@ class PFHTMLExportPref ( PreferenceView): desc = "HTML Export (File > Export HTML) allows you to export your entire fitting "+\ "database into an HTML file at the specified location. This file can be "+\ "used in the in-game browser to easily open and import your fits, or used "+\ - "in a regular web browser to open them at NULL-SEC.com." + "in a regular web browser to open them at NULL-SEC.com or Osmium." desc2 = "Enabling automatic exporting will update the HTML file after any change "+\ "to a fit is made. Under certain circumstance, this may cause performance issues." + desc3 = "Preferred website to view fits while not using in-game browser can be selected below." def populatePanel( self, panel ): self.mainFrame = gui.mainFrame.MainFrame.getInstance() @@ -57,6 +58,24 @@ class PFHTMLExportPref ( PreferenceView): self.exportEnabled.Bind(wx.EVT_CHECKBOX, self.OnExportEnabledChange) mainSizer.Add( self.exportEnabled, 0, wx.ALL|wx.EXPAND, 5 ) + self.stDesc3 = wx.StaticText( panel, wx.ID_ANY, self.desc3, wx.DefaultPosition, wx.DefaultSize, 0 ) + self.stDesc3.Wrap(dlgWidth - 50) + mainSizer.Add( self.stDesc3, 0, wx.ALL, 5 ) + + websiteSizer = wx.BoxSizer( wx.HORIZONTAL ) + + self.stWebsite = wx.StaticText( panel, wx.ID_ANY, u"Website:", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.stWebsite.Wrap( -1 ) + websiteSizer.Add( self.stWebsite, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) + + self.chWebsiteChoices = [ "o.smium.org", "null-sec.com" ] + self.chWebsiteType = wx.Choice( panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, self.chWebsiteChoices, 0 ) + self.chWebsiteType.SetStringSelection( self.HTMLExportSettings.getWebsite() ) + websiteSizer.Add( self.chWebsiteType, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) + self.chWebsiteType.Bind(wx.EVT_CHOICE, self.OnCHWebsiteTypeSelect) + + mainSizer.Add( websiteSizer, 0, wx.EXPAND, 5 ) + panel.SetSizer( mainSizer ) panel.Layout() @@ -75,6 +94,10 @@ class PFHTMLExportPref ( PreferenceView): def OnExportEnabledChange(self, event): self.HTMLExportSettings.setEnabled(self.exportEnabled.GetValue()) + def OnCHWebsiteTypeSelect(self, event): + choice = self.chWebsiteType.GetStringSelection() + self.HTMLExportSettings.setWebsite(choice) + def getImage(self): return BitmapLoader.getBitmap("prefs_html", "gui") diff --git a/gui/utils/exportHtml.py b/gui/utils/exportHtml.py index d7e25c04a..8de0f35eb 100644 --- a/gui/utils/exportHtml.py +++ b/gui/utils/exportHtml.py @@ -45,6 +45,12 @@ class exportHtmlThread(threading.Thread): timestamp = time.localtime(time.time()) localDate = "%d/%02d/%02d %02d:%02d" % (timestamp[0], timestamp[1], timestamp[2], timestamp[3], timestamp[4]) + + website = settings.getWebsite() + if website == "o.smium.org": + dnaUrl = "https://o.smium.org/loadout/dna/" + elif website == "null-sec.com": + dnaUrl = "https://null-sec.com/hangar/?dna=" HTML = """ @@ -126,7 +132,7 @@ class exportHtmlThread(threading.Thread): if (typeof CCPEVE !== 'undefined') { // inside IGB $(this).attr('href', 'javascript:CCPEVE.showFitting("'+dna+'");'); } else { // outside IGB - $(this).attr('href', 'https://null-sec.com/hangar/?dna='+dna); } + $(this).attr('href', '%s'+dna); } }); }); @@ -139,7 +145,7 @@ class exportHtmlThread(threading.Thread):
Last updated: %s ()
-""" % (time.time(), localDate) +""" % (time.time(), dnaUrl, localDate) HTML += '
    \n' categoryList = list(sMkt.getShipRoot()) categoryList.sort(key=lambda ship: ship.name) diff --git a/service/settings.py b/service/settings.py index 5b4bd003b..60627e6b8 100644 --- a/service/settings.py +++ b/service/settings.py @@ -221,7 +221,7 @@ class HTMLExportSettings(): return cls._instance def __init__(self): - serviceHTMLExportDefaultSettings = {"enabled": False, "path": config.pyfaPath + os.sep + 'pyfaFits.html' } + serviceHTMLExportDefaultSettings = {"enabled": False, "path": config.pyfaPath + os.sep + 'pyfaFits.html', "website": "null-sec.com" } self.serviceHTMLExportSettings = SettingsProvider.getInstance().getSettings("pyfaServiceHTMLExportSettings", serviceHTMLExportDefaultSettings) def getEnabled(self): @@ -236,6 +236,12 @@ class HTMLExportSettings(): def setPath(self, path): self.serviceHTMLExportSettings["path"] = path + def getWebsite(self): + return self.serviceHTMLExportSettings["website"] + + def setWebsite(self, website): + self.serviceHTMLExportSettings["website"] = website + """ Settings used by update notification """ From e7dc9db75a8650d5b19ad63e52a8153f39d346ca Mon Sep 17 00:00:00 2001 From: Markus Maucher Date: Mon, 25 Apr 2016 12:10:00 +0200 Subject: [PATCH 4/4] fix separation of moving/non-moving drones --- eos/graph/fitDps.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eos/graph/fitDps.py b/eos/graph/fitDps.py index 957f6778b..d914801e4 100644 --- a/eos/graph/fitDps.py +++ b/eos/graph/fitDps.py @@ -71,7 +71,7 @@ class FitDpsGraph(Graph): if distance <= fit.extraAttributes["droneControlRange"]: for drone in fit.drones: - multiplier = 1 if drone.getModifiedItemAttr("maxVelocity") > 0 else self.calculateTurretMultiplier(drone, data) + multiplier = 1 if drone.getModifiedItemAttr("maxVelocity") > 1 else self.calculateTurretMultiplier(drone, data) dps, _ = drone.damageStats(fit.targetResists) total += dps * multiplier return total