diff --git a/eos/db/gamedata/queries.py b/eos/db/gamedata/queries.py index 0da3f38a4..f1e9954c3 100644 --- a/eos/db/gamedata/queries.py +++ b/eos/db/gamedata/queries.py @@ -26,7 +26,7 @@ from eos.db import gamedata_session from eos.db.gamedata.metaGroup import metatypes_table, items_table from eos.db.gamedata.group import groups_table from eos.db.util import processEager, processWhere -from eos.gamedata import AlphaClone, Attribute, Category, Group, Item, MarketGroup, MetaGroup, AttributeInfo, MetaData +from eos.gamedata import AlphaClone, Attribute, Category, Group, Item, MarketGroup, MetaGroup, AttributeInfo, MetaData, DynamicItem cache = {} configVal = getattr(eos.config, "gamedataCache", None) @@ -98,6 +98,14 @@ def getItem(lookfor, eager=None): return item +def getMutaplasmid(lookfor, eager=None): + if isinstance(lookfor, int): + item = gamedata_session.query(DynamicItem).filter(DynamicItem.ID == lookfor).first() + else: + raise TypeError("Need integer as argument") + return item + + def getItemWithBaseItemAttribute(lookfor, baseItemID, eager=None): # A lot of this is described in more detail in #1597 item = gamedata_session.query(Item).get(lookfor) diff --git a/eos/saveddata/module.py b/eos/saveddata/module.py index bdf6af4c1..2fe0044b9 100644 --- a/eos/saveddata/module.py +++ b/eos/saveddata/module.py @@ -122,7 +122,7 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut): if self.baseItemID: self.__item = eos.db.getItemWithBaseItemAttribute(self.itemID, self.baseItemID) self.__baseItem = eos.db.getItem(self.baseItemID) - self.__mutaplasmid = eos.db.getItem(self.mutaplasmidID) + self.__mutaplasmid = eos.db.getMutaplasmid(self.mutaplasmidID) if self.__baseItem is None: pyfalog.error("Base Item (id: {0}) does not exist", self.itemID) return @@ -195,6 +195,10 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut): (self.__item.category.name not in ("Module", "Subsystem", "Structure Module") and self.__item.group.name not in self.SYSTEM_GROUPS) + @property + def isMutated(self): + return self.baseItemID or self.mutaplasmidID + @property def numCharges(self): if self.charge is None: @@ -333,6 +337,14 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut): def item(self): return self.__item if self.__item != 0 else None + @property + def baseItem(self): + return self.__baseItem if self.__baseItem != 0 else None # what? + + @property + def mutaplasmid(self): + return self.__mutaplasmid if self.__mutaplasmid != 0 else None + @property def charge(self): return self.__charge if self.__charge != 0 else None diff --git a/gui/builtinContextMenus/boosterSideEffects.py b/gui/builtinContextMenus/boosterSideEffects.py index 60f5e2ca5..a936e9340 100644 --- a/gui/builtinContextMenus/boosterSideEffects.py +++ b/gui/builtinContextMenus/boosterSideEffects.py @@ -34,6 +34,7 @@ class BoosterSideEffect(ContextMenu): label = ability.name id = ContextMenu.nextID() self.effectIds[id] = ability + menuItem = wx.MenuItem(menu, id, label, kind=wx.ITEM_CHECK) menu.Bind(wx.EVT_MENU, self.handleMode, menuItem) return menuItem diff --git a/gui/builtinContextMenus/mutaplasmids.py b/gui/builtinContextMenus/mutaplasmids.py index 268e809b2..253cdac60 100644 --- a/gui/builtinContextMenus/mutaplasmids.py +++ b/gui/builtinContextMenus/mutaplasmids.py @@ -22,33 +22,38 @@ class MutaplasmidCM(ContextMenu): return False mod = selection[0] - if len(mod.item.mutaplasmids) == 0: + if len(mod.item.mutaplasmids) == 0 and not mod.isMutated: return False return True def getText(self, itmContext, selection): - # todo: switch between apply and remove - return "Apply Mutaplasmid" + mod = selection[0] + return "Apply Mutaplasmid" if not mod.isMutated else "Revert to {}".format(mod.baseItem.name) def getSubMenu(self, context, selection, rootMenu, i, pitem): + if selection[0].isMutated: + return None + msw = True if "wxMSW" in wx.PlatformInfo else False self.skillIds = {} sub = wx.Menu() mod = selection[0] + menu = rootMenu if msw else sub + for item in mod.item.mutaplasmids: label = item.item.name id = ContextMenu.nextID() self.eventIDs[id] = (item, mod) - skillItem = wx.MenuItem(sub, id, label) - rootMenu.Bind(wx.EVT_MENU, self.activate, skillItem) + skillItem = wx.MenuItem(menu, id, label) + menu.Bind(wx.EVT_MENU, self.handleMenu, skillItem) sub.Append(skillItem) return sub - def activate(self, event): + def handleMenu(self, event): mutaplasmid, mod = self.eventIDs[event.Id] fit = self.mainFrame.getActiveFit() sFit = Fit.getInstance() @@ -58,6 +63,14 @@ class MutaplasmidCM(ContextMenu): sFit.convertMutaplasmid(fit, mod.modPosition, mutaplasmid) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fit)) + def activate(self, fullContext, selection, i): + sFit = Fit.getInstance() + fitID = self.mainFrame.getActiveFit() + + mod = selection[0] + sFit.changeModule(fitID, mod.modPosition, mod.baseItemID) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) + def getBitmap(self, context, selection): return None diff --git a/gui/builtinItemStatsViews/itemMutator.py b/gui/builtinItemStatsViews/itemMutator.py new file mode 100644 index 000000000..82424c7a4 --- /dev/null +++ b/gui/builtinItemStatsViews/itemMutator.py @@ -0,0 +1,136 @@ +# noinspection PyPackageRequirements +import wx + +from eos.saveddata.mode import Mode +from eos.saveddata.character import Skill +from eos.saveddata.implant import Implant +from eos.saveddata.booster import Booster +from eos.saveddata.drone import Drone +from eos.saveddata.fighter import Fighter +from eos.saveddata.module import Module +from eos.saveddata.ship import Ship +from eos.saveddata.citadel import Citadel +from eos.saveddata.fit import Fit + +import gui.mainFrame +from gui.contextMenu import ContextMenu +from gui.bitmap_loader import BitmapLoader + + +class ItemMutator(wx.Panel): + ORDER = [Fit, Ship, Citadel, Mode, Module, Drone, Fighter, Implant, Booster, Skill] + + def __init__(self, parent, stuff, item): + wx.Panel.__init__(self, parent) + self.stuff = stuff + self.item = item + + self.activeFit = gui.mainFrame.MainFrame.getInstance().getActiveFit() + mainSizer = wx.BoxSizer(wx.VERTICAL) + + + for x in stuff.mutaplasmid.attributes: + # convert to percentages + min = round(x.min, 2) + max = round(x.max, 2) + value = stuff.itemModifiedAttributes.getOriginal(x.name) + slider = AttributeSlider(self, value, min, max) + mainSizer.Add(wx.StaticText(self, wx.ID_ANY, x.displayName), 1, wx.ALL | wx.EXPAND, 0) + mainSizer.Add(slider, 1, wx.ALL | wx.EXPAND, 0) + mainSizer.Add(wx.StaticLine(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL), 0, wx.ALL | wx.EXPAND, 0) + + + self.SetSizer(mainSizer) + self.Layout() + +class AttributeSlider(wx.Panel): + # based on http://wxpython-users.wxwidgets.narkive.com/ekgBzA7u/anyone-ever-thought-of-a-floating-point-slider + + def __init__(self, parent, baseValue, minMod, maxMod): + wx.Panel.__init__(self, parent) + + self.parent = parent + + self.mod = 100 # modifier for the underlying Slider (ensure we don't hit floats, which it doesn't support) + self.base_value = baseValue + + + self.UserMinValue = minMod + self.UserMaxValue = maxMod + self.UserValue = 1 + + self.SliderMinValue = self.UserMinValue * self.mod + self.SliderMaxValue = self.UserMaxValue * self.mod + self.SliderValue = self.UserValue * self.mod + + self.statxt1 = wx.StaticText(self, wx.ID_ANY, 'left', + style=wx.ST_NO_AUTORESIZE | wx.ALIGN_LEFT) + self.statxt2 = wx.StaticText(self, wx.ID_ANY, 'middle', + style=wx.ST_NO_AUTORESIZE | wx.ALIGN_CENTRE) + self.statxt3 = wx.StaticText(self, wx.ID_ANY, 'right', + style=wx.ST_NO_AUTORESIZE | wx.ALIGN_RIGHT) + + self.statxt1.SetLabel("{0:.3f}".format(self.UserMinValue * self.base_value)) + self.statxt1.SetToolTip("{0:+f}%".format((1-self.UserMinValue)*-100)) + self.statxt2.SetLabel("{0:.3f}".format(self.UserValue * self.base_value)) + self.statxt3.SetLabel("{0:.3f}".format(self.UserMaxValue * self.base_value)) + self.statxt3.SetToolTip("{0:+f}%".format((1-self.UserMaxValue)*-100)) + + self.slider = wx.Slider( + self, wx.ID_ANY, + self.SliderValue, + self.SliderMinValue, + self.SliderMaxValue, + style=wx.SL_HORIZONTAL) + + self.slider.SetTickFreq((self.SliderMaxValue - self.SliderMinValue) / 15) + + self.slider.Bind(wx.EVT_SCROLL, self.OnScroll) + + b = 20 + hsizer1 = wx.BoxSizer(wx.HORIZONTAL) + hsizer1.Add(self.statxt1, 1, wx.RIGHT, b) + hsizer1.Add(self.statxt2, 1, wx.LEFT | wx.RIGHT, b) + hsizer1.Add(self.statxt3, 1, wx.LEFT, b) + + b = 4 + vsizer1 = wx.BoxSizer(wx.VERTICAL) + vsizer1.Add(hsizer1, 0, wx.EXPAND | wx.ALL, b) + vsizer1.Add(self.slider, 0, wx.EXPAND | wx.LEFT | wx.TOP | wx.BOTTOM, b) + + self.SetSizerAndFit(vsizer1) + self.parent.SetClientSize((500, vsizer1.GetSize()[1])) + + def OnScroll(self, event): + self.SliderValue = self.slider.GetValue() + self.UserValue = self.SliderValue / self.mod + newValue = self.UserValue * self.base_value + if self.UserValue == 1: + self.statxt2.SetLabel("{0:.3f}".format(newValue)) + else: + self.statxt2.SetLabel("{0:.3f} ({1:+.3f})".format(newValue, newValue-self.base_value,)) + self.statxt2.SetToolTip("{0:+f}%".format((1 - self.UserValue) * -100)) + + +class TestAttributeSlider(wx.Frame): + + def __init__(self, parent, id): + title = 'Slider...' + pos = wx.DefaultPosition + size = wx.DefaultSize + sty = wx.DEFAULT_FRAME_STYLE + wx.Frame.__init__(self, parent, id, title, pos, size, sty) + + self.panel = AttributeSlider(self, 200, 0.20, 1.3) + + self.Bind(wx.EVT_CLOSE, self.OnCloseWindow) + + def OnCloseWindow(self, event): + self.Destroy() + + +if __name__ == "__main__": + app = wx.App() + frame = TestAttributeSlider(None, wx.ID_ANY) + frame.Show() + app.MainLoop() diff --git a/gui/itemStats.py b/gui/itemStats.py index 3440fb322..1ad422c42 100644 --- a/gui/itemStats.py +++ b/gui/itemStats.py @@ -34,6 +34,9 @@ from gui.builtinItemStatsViews.itemDependants import ItemDependents from gui.builtinItemStatsViews.itemEffects import ItemEffects from gui.builtinItemStatsViews.itemAffectedBy import ItemAffectedBy from gui.builtinItemStatsViews.itemProperties import ItemProperties +from gui.builtinItemStatsViews.itemMutator import ItemMutator + +from eos.saveddata.module import Module class ItemStatsDialog(wx.Dialog): @@ -163,6 +166,10 @@ class ItemStatsContainer(wx.Panel): self.traits = ItemTraits(self.nbContainer, stuff, item) self.nbContainer.AddPage(self.traits, "Traits") + if isinstance(stuff, Module) and stuff.isMutated: + self.mutator = ItemMutator(self.nbContainer, stuff, item) + self.nbContainer.AddPage(self.mutator, "Multiplasmid") + self.desc = ItemDescription(self.nbContainer, stuff, item) self.nbContainer.AddPage(self.desc, "Description")