diff --git a/eos/db/saveddata/booster.py b/eos/db/saveddata/booster.py index 3a6334985..9b8272540 100644 --- a/eos/db/saveddata/booster.py +++ b/eos/db/saveddata/booster.py @@ -31,6 +31,7 @@ boosters_table = Table("boosters", saveddata_meta, Column("active", Boolean), ) +# Legacy booster side effect code, should disable but a mapper relies on it. activeSideEffects_table = Table("boostersActiveSideEffects", saveddata_meta, Column("boosterID", ForeignKey("boosters.ID"), primary_key=True), Column("effectID", Integer, primary_key=True)) diff --git a/eos/effects/boosterarmorhppenalty.py b/eos/effects/boosterarmorhppenalty.py index 4be051731..eac33eaf4 100644 --- a/eos/effects/boosterarmorhppenalty.py +++ b/eos/effects/boosterarmorhppenalty.py @@ -3,6 +3,7 @@ # Used by: # Implants from group: Booster (12 of 47) type = "boosterSideEffect" +activeByDefault = False def handler(fit, booster, context): diff --git a/eos/effects/boosterarmorrepairamountpenalty.py b/eos/effects/boosterarmorrepairamountpenalty.py index fc7efa1ee..ac06a9c22 100644 --- a/eos/effects/boosterarmorrepairamountpenalty.py +++ b/eos/effects/boosterarmorrepairamountpenalty.py @@ -5,6 +5,7 @@ # Implants named like: Mindflood Booster (3 of 4) # Implants named like: Sooth Sayer Booster (3 of 4) type = "boosterSideEffect" +activeByDefault = False def handler(fit, booster, context): diff --git a/eos/effects/boostercapacitorcapacitypenalty.py b/eos/effects/boostercapacitorcapacitypenalty.py index a14324482..3a8351ac4 100644 --- a/eos/effects/boostercapacitorcapacitypenalty.py +++ b/eos/effects/boostercapacitorcapacitypenalty.py @@ -4,6 +4,7 @@ # Implants named like: Blue Pill Booster (3 of 5) # Implants named like: Exile Booster (3 of 4) type = "boosterSideEffect" +activeByDefault = False def handler(fit, booster, context): diff --git a/eos/effects/boostermaxvelocitypenalty.py b/eos/effects/boostermaxvelocitypenalty.py index d67e2a352..7588be3f7 100644 --- a/eos/effects/boostermaxvelocitypenalty.py +++ b/eos/effects/boostermaxvelocitypenalty.py @@ -3,6 +3,7 @@ # Used by: # Implants from group: Booster (12 of 47) type = "boosterSideEffect" +activeByDefault = False def handler(fit, booster, context): diff --git a/eos/effects/boostermissileexplosioncloudpenaltyfixed.py b/eos/effects/boostermissileexplosioncloudpenaltyfixed.py index 5c3758ccf..778e4b28c 100644 --- a/eos/effects/boostermissileexplosioncloudpenaltyfixed.py +++ b/eos/effects/boostermissileexplosioncloudpenaltyfixed.py @@ -4,6 +4,7 @@ # Implants named like: Exile Booster (3 of 4) # Implants named like: Mindflood Booster (3 of 4) type = "boosterSideEffect" +activeByDefault = False def handler(fit, booster, context): diff --git a/eos/effects/boostermissileexplosionvelocitypenalty.py b/eos/effects/boostermissileexplosionvelocitypenalty.py index 62a5d9d0a..e81a9fc96 100644 --- a/eos/effects/boostermissileexplosionvelocitypenalty.py +++ b/eos/effects/boostermissileexplosionvelocitypenalty.py @@ -3,6 +3,7 @@ # Used by: # Implants named like: Blue Pill Booster (3 of 5) type = "boosterSideEffect" +activeByDefault = False def handler(fit, booster, context): diff --git a/eos/effects/boostermissilevelocitypenalty.py b/eos/effects/boostermissilevelocitypenalty.py index 0fbb3ec22..a4f2d1205 100644 --- a/eos/effects/boostermissilevelocitypenalty.py +++ b/eos/effects/boostermissilevelocitypenalty.py @@ -4,6 +4,7 @@ # Implants named like: Crash Booster (3 of 4) # Implants named like: X Instinct Booster (3 of 4) type = "boosterSideEffect" +activeByDefault = False def handler(fit, booster, context): diff --git a/eos/effects/boostershieldcapacitypenalty.py b/eos/effects/boostershieldcapacitypenalty.py index 48d2b2616..b7d5f0554 100644 --- a/eos/effects/boostershieldcapacitypenalty.py +++ b/eos/effects/boostershieldcapacitypenalty.py @@ -3,6 +3,7 @@ # Used by: # Implants from group: Booster (12 of 47) type = "boosterSideEffect" +activeByDefault = False def handler(fit, booster, context): diff --git a/eos/effects/boosterturretfalloffpenalty.py b/eos/effects/boosterturretfalloffpenalty.py index 44576795b..84f2e2145 100644 --- a/eos/effects/boosterturretfalloffpenalty.py +++ b/eos/effects/boosterturretfalloffpenalty.py @@ -4,6 +4,7 @@ # Implants named like: Drop Booster (3 of 4) # Implants named like: X Instinct Booster (3 of 4) type = "boosterSideEffect" +activeByDefault = False def handler(fit, booster, context): diff --git a/eos/effects/boosterturretoptimalrangepenalty.py b/eos/effects/boosterturretoptimalrangepenalty.py index 216f2d44f..d70275c29 100644 --- a/eos/effects/boosterturretoptimalrangepenalty.py +++ b/eos/effects/boosterturretoptimalrangepenalty.py @@ -5,6 +5,7 @@ # Implants named like: Mindflood Booster (3 of 4) # Implants named like: Sooth Sayer Booster (3 of 4) type = "boosterSideEffect" +activeByDefault = False def handler(fit, booster, context): diff --git a/eos/effects/boosterturrettrackingpenalty.py b/eos/effects/boosterturrettrackingpenalty.py index 71f0627ff..6f268fdc4 100644 --- a/eos/effects/boosterturrettrackingpenalty.py +++ b/eos/effects/boosterturrettrackingpenalty.py @@ -4,6 +4,7 @@ # Implants named like: Exile Booster (3 of 4) # Implants named like: Frentix Booster (3 of 4) type = "boosterSideEffect" +activeByDefault = False def handler(fit, booster, context): diff --git a/eos/gamedata.py b/eos/gamedata.py index febc59ac8..c4b58b235 100644 --- a/eos/gamedata.py +++ b/eos/gamedata.py @@ -83,6 +83,40 @@ class Effect(EqBase): return self.__runTime + @property + def activeByDefault(self): + """ + The state that this effect should be be in. + This property is also automaticly fetched from effects/.py if the file exists. + the possible values are: + None, True, False + + If this is not set: + We simply assume that missing/none = True, and set it accordingly + (much as we set runTime to Normalif not otherwise set). + Nearly all effect files will fall under this category. + + If this is set to True: + We would enable it anyway, but hey, it's double enabled. + No effect files are currently configured this way (and probably will never be). + + If this is set to False: + Basically we simply skip adding the effect to the effect handler when the effect is called, + much as if the run time didn't match or other criteria failed. + """ + if not self.__generated: + self.__generateHandler() + + return self.__activeByDefault + + @activeByDefault.setter + def activeByDefault(self, value): + """ + Just assign the input values to the activeByDefault attribute. + You *could* do something more interesting here if you wanted. + """ + self.__activeByDefault = value + @property def type(self): """ @@ -133,6 +167,11 @@ class Effect(EqBase): except AttributeError: self.__runTime = "normal" + try: + self.__activeByDefault = getattr(effectModule, "activeByDefault") + except AttributeError: + self.__activeByDefault = True + try: t = getattr(effectModule, "type") except AttributeError: @@ -143,6 +182,7 @@ class Effect(EqBase): except (ImportError, AttributeError) as e: self.__handler = effectDummy self.__runTime = "normal" + self.__activeByDefault = True self.__type = None except Exception as e: traceback.print_exc(e) diff --git a/eos/saveddata/booster.py b/eos/saveddata/booster.py index 0a46d662c..3be3845d0 100644 --- a/eos/saveddata/booster.py +++ b/eos/saveddata/booster.py @@ -64,13 +64,18 @@ class Booster(HandledItem, ItemAttrShortcut): self.__itemModifiedAttributes.overrides = self.__item.overrides self.__slot = self.__calculateSlot(self.__item) + # Legacy booster side effect code, disabling as not currently implemented + ''' for effect in self.__item.effects.itervalues(): if effect.isType("boosterSideEffect"): s = SideEffect(self) s.effect = effect s.active = effect.ID in self.__activeSideEffectIDs self.__sideEffects.append(s) + ''' + # Legacy booster side effect code, disabling as not currently implemented + ''' def iterSideEffects(self): return self.__sideEffects.__iter__() @@ -80,6 +85,7 @@ class Booster(HandledItem, ItemAttrShortcut): return sideEffect raise KeyError("SideEffect with %s as name not found" % name) + ''' @property def itemModifiedAttributes(self): @@ -112,12 +118,17 @@ class Booster(HandledItem, ItemAttrShortcut): if not self.active: return for effect in self.item.effects.itervalues(): - if effect.runTime == runTime and effect.isType("passive"): + if effect.runTime == runTime and \ + (effect.isType("passive") or effect.isType("boosterSideEffect")) and \ + effect.activeByDefault: effect.handler(fit, self, ("booster",)) + # Legacy booster code, not fully implemented + ''' for sideEffect in self.iterSideEffects(): if sideEffect.active and sideEffect.effect.runTime == runTime: sideEffect.effect.handler(fit, self, ("boosterSideEffect",)) + ''' @validates("ID", "itemID", "ammoID", "active") def validator(self, key, val): @@ -135,46 +146,52 @@ class Booster(HandledItem, ItemAttrShortcut): def __deepcopy__(self, memo): copy = Booster(self.item) copy.active = self.active + + # Legacy booster side effect code, disabling as not currently implemented + ''' origSideEffects = list(self.iterSideEffects()) copySideEffects = list(copy.iterSideEffects()) i = 0 while i < len(origSideEffects): copySideEffects[i].active = origSideEffects[i].active i += 1 + ''' return copy +# Legacy booster side effect code, disabling as not currently implemented +''' + class SideEffect(object): + def __init__(self, owner): + self.__owner = owner + self.__active = False + self.__effect = None -class SideEffect(object): - def __init__(self, owner): - self.__owner = owner - self.__active = False - self.__effect = None + @property + def active(self): + return self.__active - @property - def active(self): - return self.__active + @active.setter + def active(self, active): + if not isinstance(active, bool): + raise TypeError("Expecting a bool, not a " + type(active)) - @active.setter - def active(self, active): - if not isinstance(active, bool): - raise TypeError("Expecting a bool, not a " + type(active)) + if active != self.__active: + if active: + self.__owner._Booster__activeSideEffectIDs.append(self.effect.ID) + else: + self.__owner._Booster__activeSideEffectIDs.remove(self.effect.ID) - if active != self.__active: - if active: - self.__owner._Booster__activeSideEffectIDs.append(self.effect.ID) - else: - self.__owner._Booster__activeSideEffectIDs.remove(self.effect.ID) + self.__active = active - self.__active = active + @property + def effect(self): + return self.__effect - @property - def effect(self): - return self.__effect + @effect.setter + def effect(self, effect): + if not hasattr(effect, "handler"): + raise TypeError("Need an effect with a handler") - @effect.setter - def effect(self, effect): - if not hasattr(effect, "handler"): - raise TypeError("Need an effect with a handler") - - self.__effect = effect + self.__effect = effect +''' \ No newline at end of file diff --git a/eos/saveddata/character.py b/eos/saveddata/character.py index 3cf3e70eb..9657c7d04 100644 --- a/eos/saveddata/character.py +++ b/eos/saveddata/character.py @@ -335,8 +335,10 @@ class Skill(HandledItem): return for effect in item.effects.itervalues(): - if effect.runTime == runTime and effect.isType("passive") and \ - (not fit.isStructure or effect.isType("structure")): + if effect.runTime == runTime and \ + effect.isType("passive") and \ + (not fit.isStructure or effect.isType("structure")) and \ + effect.activeByDefault: try: effect.handler(fit, self, ("skill",)) except AttributeError: diff --git a/eos/saveddata/drone.py b/eos/saveddata/drone.py index f847c1764..d0e8511f5 100644 --- a/eos/saveddata/drone.py +++ b/eos/saveddata/drone.py @@ -232,6 +232,7 @@ class Drone(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut): for effect in self.item.effects.itervalues(): if effect.runTime == runTime and \ + effect.activeByDefault and \ ((projected is True and effect.isType("projected")) or projected is False and effect.isType("passive")): # See GH issue #765 @@ -245,7 +246,7 @@ class Drone(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut): if self.charge: for effect in self.charge.effects.itervalues(): - if effect.runTime == runTime: + if effect.runTime == runTime and effect.activeByDefault: effect.handler(fit, self, ("droneCharge",)) def __deepcopy__(self, memo): diff --git a/eos/saveddata/fighter.py b/eos/saveddata/fighter.py index 29015f5f6..23218ef02 100644 --- a/eos/saveddata/fighter.py +++ b/eos/saveddata/fighter.py @@ -270,6 +270,7 @@ class Fighter(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut): if ability.active: effect = ability.effect if effect.runTime == runTime and \ + effect.activeByDefault and \ ((projected and effect.isType("projected")) or not projected): if ability.grouped: effect.handler(fit, self, context) diff --git a/eos/saveddata/fit.py b/eos/saveddata/fit.py index cf9437dbe..dc1cf491b 100644 --- a/eos/saveddata/fit.py +++ b/eos/saveddata/fit.py @@ -462,6 +462,8 @@ class Fit(object): context = ("commandRun", thing.__class__.__name__.lower()) if isinstance(thing, Module): + # This should always be a gang effect, otherwise it wouldn't be added to commandBonuses + # @todo: Check this if effect.isType("gang"): # todo: ensure that these are run with the module is active only context += ("commandRun",) @@ -509,6 +511,9 @@ class Fit(object): if self.commandFits and not withBoosters: print "Calculatate command fits and apply to fit" for fit in self.commandFits: + if self == fit: + print "nope" + continue print "calculating ", fit fit.calculateModifiedAttributes(self, True) # diff --git a/eos/saveddata/implant.py b/eos/saveddata/implant.py index ef6852c2c..a77190bc4 100644 --- a/eos/saveddata/implant.py +++ b/eos/saveddata/implant.py @@ -93,7 +93,7 @@ class Implant(HandledItem, ItemAttrShortcut): if not self.active: return for effect in self.item.effects.itervalues(): - if effect.runTime == runTime and effect.isType("passive"): + if effect.runTime == runTime and effect.isType("passive") and effect.activeByDefault: effect.handler(fit, self, ("implant",)) @validates("fitID", "itemID", "active") diff --git a/eos/saveddata/mode.py b/eos/saveddata/mode.py index f494d8d9f..2b3108a9d 100644 --- a/eos/saveddata/mode.py +++ b/eos/saveddata/mode.py @@ -51,5 +51,5 @@ class Mode(ItemAttrShortcut, HandledItem): def calculateModifiedAttributes(self, fit, runTime, forceProjected=False): if self.item: for effect in self.item.effects.itervalues(): - if effect.runTime == runTime: + if effect.runTime == runTime and effect.activeByDefault: effect.handler(fit, self, context=("module",)) diff --git a/eos/saveddata/module.py b/eos/saveddata/module.py index a382f9a56..1a1c56de3 100644 --- a/eos/saveddata/module.py +++ b/eos/saveddata/module.py @@ -625,6 +625,7 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut): if not projected or (self.projected and not forceProjected) or gang: for effect in self.charge.effects.itervalues(): if effect.runTime == runTime and \ + effect.activeByDefault and \ (effect.isType("offline") or (effect.isType("passive") and self.state >= State.ONLINE) or (effect.isType("active") and self.state >= State.ACTIVE)) and \ @@ -645,19 +646,18 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut): if effect.runTime == runTime and \ effect.isType("overheat") \ and not forceProjected \ + and effect.activeByDefault \ and ((gang and effect.isType("gang")) or not gang): effect.handler(fit, self, context) for effect in self.item.effects.itervalues(): if effect.runTime == runTime and \ + effect.activeByDefault and \ (effect.isType("offline") or (effect.isType("passive") and self.state >= State.ONLINE) or (effect.isType("active") and self.state >= State.ACTIVE))\ and ((projected and effect.isType("projected")) or not projected)\ and ((gang and effect.isType("gang")) or not gang): - thing = effect.isType("gang") - if gang: - pass effect.handler(fit, self, context) @property diff --git a/eos/saveddata/ship.py b/eos/saveddata/ship.py index 80f961331..4e4020cc7 100644 --- a/eos/saveddata/ship.py +++ b/eos/saveddata/ship.py @@ -82,7 +82,9 @@ class Ship(ItemAttrShortcut, HandledItem): if forceProjected: return for effect in self.item.effects.itervalues(): - if effect.runTime == runTime and effect.isType("passive"): + if effect.runTime == runTime and \ + effect.isType("passive") and \ + effect.activeByDefault: # Ships have effects that utilize the level of a skill as an # additional operator to the modifier. These are defined in # the effect itself, and these skillbooks are registered when diff --git a/eos/types.py b/eos/types.py index cc32f4fa9..d42cd0fe8 100644 --- a/eos/types.py +++ b/eos/types.py @@ -34,7 +34,8 @@ from eos.saveddata.fighter import Fighter from eos.saveddata.cargo import Cargo from eos.saveddata.implant import Implant from eos.saveddata.implantSet import ImplantSet -from eos.saveddata.booster import SideEffect +# Legacy booster side effect code, disabling as not currently implemented +# from eos.saveddata.booster import SideEffect from eos.saveddata.booster import Booster from eos.saveddata.fit import Fit, ImplantLocation from eos.saveddata.mode import Mode diff --git a/gui/itemStats.py b/gui/itemStats.py index 5223a0b07..63e4ce67d 100644 --- a/gui/itemStats.py +++ b/gui/itemStats.py @@ -740,31 +740,44 @@ class ItemRequirements ( wx.Panel ): class ItemEffects (wx.Panel): def __init__(self, parent, stuff, item): - wx.Panel.__init__ (self, parent) - mainSizer = wx.BoxSizer( wx.VERTICAL ) + wx.Panel.__init__(self, parent) + self.item = item + + mainSizer = wx.BoxSizer(wx.VERTICAL) self.effectList = AutoListCtrl(self, wx.ID_ANY, - style = - #wx.LC_HRULES | - #wx.LC_NO_HEADER | - wx.LC_REPORT |wx.LC_SINGLE_SEL |wx.LC_VRULES |wx.NO_BORDER) - mainSizer.Add( self.effectList, 1, wx.ALL|wx.EXPAND, 0 ) - self.SetSizer( mainSizer ) + style= + # wx.LC_HRULES | + # wx.LC_NO_HEADER | + wx.LC_REPORT | wx.LC_SINGLE_SEL | wx.LC_VRULES | wx.NO_BORDER) + mainSizer.Add(self.effectList, 1, wx.ALL | wx.EXPAND, 0) + self.SetSizer(mainSizer) + self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnClick, self.effectList) if config.debug: - self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnClick, self.effectList) + self.Bind(wx.EVT_LIST_ITEM_RIGHT_CLICK, self.OnRightClick, self.effectList) + + self.PopulateList() + + def PopulateList(self): self.effectList.InsertColumn(0,"Name") - self.effectList.InsertColumn(1,"Implemented") + self.effectList.InsertColumn(1,"Active") + self.effectList.InsertColumn(2, "Type") if config.debug: - self.effectList.InsertColumn(2,"ID") + self.effectList.InsertColumn(3, "Run Time") + self.effectList.InsertColumn(4,"ID") #self.effectList.SetColumnWidth(0,385) self.effectList.setResizeColumn(0) + self.effectList.SetColumnWidth(1,50) + self.effectList.SetColumnWidth(2, 80) + if config.debug: + self.effectList.SetColumnWidth(3, 65) + self.effectList.SetColumnWidth(4, 40) - self.effectList.SetColumnWidth(1,100) - + item = self.item effects = item.effects names = list(effects.iterkeys()) names.sort() @@ -772,19 +785,55 @@ class ItemEffects (wx.Panel): for name in names: index = self.effectList.InsertStringItem(sys.maxint, name) - try: - implemented = "Yes" if effects[name].isImplemented else "No" - except: - implemented = "Erroneous" + if effects[name].isImplemented: + if effects[name].activeByDefault: + activeByDefault = "Yes" + else: + activeByDefault = "No" + else: + activeByDefault = "" - self.effectList.SetStringItem(index, 1, implemented) + effectTypeText = "" + if effects[name].type: + for effectType in effects[name].type: + effectTypeText += effectType + " " + pass + + if effects[name].runTime and effects[name].isImplemented: + effectRunTime = str(effects[name].runTime) + else: + effectRunTime = "" + + self.effectList.SetStringItem(index, 1, activeByDefault) + self.effectList.SetStringItem(index, 2, effectTypeText) if config.debug: - self.effectList.SetStringItem(index, 2, str(effects[name].ID)) + self.effectList.SetStringItem(index, 3, effectRunTime) + self.effectList.SetStringItem(index, 4, str(effects[name].ID)) self.effectList.RefreshRows() self.Layout() def OnClick(self, event): + """ + Debug use: toggle effects on/off. + Affects *ALL* items that use that effect. + Is not stateful. Will reset if Pyfa is closed and reopened. + """ + + try: + activeByDefault = getattr(self.item.effects[event.GetText()], "activeByDefault") + if activeByDefault: + setattr(self.item.effects[event.GetText()], "activeByDefault", False) + else: + setattr(self.item.effects[event.GetText()], "activeByDefault", True) + + except AttributeError: + # Attribute doesn't exist, do nothing + pass + + self.RefreshValues(event) + + def OnRightClick(self, event): """ Debug use: open effect file with default application. If effect file does not exist, create it @@ -804,6 +853,14 @@ class ItemEffects (wx.Panel): import subprocess subprocess.call(["xdg-open", file]) + def RefreshValues(self, event): + self.Freeze() + self.effectList.ClearAll() + self.PopulateList() + self.effectList.RefreshRows() + self.Layout() + self.Thaw() + event.Skip() ########################################################################### ## Class ItemAffectedBy