diff --git a/eos/effects/covertopscloakcpupercentbonus1.py b/eos/effects/covertopscloakcpupercentbonus1.py index cdd671913..534a50a38 100644 --- a/eos/effects/covertopscloakcpupercentbonus1.py +++ b/eos/effects/covertopscloakcpupercentbonus1.py @@ -5,5 +5,5 @@ type = "passive" runTime = "early" def handler(fit, ship, context): - fit.modules.filteredItemBoost(lambda mod: mod.item.group.name == "Cloaking Device", + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Cloaking"), "cpu", ship.getModifiedItemAttr("eliteBonusCoverOps1"), skill="Covert Ops") diff --git a/eos/modifiedAttributeDict.py b/eos/modifiedAttributeDict.py index a9a0e9fe5..203a1d99a 100644 --- a/eos/modifiedAttributeDict.py +++ b/eos/modifiedAttributeDict.py @@ -44,7 +44,8 @@ class ModifiedAttributeDict(collections.MutableMapping): class CalculationPlaceholder(): pass - def __init__(self, fit = None): + def __init__(self, fit=None, parent=None): + self.parent = parent self.fit = fit # Stores original values of the entity self.__original = None @@ -225,8 +226,15 @@ class ModifiedAttributeDict(collections.MutableMapping): with the fit and thus get the correct affector. Returns skill level to be used to modify modifier. See GH issue #101 """ - skill = self.fit.character.getSkill(skillName) - self.fit.register(skill) + fit = self.fit + if not fit: + # self.fit is usually set during fit calculations when the item is registered with the fit. However, + # under certain circumstances, an effect will not work as it will try to modify an item which has NOT + # yet been registered and thus has not had self.fit set. In this case, use the modules owner attribute + # to point to the correct fit. See GH Issue #434 + fit = self.parent.owner + skill = fit.character.getSkill(skillName) + fit.register(skill) return skill.level def getAfflictions(self, key): diff --git a/eos/saveddata/module.py b/eos/saveddata/module.py index 6c3b4273a..57501ca48 100644 --- a/eos/saveddata/module.py +++ b/eos/saveddata/module.py @@ -107,8 +107,8 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut): self.__reloadForce = None self.__chargeCycles = None self.__hardpoint = Hardpoint.NONE - self.__itemModifiedAttributes = ModifiedAttributeDict() - self.__chargeModifiedAttributes = ModifiedAttributeDict() + self.__itemModifiedAttributes = ModifiedAttributeDict(parent=self) + self.__chargeModifiedAttributes = ModifiedAttributeDict(parent=self) self.__slot = self.dummySlot # defaults to None if self.__item: diff --git a/gui/gangView.py b/gui/gangView.py index c06f8b362..2e6d7b1da 100644 --- a/gui/gangView.py +++ b/gui/gangView.py @@ -43,15 +43,10 @@ class GangView ( ScrolledPanel ): self.helpText = wx.StaticText( self, wx.ID_ANY, help, wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_CENTRE ) helpSizer.Add( self.helpText, 1, wx.ALL, 5 ) - self.FitDNDPopupMenu = wx.Menu() - self.options = ["Fleet", "Wing", "Squad"] self.fleet = {} for id, option in enumerate(self.options): - item = self.FitDNDPopupMenu.Append(-1, option) - # We bind it to the mainFrame because it may be called from either this class or from FitItem via shipBrowser - self.mainFrame.Bind(wx.EVT_MENU, self.OnPopupItemSelected, item) # set content for each commander self.fleet[id] = {} @@ -61,6 +56,8 @@ class GangView ( ScrolledPanel ): self.fleet[id]['chChar'] = wx.Choice( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, [] ) self.fleet[id]['fitSizer'] = wx.BoxSizer( wx.VERTICAL ) + self.FitDNDPopupMenu = self.buildBoostermenu() + contentFGSizer = wx.FlexGridSizer( 5, 3, 0, 0 ) contentFGSizer.AddGrowableCol( 1 ) contentFGSizer.SetFlexibleDirection( wx.BOTH ) @@ -130,6 +127,15 @@ class GangView ( ScrolledPanel ): self.RefreshBoosterFits() self.RefreshCharacterList() + def buildBoostermenu(self): + menu = wx.Menu() + + for id, option in enumerate(self.options): + item = menu.Append(-1, option) + # We bind it to the mainFrame because it may be called from either this class or from FitItem via shipBrowser + self.mainFrame.Bind(wx.EVT_MENU, self.OnPopupItemSelected, item) + return menu + def OnEnterWindow(self, event): obj = event.GetEventObject() obj.SetCursor(wx.StockCursor(wx.CURSOR_HAND)) @@ -371,7 +377,7 @@ class GangView ( ScrolledPanel ): def OnPopupItemSelected(self, event): ''' Fired when booster popup item is selected ''' # Get menu selection ID via self.options - menuItem = self.FitDNDPopupMenu.FindItemById(event.GetId()) + menuItem = event.EventObject.FindItemById(event.GetId()) type = self.options.index(menuItem.GetText()) if self.draggedFitID: diff --git a/gui/shipBrowser.py b/gui/shipBrowser.py index 2642c7d7a..db033b774 100644 --- a/gui/shipBrowser.py +++ b/gui/shipBrowser.py @@ -1536,13 +1536,13 @@ class FitItem(SFItem.SFBrowserItem): menu = wx.Menu() toggleItem = menu.Append(wx.ID_ANY, "Booster Fit", kind=wx.ITEM_CHECK) menu.Check(toggleItem.GetId(), self.fitBooster) - + menu.Break() self.Bind(wx.EVT_MENU, self.OnToggleBooster, toggleItem) if self.mainFrame.getActiveFit(): # If there is an active fit, get menu for setting individual boosters menu.AppendSeparator() - boosterMenu = self.mainFrame.additionsPane.gangPage.FitDNDPopupMenu + boosterMenu = self.mainFrame.additionsPane.gangPage.buildBoostermenu() menu.AppendSubMenu(boosterMenu, 'Set Booster') self.PopupMenu(menu, pos) diff --git a/pyfa.py b/pyfa.py index c0d361dbb..c4a39c9d6 100755 --- a/pyfa.py +++ b/pyfa.py @@ -22,12 +22,24 @@ import sys import re import config +from optparse import OptionParser, BadOptionError, AmbiguousOptionError -from optparse import OptionParser +class PassThroughOptionParser(OptionParser): + """ + An unknown option pass-through implementation of OptionParser. + + OSX passes -psn_0_* argument, which is something that pyfa does not handle. See GH issue #423 + """ + def _process_args(self, largs, rargs, values): + while rargs: + try: + OptionParser._process_args(self,largs,rargs,values) + except (BadOptionError,AmbiguousOptionError), e: + largs.append(e.opt_str) # Parse command line options usage = "usage: %prog [--root]" -parser = OptionParser(usage=usage) +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) diff --git a/setup-osx.py b/setup-osx.py new file mode 100644 index 000000000..b27a5df2b --- /dev/null +++ b/setup-osx.py @@ -0,0 +1,22 @@ +""" +This is a setup.py script generated by py2applet +Usage: + python setup.py py2app +""" + +from setuptools import setup +import requests.certs +APP = ['pyfa.py'] +DATA_FILES = ['eve.db', 'README.md', 'LICENSE', 'imgs', requests.certs.where()] +OPTIONS = { + 'argv_emulation': False, + 'iconfile': 'dist_assets/mac/pyfa.icns', + 'packages': ['eos', 'gui', 'service', 'utils'] +} + +setup( + app=APP, + data_files=DATA_FILES, + options={'py2app': OPTIONS}, + setup_requires=['py2app'], +)