Make Effects Togglable

This commit is contained in:
Ebag333
2016-11-09 00:46:19 -08:00
parent 6849478226
commit a3dfa3b5ba
24 changed files with 184 additions and 60 deletions

View File

@@ -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))

View File

@@ -3,5 +3,6 @@
# Used by:
# Implants from group: Booster (12 of 45)
type = "boosterSideEffect"
activeByDefault = False
def handler(fit, booster, context):
fit.ship.boostItemAttr("armorHP", booster.getModifiedItemAttr("boosterArmorHPPenalty"))

View File

@@ -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):
fit.modules.filteredItemBoost(lambda mod: mod.item.group.name == "Armor Repair Unit",
"armorDamageAmount", booster.getModifiedItemAttr("boosterArmorRepairAmountPenalty"))

View File

@@ -4,5 +4,6 @@
# 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):
fit.ship.boostItemAttr("capacitorCapacity", booster.getModifiedItemAttr("boosterCapacitorCapacityPenalty"))

View File

@@ -3,5 +3,6 @@
# Used by:
# Implants from group: Booster (12 of 45)
type = "boosterSideEffect"
activeByDefault = False
def handler(fit, booster, context):
fit.ship.boostItemAttr("maxVelocity", booster.getModifiedItemAttr("boosterMaxVelocityPenalty"))

View File

@@ -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):
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Missile Launcher Operation"),
"aoeCloudSize", booster.getModifiedItemAttr("boosterMissileAOECloudPenalty"))

View File

@@ -3,6 +3,7 @@
# Used by:
# Implants named like: Blue Pill Booster (3 of 5)
type = "boosterSideEffect"
activeByDefault = False
def handler(fit, booster, context):
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Missile Launcher Operation"),
"aoeVelocity", booster.getModifiedItemAttr("boosterAOEVelocityPenalty"))

View File

@@ -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):
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Missile Launcher Operation"),
"maxVelocity", "boosterMissileVelocityPenalty")

View File

@@ -3,5 +3,6 @@
# Used by:
# Implants from group: Booster (12 of 45)
type = "boosterSideEffect"
activeByDefault = False
def handler(fit, booster, context):
fit.ship.boostItemAttr("shieldCapacity", booster.getModifiedItemAttr("boosterShieldCapacityPenalty"))

View File

@@ -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):
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Gunnery"),
"falloff", booster.getModifiedItemAttr("boosterTurretFalloffPenalty"))

View File

@@ -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):
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Gunnery"),
"maxRange", booster.getModifiedItemAttr("boosterTurretOptimalRange"))

View File

@@ -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):
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Gunnery"),
"trackingSpeed", booster.getModifiedItemAttr("boosterTurretTrackingPenalty"))

View File

@@ -83,6 +83,28 @@ class Effect(EqBase):
return self.__runTime
@property
def activeByDefault(self):
'''
The runTime that this effect should be run at.
This property is also automaticly fetched from effects/<effectName>.py if the file exists.
the possible values are:
None, True, False
None and False are equivalent. True is the default if the effect is also implemented.
effects that are not active will not be calculated.
'''
if not self.__generated:
self.__generateHandler()
return self.__activeByDefault
@activeByDefault.setter
def activeByDefault(self, value):
# Just assign the input values to the ``numbers`` attribute.
# You *could* do something more interesting here if you wanted.
self.__activeByDefault = value
@property
def type(self):
'''
@@ -133,6 +155,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 +170,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)

View File

@@ -61,13 +61,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__()
@@ -77,6 +82,7 @@ class Booster(HandledItem, ItemAttrShortcut):
return sideEffect
raise KeyError("SideEffect with %s as name not found" % name)
'''
@property
def itemModifiedAttributes(self):
@@ -107,12 +113,17 @@ class Booster(HandledItem, ItemAttrShortcut):
if forceProjected: return
if self.active == False: 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):
@@ -128,46 +139,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
'''

View File

@@ -330,7 +330,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:

View File

@@ -220,8 +220,9 @@ class Drone(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
for effect in self.item.effects.itervalues():
if effect.runTime == runTime and \
((projected == True and effect.isType("projected")) or \
projected == False and effect.isType("passive")):
effect.activeByDefault and \
((projected == True and effect.isType("projected")) or \
projected == False and effect.isType("passive")):
# See GH issue #765
if effect.getattr('grouped'):
effect.handler(fit, self, context)
@@ -233,7 +234,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):

View File

@@ -260,6 +260,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)

View File

@@ -435,7 +435,7 @@ class Fit(object):
for name, info in self.gangBoosts.iteritems():
# Unpack all data required to run effect properly
effect, thing = info[1]
if effect.runTime == runTime:
if effect.runTime == runTime and effect.activeByDefault:
context = ("gang", thing.__class__.__name__.lower())
if isinstance(thing, Module):
if effect.isType("offline") or (effect.isType("passive") and thing.state >= State.ONLINE) or \

View File

@@ -88,7 +88,7 @@ class Implant(HandledItem, ItemAttrShortcut):
if forceProjected: return
if self.active == False: 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")

View File

@@ -50,5 +50,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",))

View File

@@ -594,15 +594,16 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
# fix for #82 and it's regression #106
if not projected or (self.projected and not forceProjected):
for effect in self.charge.effects.itervalues():
if effect.runTime == runTime:
if effect.runTime == runTime and effect.activeByDefault:
effect.handler(fit, self, ("moduleCharge",))
if self.item:
if self.state >= State.OVERHEATED:
for effect in self.item.effects.itervalues():
if effect.runTime == runTime and \
effect.isType("overheat") and \
not forceProjected:
effect.isType("overheat") and \
not forceProjected and \
effect.activeByDefault:
effect.handler(fit, self, context)
for effect in self.item.effects.itervalues():
@@ -610,7 +611,8 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
(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):
((projected and effect.isType("projected")) or not projected) and \
effect.activeByDefault:
effect.handler(fit, self, context)
@property

View File

@@ -78,7 +78,9 @@ class Ship(ItemAttrShortcut, HandledItem):
def calculateModifiedAttributes(self, fit, runTime, forceProjected = False):
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

View File

@@ -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

View File

@@ -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