From 3774e3bca07d8cefc2034eb899f94065a70f0a5a Mon Sep 17 00:00:00 2001 From: Ebag333 Date: Thu, 12 Jan 2017 01:24:26 -0800 Subject: [PATCH 01/19] add variations for drones, fighters, boosters, and implants --- eos/db/gamedata/queries.py | 16 +++++++- gui/builtinContextMenus/metaSwap.py | 63 +++++++++++++++++++++++++++-- service/fit.py | 4 +- service/market.py | 3 +- 4 files changed, 77 insertions(+), 9 deletions(-) diff --git a/eos/db/gamedata/queries.py b/eos/db/gamedata/queries.py index b2db92437..31a2b914d 100644 --- a/eos/db/gamedata/queries.py +++ b/eos/db/gamedata/queries.py @@ -23,6 +23,7 @@ from sqlalchemy.sql import and_, or_, select import eos.config 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.types import Item, Category, Group, MarketGroup, AttributeInfo, MetaData, MetaGroup @@ -231,7 +232,7 @@ def searchItems(nameLike, where=None, join=None, eager=None): @cachedQuery(2, "where", "itemids") -def getVariations(itemids, where=None, eager=None): +def getVariations(itemids, groupIDs=None, where=None, eager=None): for itemid in itemids: if not isinstance(itemid, int): raise TypeError("All passed item IDs must be integers") @@ -244,7 +245,18 @@ def getVariations(itemids, where=None, eager=None): joinon = items_table.c.typeID == metatypes_table.c.typeID vars = gamedata_session.query(Item).options(*processEager(eager)).join((metatypes_table, joinon)).filter( filter).all() - return vars + + if vars: + return vars + elif groupIDs: + itemfilter = or_(*(groups_table.c.groupID == groupID for groupID in groupIDs)) + filter = processWhere(itemfilter, where) + joinon = items_table.c.groupID == groups_table.c.groupID + vars = gamedata_session.query(Item).options(*processEager(eager)).join((groups_table, joinon)).filter( + filter).all() + + return vars + @cachedQuery(1, "attr") diff --git a/gui/builtinContextMenus/metaSwap.py b/gui/builtinContextMenus/metaSwap.py index 0b2d847ac..ff40ef8a0 100644 --- a/gui/builtinContextMenus/metaSwap.py +++ b/gui/builtinContextMenus/metaSwap.py @@ -12,7 +12,13 @@ class MetaSwap(ContextMenu): def display(self, srcContext, selection): - if self.mainFrame.getActiveFit() is None or srcContext not in ("fittingModule",): + if self.mainFrame.getActiveFit() is None or srcContext not in ( + "fittingModule", + "droneItem", + "fighterItem", + "boosterItem", + "implantItem", + ): return False # Check if list of variations is same for all of selection @@ -92,9 +98,58 @@ class MetaSwap(ContextMenu): fitID = self.mainFrame.getActiveFit() fit = sFit.getFit(fitID) - for mod in self.selection: - pos = fit.modules.index(mod) - sFit.changeModule(fitID, pos, item.ID) + for selected_item in self.selection: + if type(selected_item).__name__== 'Module': + pos = fit.modules.index(selected_item) + sFit.changeModule(fitID, pos, item.ID) + + elif type(selected_item).__name__== 'Drone': + drone_count = None + drone_index = None + + for idx, drone_stack in enumerate(fit.drones): + if drone_stack is selected_item: + drone_count = drone_stack.amount + sFit.removeDrone(fitID, idx, drone_count) + break + + if drone_count: + sFit.addDrone(fitID, item.ID, drone_count) + + elif type(selected_item).__name__== 'Fighter': + fighter_count = None + fighter_index = None + + for idx, fighter_stack in enumerate(fit.fighters): + # Right now fighters always will have max stack size. + # Including this for future improvement, so if adjustable + # fighter stacks get added we're ready for it. + if fighter_stack is selected_item: + if fighter_stack.amount > 0: + fighter_count = fighter_stack.amount + elif fighter_stack.amount == -1: + fighter_count = fighter_stack.amountActive + else: + fighter_count.amount = 0 + + sFit.removeFighter(fitID, idx) + break + + sFit.addFighter(fitID, item.ID) + + elif type(selected_item).__name__== 'Booster': + for idx, booster_stack in enumerate(fit.boosters): + if booster_stack is selected_item: + sFit.removeBooster(fitID, idx) + sFit.addBooster(fitID, item.ID) + break + + elif type(selected_item).__name__== 'Implant': + for idx, implant_stack in enumerate(fit.implants): + if implant_stack is selected_item: + sFit.removeImplant(fitID, idx) + sFit.addImplant(fitID, item.ID, False) + break wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) diff --git a/service/fit.py b/service/fit.py index 42eb60046..0373bb523 100644 --- a/service/fit.py +++ b/service/fit.py @@ -722,7 +722,7 @@ class Fit(object): self.recalc(fit) return True - def addDrone(self, fitID, itemID): + def addDrone(self, fitID, itemID, numDronesToAdd=1): if fitID is None: return False @@ -741,7 +741,7 @@ class Fit(object): fit.drones.append(drone) else: return False - drone.amount += 1 + drone.amount += numDronesToAdd eos.db.commit() self.recalc(fit) return True diff --git a/service/market.py b/service/market.py index 7d1cdea19..a3ca348df 100644 --- a/service/market.py +++ b/service/market.py @@ -537,7 +537,8 @@ class Market(): variations.update(parents) # Add all variations of parents to the set parentids = tuple(item.ID for item in parents) - variations.update(eos.db.getVariations(parentids)) + groupids = tuple(item.group.ID for item in parents) + variations.update(eos.db.getVariations(parentids, groupids)) return variations def getGroupsByCategory(self, cat): From ea12ec9cd1139e058475bf09c1ce518ca93af997 Mon Sep 17 00:00:00 2001 From: Ebag333 Date: Thu, 12 Jan 2017 08:45:16 -0800 Subject: [PATCH 02/19] Now can add 1000 ammo stacks or 5 drone stacks through context menu --- gui/builtinContextMenus/__init__.py | 2 ++ gui/builtinContextMenus/cargoAmmo.py | 34 +++++++++++++++++++++++++ gui/builtinContextMenus/droneStack.py | 36 +++++++++++++++++++++++++++ 3 files changed, 72 insertions(+) create mode 100644 gui/builtinContextMenus/cargoAmmo.py create mode 100644 gui/builtinContextMenus/droneStack.py diff --git a/gui/builtinContextMenus/__init__.py b/gui/builtinContextMenus/__init__.py index 55f26256a..10e44a72b 100644 --- a/gui/builtinContextMenus/__init__.py +++ b/gui/builtinContextMenus/__init__.py @@ -22,4 +22,6 @@ __all__ = [ "metaSwap", "implantSets", "fighterAbilities", + "cargoAmmo", + "droneStack" ] diff --git a/gui/builtinContextMenus/cargoAmmo.py b/gui/builtinContextMenus/cargoAmmo.py new file mode 100644 index 000000000..6b1233164 --- /dev/null +++ b/gui/builtinContextMenus/cargoAmmo.py @@ -0,0 +1,34 @@ +from gui.contextMenu import ContextMenu +import gui.mainFrame +import service +import gui.globalEvents as GE +import wx + + +class CargoAmmo(ContextMenu): + def __init__(self): + self.mainFrame = gui.mainFrame.MainFrame.getInstance() + + def display(self, srcContext, selection): + if srcContext not in ("marketItemGroup", "marketItemMisc") or self.mainFrame.getActiveFit() is None: + return False + + for selected_item in selection: + if selected_item.category.ID in ( + 8, # Charge + ): + return True + + def getText(self, itmContext, selection): + return "Add {0} to Cargo (x1000)".format(itmContext) + + def activate(self, fullContext, selection, i): + sFit = service.Fit.getInstance() + fitID = self.mainFrame.getActiveFit() + + typeID = int(selection[0].ID) + sFit.addCargo(fitID, typeID, 1000) + self.mainFrame.additionsPane.select("Cargo") + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) + +CargoAmmo.register() diff --git a/gui/builtinContextMenus/droneStack.py b/gui/builtinContextMenus/droneStack.py new file mode 100644 index 000000000..687f94906 --- /dev/null +++ b/gui/builtinContextMenus/droneStack.py @@ -0,0 +1,36 @@ +from gui.contextMenu import ContextMenu +import gui.mainFrame +import service +import gui.globalEvents as GE +import wx + + +class CargoAmmo(ContextMenu): + def __init__(self): + self.mainFrame = gui.mainFrame.MainFrame.getInstance() + + def display(self, srcContext, selection): + if srcContext not in ("marketItemGroup", "marketItemMisc") or self.mainFrame.getActiveFit() is None: + return False + + for selected_item in selection: + if selected_item.category.ID in ( + 18, # Drones + ): + return True + + return False + + def getText(self, itmContext, selection): + return "Add {0} to Drone Bay (x5)".format(itmContext) + + def activate(self, fullContext, selection, i): + sFit = service.Fit.getInstance() + fitID = self.mainFrame.getActiveFit() + + typeID = int(selection[0].ID) + sFit.addDrone(fitID, typeID, 5) + self.mainFrame.additionsPane.select("Drones") + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) + +CargoAmmo.register() From ade47bed8b4b5f4b37b66110b3c1fa6b80eafacd Mon Sep 17 00:00:00 2001 From: Ebag333 Date: Thu, 12 Jan 2017 12:30:25 -0800 Subject: [PATCH 03/19] Add filtering for implants and boosters --- service/market.py | 43 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/service/market.py b/service/market.py index a3ca348df..313b711d8 100644 --- a/service/market.py +++ b/service/market.py @@ -519,7 +519,40 @@ class Market(): parents = set() # Set-container for variables variations = set() + variations_limiter = set() for item in items: + if item.category.ID == 20: # Implants and Boosters + implant_remove_list = set() + implant_remove_list.add("Low-Grade ") + implant_remove_list.add("Low-grade ") + implant_remove_list.add("Mid-Grade ") + implant_remove_list.add("Mid-grade ") + implant_remove_list.add("High-Grade ") + implant_remove_list.add("High-grade ") + implant_remove_list.add("Limited ") + implant_remove_list.add(" - Advanced") + implant_remove_list.add(" - Basic") + implant_remove_list.add(" - Elite") + implant_remove_list.add(" - Improved") + implant_remove_list.add(" - Standard") + implant_remove_list.add("Copper ") + implant_remove_list.add("Gold ") + implant_remove_list.add("Silver ") + implant_remove_list.add("Advanced ") + implant_remove_list.add("Improved ") + implant_remove_list.add("Prototype ") + implant_remove_list.add("Standard ") + implant_remove_list.add("Strong ") + implant_remove_list.add("Synth ") + + for implant_prefix in ("-6","-7","-8","-9","-10"): + for i in range(50): + implant_remove_list.add(implant_prefix + str("%02d" % i)) + + for text_to_remove in implant_remove_list: + if text_to_remove in item.name: + variations_limiter.add(item.name.replace(text_to_remove,"")) + # Get parent item if alreadyparent is False: parent = self.getParentItemByItem(item) @@ -538,7 +571,15 @@ class Market(): # Add all variations of parents to the set parentids = tuple(item.ID for item in parents) groupids = tuple(item.group.ID for item in parents) - variations.update(eos.db.getVariations(parentids, groupids)) + variations_list = eos.db.getVariations(parentids, groupids) + + if variations_limiter: + for limit in variations_limiter: + trimmed_variations_list = [variation_item for variation_item in variations_list if limit in variation_item.name] + if trimmed_variations_list: + variations_list = trimmed_variations_list + + variations.update(variations_list) return variations def getGroupsByCategory(self, cat): From 93e7b4f5cfba519810ad9126d9e644ef0dfb06a8 Mon Sep 17 00:00:00 2001 From: Ebag333 Date: Wed, 15 Feb 2017 17:23:53 -0800 Subject: [PATCH 04/19] Cherry pick d033e4a8d919664d3ae210098291e38df71d3256 --- eos/saveddata/module.py | 9 ++ gui/builtinStatsViews/__init__.py | 2 +- gui/builtinStatsViews/outgoingViewFull.py | 153 ++++++++++++++++++++++ 3 files changed, 163 insertions(+), 1 deletion(-) create mode 100644 gui/builtinStatsViews/outgoingViewFull.py diff --git a/eos/saveddata/module.py b/eos/saveddata/module.py index ba41d559d..f211ce4bc 100644 --- a/eos/saveddata/module.py +++ b/eos/saveddata/module.py @@ -701,6 +701,15 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut): else: return 0 + def getAmountPerSec(self, attribute): + amount = self.getModifiedItemAttr(attribute) + if not amount: + return 0 + cycleTime = self.cycleTime + if not cycleTime: + return 0 + return float(amount) * 1000 / cycleTime + def __deepcopy__(self, memo): item = self.item if item is None: diff --git a/gui/builtinStatsViews/__init__.py b/gui/builtinStatsViews/__init__.py index 5f2ca646e..7161d1c38 100644 --- a/gui/builtinStatsViews/__init__.py +++ b/gui/builtinStatsViews/__init__.py @@ -1,3 +1,3 @@ __all__ = ["resourcesViewFull", "resistancesViewFull", - "rechargeViewFull", "firepowerViewFull", "capacitorViewFull", + "rechargeViewFull", "firepowerViewFull", "capacitorViewFull", "outgoingViewFull", "targetingMiscViewFull", "priceViewFull", "miningyieldViewFull"] diff --git a/gui/builtinStatsViews/outgoingViewFull.py b/gui/builtinStatsViews/outgoingViewFull.py new file mode 100644 index 000000000..75734e24e --- /dev/null +++ b/gui/builtinStatsViews/outgoingViewFull.py @@ -0,0 +1,153 @@ +#=============================================================================== +# Copyright (C) 2014 Alexandros Kosiaris +# +# This file is part of pyfa. +# +# pyfa is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# pyfa is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with pyfa. If not, see . +#=============================================================================== + +import wx +import service +import gui.mainFrame +from gui.statsView import StatsView +from gui import bitmapLoader +from gui.utils.numberFormatter import formatAmount + +class OutgoingViewFull(StatsView): + name = "outgoingViewFull" + def __init__(self, parent): + StatsView.__init__(self) + self.parent = parent + self._cachedValues = [] + def getHeaderText(self, fit): + return "Outgoing" + + def getTextExtentW(self, text): + width, height = self.parent.GetTextExtent( text ) + return width + + def populatePanel(self, contentPanel, headerPanel): + contentSizer = contentPanel.GetSizer() + parent = self.panel = contentPanel + self.headerPanel = headerPanel + + panel = "full" + + sizerOutgoing = wx.FlexGridSizer(1, 6) + sizerOutgoing.AddGrowableCol(1) + + contentSizer.Add( sizerOutgoing, 0, wx.EXPAND, 0) + + counter = 0 + + for outgoingType, label, image in (("remoteArmor","Armor RR","armorActive") , ("remoteShield","Shield RR","shieldActive")): + baseBox = wx.BoxSizer(wx.HORIZONTAL) + sizerOutgoing.Add(baseBox, 1, wx.ALIGN_LEFT if counter == 0 else wx.ALIGN_CENTER_HORIZONTAL) + + baseBox.Add(bitmapLoader.getStaticBitmap("%s_big" % image, parent, "icons"), 0, wx.ALIGN_CENTER) + + box = wx.BoxSizer(wx.VERTICAL) + baseBox.Add(box, 0, wx.ALIGN_CENTER) + + box.Add(wx.StaticText(parent, wx.ID_ANY, label), 0, wx.ALIGN_LEFT) + + hbox = wx.BoxSizer(wx.HORIZONTAL) + box.Add(hbox, 1, wx.ALIGN_CENTER) + + lbl = wx.StaticText(parent, wx.ID_ANY, u"0.0 HP/s") + setattr(self, "label%soutgoing%s" % (panel.capitalize() ,outgoingType.capitalize()), lbl) + + hbox.Add(lbl, 0, wx.ALIGN_CENTER) + self._cachedValues.append(0) + counter += 1 + + targetSizer = sizerOutgoing + + baseBox = wx.BoxSizer(wx.HORIZONTAL) + targetSizer.Add(baseBox, 0, wx.ALIGN_RIGHT) + + baseBox.Add(bitmapLoader.getStaticBitmap("capacitorInfo_big", parent, "icons"), 0, wx.ALIGN_CENTER) + + gridS = wx.GridSizer(2,2,0,0) + + baseBox.Add(gridS, 0) + + lbl = wx.StaticText(parent, wx.ID_ANY, "0.0 GJ/s") + setattr(self, "label%soutgoingRemotecapacitor" % panel.capitalize(), lbl) + gridS.Add(wx.StaticText(parent, wx.ID_ANY, " +CAP: "), 0, wx.ALL | wx.ALIGN_RIGHT) + gridS.Add(lbl, 0, wx.ALIGN_LEFT) + + self._cachedValues.append(0) + + lbl = wx.StaticText(parent, wx.ID_ANY, "0.0 GJ/s") + setattr(self, "label%soutgoingNeuting" % panel.capitalize(), lbl) + gridS.Add(wx.StaticText(parent, wx.ID_ANY, " Neut: "), 0, wx.ALL | wx.ALIGN_RIGHT) + + self._cachedValues.append(0) + + gridS.Add(lbl, 0, wx.ALIGN_LEFT) + + image = bitmapLoader.getBitmap("turret_small", "icons") + firepower = wx.BitmapButton(contentPanel, -1, image) + firepower.SetToolTip(wx.ToolTip("Click to toggle to Firepower View")) + firepower.Bind(wx.EVT_BUTTON, self.switchToFirepowerView) + sizerOutgoing.Add(firepower, 0, wx.ALIGN_LEFT) + + self._cachedValues.append(0) + + def switchToFirepowerView(self, event): + # Getting the active fit + mainFrame = gui.mainFrame.MainFrame.getInstance() + sFit = service.Fit.getInstance() + fit = sFit.getFit(mainFrame.getActiveFit()) + # Remove ourselves from statsPane's view list + self.parent.views.remove(self) + self._cachedValues = [] + # And no longer display us + self.panel.GetSizer().Clear(True) + self.panel.GetSizer().Layout() + # Get the new view + view = StatsView.getView("firepowerViewFull")(self.parent) + view.populatePanel(self.panel, self.headerPanel) + # Populate us in statsPane's view list + self.parent.views.append(view) + # Get the TogglePanel + tp = self.panel.GetParent() + tp.SetLabel(view.getHeaderText(fit)) + view.refreshPanel(fit) + + def refreshPanel(self, fit): + #If we did anything intresting, we'd update our labels to reflect the new fit's stats here + + stats = (("labelFulloutgoingRemotearmor", lambda: fit.armorRR, 3, 0, 0, u"%s HP/s", None), + ("labelFulloutgoingRemoteshield", lambda: fit.shieldRR, 3, 0, 0, u"%s HP/s", None), + ("labelFulloutgoingRemotecapacitor", lambda: fit.captransfer, 3, 0, 0, u"%s GJ/s",None), + ("labelFulloutgoingNeuting", lambda: fit.neut, 3, 0, 0, u"%s GJ/s", None)) + + counter = 0 + for labelName, value, prec, lowest, highest, valueFormat, altFormat in stats: + label = getattr(self, labelName) + value = value() if fit is not None else 0 + value = value if value is not None else 0 + if self._cachedValues[counter] != value: + valueStr = formatAmount(value, prec, lowest, highest) + label.SetLabel(valueFormat % valueStr) + tipStr = valueFormat % valueStr if altFormat is None else altFormat % value + label.SetToolTip(wx.ToolTip(tipStr)) + self._cachedValues[counter] = value + counter +=1 + self.panel.Layout() + self.headerPanel.Layout() + +OutgoingViewFull.register() From 25b17a221c6377acf05771702eac7a425539a307 Mon Sep 17 00:00:00 2001 From: Ebag333 Date: Wed, 15 Feb 2017 18:23:14 -0800 Subject: [PATCH 05/19] Update to current version --- eos/saveddata/module.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/eos/saveddata/module.py b/eos/saveddata/module.py index f211ce4bc..ba41d559d 100644 --- a/eos/saveddata/module.py +++ b/eos/saveddata/module.py @@ -701,15 +701,6 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut): else: return 0 - def getAmountPerSec(self, attribute): - amount = self.getModifiedItemAttr(attribute) - if not amount: - return 0 - cycleTime = self.cycleTime - if not cycleTime: - return 0 - return float(amount) * 1000 / cycleTime - def __deepcopy__(self, memo): item = self.item if item is None: From 6e047074576d204228f6fc7560e61fd6e39761ef Mon Sep 17 00:00:00 2001 From: Ebag333 Date: Wed, 15 Feb 2017 18:25:11 -0800 Subject: [PATCH 06/19] Commit *ALL* the files. --- eos/saveddata/fit.py | 85 ++++++++++++++++++++++++++++++++++++++++++++ gui/statsPane.py | 2 +- gui/statsView.py | 1 + 3 files changed, 87 insertions(+), 1 deletion(-) diff --git a/eos/saveddata/fit.py b/eos/saveddata/fit.py index de245e185..07960928d 100644 --- a/eos/saveddata/fit.py +++ b/eos/saveddata/fit.py @@ -18,6 +18,7 @@ # =============================================================================== import time +import math from copy import deepcopy from itertools import chain from math import sqrt, log, asinh @@ -127,6 +128,12 @@ class Fit(object): self.__capUsed = None self.__capRecharge = None self.__calculatedTargets = [] + self.__remoteReps = { + "Armor": 0, + "Shield": 0, + "Hull": 0, + "Capacitor": 0, + } self.factorReload = False self.boostsFits = set() self.gangBoosts = None @@ -392,6 +399,9 @@ class Fit(object): self.ecmProjectedStr = 1 self.commandBonuses = {} + for remoterep_type in ("Armor", "Shield", "Hull", "Capacitor"): + self.__remoteReps[remoterep_type] = 0 + del self.__calculatedTargets[:] del self.__extraDrains[:] @@ -1147,6 +1157,81 @@ class Fit(object): self.__capStable = True self.__capState = 100 + @property + def remoteReps(self): + def amount_per_second(module_amount, module_duration, module_reload, module_chargerate, module_capacity, module_volume): + numcycles = math.floor(module_capacity / (module_volume * module_chargerate)) + + module_amount *= numcycles + module_duration = module_chargerate * numcycles + module_reload + + return module_amount / module_duration + + for module in self.modules: + # Skip empty modules + if module.isEmpty: + continue + + module_group = getattr(module.item.group, "name") + + # Skip modules that aren't online + if getattr(module, "state", 0) < 1: + continue + + if module_group in ("Remote Armor Repairer", "Ancillary Remote Armor Repairer"): + # Remote Armor Reppers + hp = module.getModifiedItemAttr("armorDamageAmount", 0) + duration = module.getModifiedItemAttr("duration", 0) / 1000 + reloadTime = module.getModifiedItemAttr("reloadTime", 0) / 1000 + chargeRate = module.getModifiedItemAttr("chargeRate", 1) + fueledMultiplier = module.getModifiedItemAttr("chargedArmorDamageMultiplier", 1) + capacity = module.getModifiedItemAttr("capacity", 0) + volume = module.getModifiedChargeAttr("volume", 0) + + if module.charge: + hp *= fueledMultiplier + hp_per_s = amount_per_second(hp, duration, reloadTime, chargeRate, capacity, volume) + else: + hp_per_s = hp / duration + + self.__remoteReps["Armor"] += hp_per_s + + elif module_group in ("Remote Hull Repairer",): + # Remote Hull Reppers + hp = module.getModifiedItemAttr("structureDamageAmount", 0) + duration = module.getModifiedItemAttr("duration", 0) / 1000 + + hp_per_s = hp / duration + + self.__remoteReps["Hull"] += hp_per_s + + elif module_group in ("Remote Shield Booster", "Ancillary Remote Shield Booster"): + # Remote Shield Reppers + hp = module.getModifiedItemAttr("shieldBonus", 0) + duration = module.getModifiedItemAttr("duration", 0) / 1000 + reloadTime = module.getModifiedItemAttr("reloadTime", 0) / 1000 + chargeRate = module.getModifiedItemAttr("chargeRate", 1) + capacity = module.getModifiedItemAttr("capacity", 0) + volume = module.getModifiedChargeAttr("volume", 0) + + if module.charge: + hp_per_s = amount_per_second(hp, duration, reloadTime, chargeRate, capacity, volume) + else: + hp_per_s = hp / duration + + self.__remoteReps["Shield"] += hp_per_s + + elif module_group in ("Remote Capacitor Transmitter",): + # Remote Capacitor Boosters + hp = module.getModifiedItemAttr("powerTransferAmount", 0) + duration = module.getModifiedItemAttr("duration", 0) / 1000 + + hp_per_s = hp / duration + + self.__remoteReps["Capacitor"] += hp_per_s + + return self.__remoteReps + @property def hp(self): hp = {} diff --git a/gui/statsPane.py b/gui/statsPane.py index 6aaf277f5..c86786f97 100644 --- a/gui/statsPane.py +++ b/gui/statsPane.py @@ -33,7 +33,7 @@ from gui.pyfatogglepanel import TogglePanel class StatsPane(wx.Panel): DEFAULT_VIEWS = ["resourcesViewFull", "resistancesViewFull", "rechargeViewFull", "firepowerViewFull", "capacitorViewFull", "targetingmiscViewFull", - "priceViewFull"] + "priceViewFull", "outgoingViewFull"] def fitChanged(self, event): sFit = Fit.getInstance() diff --git a/gui/statsView.py b/gui/statsView.py index 773063ca4..dbdb6da3c 100644 --- a/gui/statsView.py +++ b/gui/statsView.py @@ -52,4 +52,5 @@ from gui.builtinStatsViews import ( # noqa: E402, F401 rechargeViewFull, targetingMiscViewFull, priceViewFull, + outgoingViewFull, ) From 13996d777076149d50c8d6ca01959741151c56b1 Mon Sep 17 00:00:00 2001 From: Ebag333 Date: Wed, 15 Feb 2017 18:50:35 -0800 Subject: [PATCH 07/19] Stupid change list making me miss files. --- gui/builtinStatsViews/outgoingViewFull.py | 121 +++++++--------------- 1 file changed, 37 insertions(+), 84 deletions(-) diff --git a/gui/builtinStatsViews/outgoingViewFull.py b/gui/builtinStatsViews/outgoingViewFull.py index 75734e24e..5a693aae9 100644 --- a/gui/builtinStatsViews/outgoingViewFull.py +++ b/gui/builtinStatsViews/outgoingViewFull.py @@ -1,4 +1,4 @@ -#=============================================================================== +# =============================================================================== # Copyright (C) 2014 Alexandros Kosiaris # # This file is part of pyfa. @@ -15,26 +15,28 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# =============================================================================== +# noinspection PyPackageRequirements import wx -import service -import gui.mainFrame from gui.statsView import StatsView -from gui import bitmapLoader +from gui.bitmapLoader import BitmapLoader from gui.utils.numberFormatter import formatAmount + class OutgoingViewFull(StatsView): name = "outgoingViewFull" + def __init__(self, parent): StatsView.__init__(self) self.parent = parent self._cachedValues = [] + def getHeaderText(self, fit): - return "Outgoing" + return "Remote Reps" def getTextExtentW(self, text): - width, height = self.parent.GetTextExtent( text ) + width, height = self.parent.GetTextExtent(text) return width def populatePanel(self, contentPanel, headerPanel): @@ -44,96 +46,46 @@ class OutgoingViewFull(StatsView): panel = "full" - sizerOutgoing = wx.FlexGridSizer(1, 6) - sizerOutgoing.AddGrowableCol(1) + sizerOutgoing = wx.GridSizer(1, 4) - contentSizer.Add( sizerOutgoing, 0, wx.EXPAND, 0) + contentSizer.Add(sizerOutgoing, 0, wx.EXPAND, 0) counter = 0 - for outgoingType, label, image in (("remoteArmor","Armor RR","armorActive") , ("remoteShield","Shield RR","shieldActive")): - baseBox = wx.BoxSizer(wx.HORIZONTAL) - sizerOutgoing.Add(baseBox, 1, wx.ALIGN_LEFT if counter == 0 else wx.ALIGN_CENTER_HORIZONTAL) + rr_list = [ + ("RemoteArmor", "Armor RR", "armorActive"), + ("RemoteShield", "Shield RR", "shieldActive"), + ("RemoteHull", "Hull RR", "hullActive"), + ("RemoteCapacitor", "Capacitor RR", "capacitorInfo"), + ] - baseBox.Add(bitmapLoader.getStaticBitmap("%s_big" % image, parent, "icons"), 0, wx.ALIGN_CENTER) + for outgoingType, label, image in rr_list: + baseBox = wx.BoxSizer(wx.VERTICAL) - box = wx.BoxSizer(wx.VERTICAL) - baseBox.Add(box, 0, wx.ALIGN_CENTER) + baseBox.Add(BitmapLoader.getStaticBitmap("%s_big" % image, parent, "gui"), 0, wx.ALIGN_CENTER) - box.Add(wx.StaticText(parent, wx.ID_ANY, label), 0, wx.ALIGN_LEFT) + if "Capacitor" in label: + lbl = wx.StaticText(parent, wx.ID_ANY, u"0 GJ/s") + else: + lbl = wx.StaticText(parent, wx.ID_ANY, u"0 HP/s") - hbox = wx.BoxSizer(wx.HORIZONTAL) - box.Add(hbox, 1, wx.ALIGN_CENTER) + setattr(self, "label%s" % outgoingType, lbl) - lbl = wx.StaticText(parent, wx.ID_ANY, u"0.0 HP/s") - setattr(self, "label%soutgoing%s" % (panel.capitalize() ,outgoingType.capitalize()), lbl) - - hbox.Add(lbl, 0, wx.ALIGN_CENTER) + baseBox.Add(lbl, 0, wx.ALIGN_CENTER) self._cachedValues.append(0) counter += 1 - targetSizer = sizerOutgoing - - baseBox = wx.BoxSizer(wx.HORIZONTAL) - targetSizer.Add(baseBox, 0, wx.ALIGN_RIGHT) - - baseBox.Add(bitmapLoader.getStaticBitmap("capacitorInfo_big", parent, "icons"), 0, wx.ALIGN_CENTER) - - gridS = wx.GridSizer(2,2,0,0) - - baseBox.Add(gridS, 0) - - lbl = wx.StaticText(parent, wx.ID_ANY, "0.0 GJ/s") - setattr(self, "label%soutgoingRemotecapacitor" % panel.capitalize(), lbl) - gridS.Add(wx.StaticText(parent, wx.ID_ANY, " +CAP: "), 0, wx.ALL | wx.ALIGN_RIGHT) - gridS.Add(lbl, 0, wx.ALIGN_LEFT) - - self._cachedValues.append(0) - - lbl = wx.StaticText(parent, wx.ID_ANY, "0.0 GJ/s") - setattr(self, "label%soutgoingNeuting" % panel.capitalize(), lbl) - gridS.Add(wx.StaticText(parent, wx.ID_ANY, " Neut: "), 0, wx.ALL | wx.ALIGN_RIGHT) - - self._cachedValues.append(0) - - gridS.Add(lbl, 0, wx.ALIGN_LEFT) - - image = bitmapLoader.getBitmap("turret_small", "icons") - firepower = wx.BitmapButton(contentPanel, -1, image) - firepower.SetToolTip(wx.ToolTip("Click to toggle to Firepower View")) - firepower.Bind(wx.EVT_BUTTON, self.switchToFirepowerView) - sizerOutgoing.Add(firepower, 0, wx.ALIGN_LEFT) - - self._cachedValues.append(0) - - def switchToFirepowerView(self, event): - # Getting the active fit - mainFrame = gui.mainFrame.MainFrame.getInstance() - sFit = service.Fit.getInstance() - fit = sFit.getFit(mainFrame.getActiveFit()) - # Remove ourselves from statsPane's view list - self.parent.views.remove(self) - self._cachedValues = [] - # And no longer display us - self.panel.GetSizer().Clear(True) - self.panel.GetSizer().Layout() - # Get the new view - view = StatsView.getView("firepowerViewFull")(self.parent) - view.populatePanel(self.panel, self.headerPanel) - # Populate us in statsPane's view list - self.parent.views.append(view) - # Get the TogglePanel - tp = self.panel.GetParent() - tp.SetLabel(view.getHeaderText(fit)) - view.refreshPanel(fit) + sizerOutgoing.Add(baseBox, 1, wx.ALIGN_LEFT) def refreshPanel(self, fit): - #If we did anything intresting, we'd update our labels to reflect the new fit's stats here + # If we did anything intresting, we'd update our labels to reflect the new fit's stats here - stats = (("labelFulloutgoingRemotearmor", lambda: fit.armorRR, 3, 0, 0, u"%s HP/s", None), - ("labelFulloutgoingRemoteshield", lambda: fit.shieldRR, 3, 0, 0, u"%s HP/s", None), - ("labelFulloutgoingRemotecapacitor", lambda: fit.captransfer, 3, 0, 0, u"%s GJ/s",None), - ("labelFulloutgoingNeuting", lambda: fit.neut, 3, 0, 0, u"%s GJ/s", None)) + stats = [ + ("labelRemoteArmor", lambda: fit.remoteReps["Armor"], 3, 0, 0, u"%s HP/s", None), + ("labelRemoteShield", lambda: fit.remoteReps["Shield"], 3, 0, 0, u"%s HP/s", None), + ("labelRemoteHull", lambda: fit.remoteReps["Hull"], 3, 0, 0, u"%s HP/s", None), + ("labelRemoteCapacitor", lambda: fit.remoteReps["Capacitor"], 3, 0, 0, u"%s GJ/s", None), + ] counter = 0 for labelName, value, prec, lowest, highest, valueFormat, altFormat in stats: @@ -146,8 +98,9 @@ class OutgoingViewFull(StatsView): tipStr = valueFormat % valueStr if altFormat is None else altFormat % value label.SetToolTip(wx.ToolTip(tipStr)) self._cachedValues[counter] = value - counter +=1 + counter += 1 self.panel.Layout() self.headerPanel.Layout() - + + OutgoingViewFull.register() From eb97a1c11cd93dfff6e1e50891df985293197861 Mon Sep 17 00:00:00 2001 From: Ebag333 Date: Wed, 15 Feb 2017 19:11:32 -0800 Subject: [PATCH 08/19] Add tooltip and also a minimal version of the view (for future state). --- gui/builtinStatsViews/outgoingViewFull.py | 14 +-- gui/builtinStatsViews/outgoingViewMinimal.py | 108 +++++++++++++++++++ 2 files changed, 116 insertions(+), 6 deletions(-) create mode 100644 gui/builtinStatsViews/outgoingViewMinimal.py diff --git a/gui/builtinStatsViews/outgoingViewFull.py b/gui/builtinStatsViews/outgoingViewFull.py index 5a693aae9..945edd4fe 100644 --- a/gui/builtinStatsViews/outgoingViewFull.py +++ b/gui/builtinStatsViews/outgoingViewFull.py @@ -53,22 +53,24 @@ class OutgoingViewFull(StatsView): counter = 0 rr_list = [ - ("RemoteArmor", "Armor RR", "armorActive"), - ("RemoteShield", "Shield RR", "shieldActive"), - ("RemoteHull", "Hull RR", "hullActive"), - ("RemoteCapacitor", "Capacitor RR", "capacitorInfo"), + ("RemoteArmor", "Armor:", "armorActive", "Armor hitpoints per second repaired remotely."), + ("RemoteShield", "Shield:", "shieldActive", "Shield hitpoints per second repaired remotely."), + ("RemoteHull", "Hull:", "hullActive", "Hull hitpoints per second repaired remotely."), + ("RemoteCapacitor", "Capacitor:", "capacitorInfo", "Capacitor GJ/s per second transferred remotely."), ] - for outgoingType, label, image in rr_list: + for outgoingType, label, image, tooltip in rr_list: baseBox = wx.BoxSizer(wx.VERTICAL) baseBox.Add(BitmapLoader.getStaticBitmap("%s_big" % image, parent, "gui"), 0, wx.ALIGN_CENTER) - if "Capacitor" in label: + if "Capacitor" in outgoingType: lbl = wx.StaticText(parent, wx.ID_ANY, u"0 GJ/s") else: lbl = wx.StaticText(parent, wx.ID_ANY, u"0 HP/s") + lbl.SetToolTip(wx.ToolTip(tooltip)) + setattr(self, "label%s" % outgoingType, lbl) baseBox.Add(lbl, 0, wx.ALIGN_CENTER) diff --git a/gui/builtinStatsViews/outgoingViewMinimal.py b/gui/builtinStatsViews/outgoingViewMinimal.py new file mode 100644 index 000000000..945edd4fe --- /dev/null +++ b/gui/builtinStatsViews/outgoingViewMinimal.py @@ -0,0 +1,108 @@ +# =============================================================================== +# Copyright (C) 2014 Alexandros Kosiaris +# +# This file is part of pyfa. +# +# pyfa is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# pyfa is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with pyfa. If not, see . +# =============================================================================== + +# noinspection PyPackageRequirements +import wx +from gui.statsView import StatsView +from gui.bitmapLoader import BitmapLoader +from gui.utils.numberFormatter import formatAmount + + +class OutgoingViewFull(StatsView): + name = "outgoingViewFull" + + def __init__(self, parent): + StatsView.__init__(self) + self.parent = parent + self._cachedValues = [] + + def getHeaderText(self, fit): + return "Remote Reps" + + def getTextExtentW(self, text): + width, height = self.parent.GetTextExtent(text) + return width + + def populatePanel(self, contentPanel, headerPanel): + contentSizer = contentPanel.GetSizer() + parent = self.panel = contentPanel + self.headerPanel = headerPanel + + panel = "full" + + sizerOutgoing = wx.GridSizer(1, 4) + + contentSizer.Add(sizerOutgoing, 0, wx.EXPAND, 0) + + counter = 0 + + rr_list = [ + ("RemoteArmor", "Armor:", "armorActive", "Armor hitpoints per second repaired remotely."), + ("RemoteShield", "Shield:", "shieldActive", "Shield hitpoints per second repaired remotely."), + ("RemoteHull", "Hull:", "hullActive", "Hull hitpoints per second repaired remotely."), + ("RemoteCapacitor", "Capacitor:", "capacitorInfo", "Capacitor GJ/s per second transferred remotely."), + ] + + for outgoingType, label, image, tooltip in rr_list: + baseBox = wx.BoxSizer(wx.VERTICAL) + + baseBox.Add(BitmapLoader.getStaticBitmap("%s_big" % image, parent, "gui"), 0, wx.ALIGN_CENTER) + + if "Capacitor" in outgoingType: + lbl = wx.StaticText(parent, wx.ID_ANY, u"0 GJ/s") + else: + lbl = wx.StaticText(parent, wx.ID_ANY, u"0 HP/s") + + lbl.SetToolTip(wx.ToolTip(tooltip)) + + setattr(self, "label%s" % outgoingType, lbl) + + baseBox.Add(lbl, 0, wx.ALIGN_CENTER) + self._cachedValues.append(0) + counter += 1 + + sizerOutgoing.Add(baseBox, 1, wx.ALIGN_LEFT) + + def refreshPanel(self, fit): + # If we did anything intresting, we'd update our labels to reflect the new fit's stats here + + stats = [ + ("labelRemoteArmor", lambda: fit.remoteReps["Armor"], 3, 0, 0, u"%s HP/s", None), + ("labelRemoteShield", lambda: fit.remoteReps["Shield"], 3, 0, 0, u"%s HP/s", None), + ("labelRemoteHull", lambda: fit.remoteReps["Hull"], 3, 0, 0, u"%s HP/s", None), + ("labelRemoteCapacitor", lambda: fit.remoteReps["Capacitor"], 3, 0, 0, u"%s GJ/s", None), + ] + + counter = 0 + for labelName, value, prec, lowest, highest, valueFormat, altFormat in stats: + label = getattr(self, labelName) + value = value() if fit is not None else 0 + value = value if value is not None else 0 + if self._cachedValues[counter] != value: + valueStr = formatAmount(value, prec, lowest, highest) + label.SetLabel(valueFormat % valueStr) + tipStr = valueFormat % valueStr if altFormat is None else altFormat % value + label.SetToolTip(wx.ToolTip(tipStr)) + self._cachedValues[counter] = value + counter += 1 + self.panel.Layout() + self.headerPanel.Layout() + + +OutgoingViewFull.register() From 5ca882d3eafd99b083cdd7c730d547c9c6aa0bbf Mon Sep 17 00:00:00 2001 From: Ebag333 Date: Fri, 24 Feb 2017 13:06:02 -0800 Subject: [PATCH 09/19] implement a suggestion from @blitzmann --- eos/saveddata/fit.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eos/saveddata/fit.py b/eos/saveddata/fit.py index 07960928d..5e40aff80 100644 --- a/eos/saveddata/fit.py +++ b/eos/saveddata/fit.py @@ -399,7 +399,7 @@ class Fit(object): self.ecmProjectedStr = 1 self.commandBonuses = {} - for remoterep_type in ("Armor", "Shield", "Hull", "Capacitor"): + for remoterep_type in self.__remoteReps: self.__remoteReps[remoterep_type] = 0 del self.__calculatedTargets[:] From 3892ac5996be5b5d21ca8f7962b211e5557d08ed Mon Sep 17 00:00:00 2001 From: blitzman Date: Fri, 24 Feb 2017 18:33:42 -0500 Subject: [PATCH 10/19] Change functionality of remote rep calculations to be more efficient. * Implement a property per attribute * Use None as our cleared value (signifies that it really hasn't been calculated, not just that the calc was 0) --- eos/saveddata/fit.py | 51 +++++++++++++++----- gui/builtinStatsViews/outgoingViewFull.py | 8 +-- gui/builtinStatsViews/outgoingViewMinimal.py | 8 +-- 3 files changed, 48 insertions(+), 19 deletions(-) diff --git a/eos/saveddata/fit.py b/eos/saveddata/fit.py index 5e40aff80..c6cbd7c0c 100644 --- a/eos/saveddata/fit.py +++ b/eos/saveddata/fit.py @@ -129,10 +129,10 @@ class Fit(object): self.__capRecharge = None self.__calculatedTargets = [] self.__remoteReps = { - "Armor": 0, - "Shield": 0, - "Hull": 0, - "Capacitor": 0, + "Armor": None, + "Shield": None, + "Hull": None, + "Capacitor": None, } self.factorReload = False self.boostsFits = set() @@ -307,6 +307,34 @@ class Fit(object): def totalYield(self): return self.droneYield + self.minerYield + @property + def armorRR(self): + if self.__remoteReps["Armor"] is None: + self.calculateRemoteReps() + + return self.__remoteReps["Armor"] + + @property + def shieldRR(self): + if self.__remoteReps["Shield"] is None: + self.calculateRemoteReps() + + return self.__remoteReps["Shield"] + + @property + def hullRR(self): + if self.__remoteReps["Hull"] is None: + self.calculateRemoteReps() + + return self.__remoteReps["Hull"] + + @property + def capTransfer(self): + if self.__remoteReps["Capacitor"] is None: + self.calculateRemoteReps() + + return self.__remoteReps["Capacitor"] + @property def maxTargets(self): return min(self.extraAttributes["maxTargetsLockedFromSkills"], @@ -400,7 +428,7 @@ class Fit(object): self.commandBonuses = {} for remoterep_type in self.__remoteReps: - self.__remoteReps[remoterep_type] = 0 + self.__remoteReps[remoterep_type] = None del self.__calculatedTargets[:] del self.__extraDrains[:] @@ -1157,8 +1185,7 @@ class Fit(object): self.__capStable = True self.__capState = 100 - @property - def remoteReps(self): + def calculateRemoteReps(self): def amount_per_second(module_amount, module_duration, module_reload, module_chargerate, module_capacity, module_volume): numcycles = math.floor(module_capacity / (module_volume * module_chargerate)) @@ -1167,15 +1194,19 @@ class Fit(object): return module_amount / module_duration + for remoterep_type in self.__remoteReps: + # Set all to 0 + self.__remoteReps[remoterep_type] = 0 + for module in self.modules: # Skip empty modules if module.isEmpty: continue - module_group = getattr(module.item.group, "name") + module_group = module.item.group.name # Skip modules that aren't online - if getattr(module, "state", 0) < 1: + if module.state < State.ACTIVE: continue if module_group in ("Remote Armor Repairer", "Ancillary Remote Armor Repairer"): @@ -1230,8 +1261,6 @@ class Fit(object): self.__remoteReps["Capacitor"] += hp_per_s - return self.__remoteReps - @property def hp(self): hp = {} diff --git a/gui/builtinStatsViews/outgoingViewFull.py b/gui/builtinStatsViews/outgoingViewFull.py index 945edd4fe..3b5240eba 100644 --- a/gui/builtinStatsViews/outgoingViewFull.py +++ b/gui/builtinStatsViews/outgoingViewFull.py @@ -83,10 +83,10 @@ class OutgoingViewFull(StatsView): # If we did anything intresting, we'd update our labels to reflect the new fit's stats here stats = [ - ("labelRemoteArmor", lambda: fit.remoteReps["Armor"], 3, 0, 0, u"%s HP/s", None), - ("labelRemoteShield", lambda: fit.remoteReps["Shield"], 3, 0, 0, u"%s HP/s", None), - ("labelRemoteHull", lambda: fit.remoteReps["Hull"], 3, 0, 0, u"%s HP/s", None), - ("labelRemoteCapacitor", lambda: fit.remoteReps["Capacitor"], 3, 0, 0, u"%s GJ/s", None), + ("labelRemoteArmor", lambda: fit.armorRR, 3, 0, 0, u"%s HP/s", None), + ("labelRemoteShield", lambda: fit.shieldRR, 3, 0, 0, u"%s HP/s", None), + ("labelRemoteHull", lambda: fit.hullRR, 3, 0, 0, u"%s HP/s", None), + ("labelRemoteCapacitor", lambda: fit.capTransfer, 3, 0, 0, u"%s GJ/s", None), ] counter = 0 diff --git a/gui/builtinStatsViews/outgoingViewMinimal.py b/gui/builtinStatsViews/outgoingViewMinimal.py index 945edd4fe..3b5240eba 100644 --- a/gui/builtinStatsViews/outgoingViewMinimal.py +++ b/gui/builtinStatsViews/outgoingViewMinimal.py @@ -83,10 +83,10 @@ class OutgoingViewFull(StatsView): # If we did anything intresting, we'd update our labels to reflect the new fit's stats here stats = [ - ("labelRemoteArmor", lambda: fit.remoteReps["Armor"], 3, 0, 0, u"%s HP/s", None), - ("labelRemoteShield", lambda: fit.remoteReps["Shield"], 3, 0, 0, u"%s HP/s", None), - ("labelRemoteHull", lambda: fit.remoteReps["Hull"], 3, 0, 0, u"%s HP/s", None), - ("labelRemoteCapacitor", lambda: fit.remoteReps["Capacitor"], 3, 0, 0, u"%s GJ/s", None), + ("labelRemoteArmor", lambda: fit.armorRR, 3, 0, 0, u"%s HP/s", None), + ("labelRemoteShield", lambda: fit.shieldRR, 3, 0, 0, u"%s HP/s", None), + ("labelRemoteHull", lambda: fit.hullRR, 3, 0, 0, u"%s HP/s", None), + ("labelRemoteCapacitor", lambda: fit.capTransfer, 3, 0, 0, u"%s GJ/s", None), ] counter = 0 From b3c72736815c2d8332cebd2c56b3681d05e0b8f4 Mon Sep 17 00:00:00 2001 From: Ebag333 Date: Fri, 24 Feb 2017 16:10:54 -0800 Subject: [PATCH 11/19] implement a suggestion or six from @blitzmann. Fix a bunch of low level bugs (unlikely to have been noticed since we don't really expose those stats). Add some properties instead of referencing the attribute directly. --- eos/saveddata/fit.py | 100 ++++++++----------- eos/saveddata/module.py | 75 ++++++++++---- gui/builtinStatsViews/outgoingViewFull.py | 6 +- gui/builtinStatsViews/outgoingViewMinimal.py | 6 +- 4 files changed, 106 insertions(+), 81 deletions(-) diff --git a/eos/saveddata/fit.py b/eos/saveddata/fit.py index 5e40aff80..82dc8b56f 100644 --- a/eos/saveddata/fit.py +++ b/eos/saveddata/fit.py @@ -129,10 +129,10 @@ class Fit(object): self.__capRecharge = None self.__calculatedTargets = [] self.__remoteReps = { - "Armor": 0, - "Shield": 0, - "Hull": 0, - "Capacitor": 0, + "Armor": None, + "Shield": None, + "Hull": None, + "Capacitor": None, } self.factorReload = False self.boostsFits = set() @@ -400,7 +400,7 @@ class Fit(object): self.commandBonuses = {} for remoterep_type in self.__remoteReps: - self.__remoteReps[remoterep_type] = 0 + self.__remoteReps[remoterep_type] = None del self.__calculatedTargets[:] del self.__extraDrains[:] @@ -1159,76 +1159,64 @@ class Fit(object): @property def remoteReps(self): - def amount_per_second(module_amount, module_duration, module_reload, module_chargerate, module_capacity, module_volume): - numcycles = math.floor(module_capacity / (module_volume * module_chargerate)) + force_recalc = False + for remoterep_type in self.__remoteReps: + if self.__remoteReps[remoterep_type] is None: + force_recalc = True + break - module_amount *= numcycles - module_duration = module_chargerate * numcycles + module_reload - - return module_amount / module_duration + if force_recalc is False: + return self.__remoteReps for module in self.modules: # Skip empty modules if module.isEmpty: continue - module_group = getattr(module.item.group, "name") - # Skip modules that aren't online if getattr(module, "state", 0) < 1: continue - if module_group in ("Remote Armor Repairer", "Ancillary Remote Armor Repairer"): - # Remote Armor Reppers - hp = module.getModifiedItemAttr("armorDamageAmount", 0) - duration = module.getModifiedItemAttr("duration", 0) / 1000 - reloadTime = module.getModifiedItemAttr("reloadTime", 0) / 1000 - chargeRate = module.getModifiedItemAttr("chargeRate", 1) - fueledMultiplier = module.getModifiedItemAttr("chargedArmorDamageMultiplier", 1) - capacity = module.getModifiedItemAttr("capacity", 0) - volume = module.getModifiedChargeAttr("volume", 0) + duration = module.cycleTime / 1000 - if module.charge: - hp *= fueledMultiplier - hp_per_s = amount_per_second(hp, duration, reloadTime, chargeRate, capacity, volume) - else: - hp_per_s = hp / duration + # Skip modules with no duration. + if not duration: + continue - self.__remoteReps["Armor"] += hp_per_s + fueledMultiplier = module.getModifiedItemAttr("chargedArmorDamageMultiplier", 1) - elif module_group in ("Remote Hull Repairer",): - # Remote Hull Reppers + remote_module_groups = { + "Remote Armor Repairer" : "Armor", + "Ancillary Remote Armor Repairer": "Armor", + "Remote Hull Repairer" : "Hull", + "Remote Shield Booster" : "Shield", + "Ancillary Remote Shield Booster": "Shield", + "Remote Capacitor Transmitter" : "Capacitor", + } + + module_group = module.item.group.name + + if module_group in remote_module_groups: + remote_type = remote_module_groups[module_group] + else: + # Module isn't in our list of remote rep modules, bail + continue + + if remote_type == "Hull": hp = module.getModifiedItemAttr("structureDamageAmount", 0) - duration = module.getModifiedItemAttr("duration", 0) / 1000 - - hp_per_s = hp / duration - - self.__remoteReps["Hull"] += hp_per_s - - elif module_group in ("Remote Shield Booster", "Ancillary Remote Shield Booster"): - # Remote Shield Reppers + elif remote_type == "Armor": + hp = module.getModifiedItemAttr("armorDamageAmount", 0) + elif remote_type == "Shield": hp = module.getModifiedItemAttr("shieldBonus", 0) - duration = module.getModifiedItemAttr("duration", 0) / 1000 - reloadTime = module.getModifiedItemAttr("reloadTime", 0) / 1000 - chargeRate = module.getModifiedItemAttr("chargeRate", 1) - capacity = module.getModifiedItemAttr("capacity", 0) - volume = module.getModifiedChargeAttr("volume", 0) - - if module.charge: - hp_per_s = amount_per_second(hp, duration, reloadTime, chargeRate, capacity, volume) - else: - hp_per_s = hp / duration - - self.__remoteReps["Shield"] += hp_per_s - - elif module_group in ("Remote Capacitor Transmitter",): - # Remote Capacitor Boosters + elif remote_type == "Capacitor": hp = module.getModifiedItemAttr("powerTransferAmount", 0) - duration = module.getModifiedItemAttr("duration", 0) / 1000 + else: + hp = 0 - hp_per_s = hp / duration + if self.__remoteReps[remote_type] is None: + self.__remoteReps[remote_type] = 0 - self.__remoteReps["Capacitor"] += hp_per_s + self.__remoteReps[remote_type] += (hp * fueledMultiplier) / duration return self.__remoteReps diff --git a/eos/saveddata/module.py b/eos/saveddata/module.py index ba41d559d..1fddabd9d 100644 --- a/eos/saveddata/module.py +++ b/eos/saveddata/module.py @@ -20,6 +20,7 @@ import logging from sqlalchemy.orm import validates, reconstructor +from math import floor import eos.db from eos.effectHandlerHelpers import HandledItem, HandledCharge @@ -172,7 +173,7 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut): if chargeVolume is None or containerCapacity is None: charges = 0 else: - charges = floorFloat(float(containerCapacity) / chargeVolume) + charges = floor(containerCapacity / chargeVolume) return charges @property @@ -216,9 +217,10 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut): def __calculateAmmoShots(self): if self.charge is not None: # Set number of cycles before reload is needed + # numcycles = math.floor(module_capacity / (module_volume * module_chargerate)) chargeRate = self.getModifiedItemAttr("chargeRate") numCharges = self.numCharges - numShots = floorFloat(float(numCharges) / chargeRate) + numShots = floor(numCharges / chargeRate) else: numShots = None return numShots @@ -665,32 +667,67 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut): @property def cycleTime(self): - reactivation = (self.getModifiedItemAttr("moduleReactivationDelay") or 0) - # Reactivation time starts counting after end of module cycle - speed = self.rawCycleTime + reactivation - if self.charge: - reload = self.reloadTime - else: - reload = 0.0 # Determine if we'll take into account reload time or not factorReload = self.owner.factorReload if self.forceReload is None else self.forceReload - # If reactivation is longer than 10 seconds then module can be reloaded - # during reactivation time, thus we may ignore reload - if factorReload and reactivation < reload: - numShots = self.numShots - # Time it takes to reload module after end of reactivation time, - # given that we started when module cycle has just over - additionalReloadTime = (reload - reactivation) - # Speed here already takes into consideration reactivation time - speed = (speed * numShots + additionalReloadTime) / numShots if numShots > 0 else speed + + numShots = self.numShots + speed = self.rawCycleTime + + if factorReload and self.charge: + raw_reload_time = self.reloadTime + else: + raw_reload_time = 0.0 + + # Module can only fire one shot at a time, think bomb launchers or defender launchers + if self.disallowRepeatingAction: + if numShots > 1: + """ + The actual mechanics behind this is complex. Behavior will be (for 3 ammo): + fire, reactivation delay, fire, reactivation delay, fire, max(reactivation delay, reload) + so your effective reload time depends on where you are at in the cycle. + + We can't do that, so instead we'll average it out. + + Currently would apply to bomb launchers and defender missiles + """ + effective_reload_time = ((self.reactivationDelay * numShots) + raw_reload_time) / numShots + else: + """ + Applies to MJD/MJFG + """ + effective_reload_time = max(raw_reload_time, self.reactivationDelay, 0) + else: + """ + Currently no other modules would have a reactivation delay, so for sanities sake don't try and account for it. + """ + effective_reload_time = raw_reload_time + + if numShots > 0 and self.charge: + speed = (speed * numShots + effective_reload_time) / numShots return speed @property def rawCycleTime(self): - speed = self.getModifiedItemAttr("speed") or self.getModifiedItemAttr("duration") + speed = max( + self.getModifiedItemAttr("speed"), # Most weapons + self.getModifiedItemAttr("duration"), # Most average modules + self.getModifiedItemAttr("durationSensorDampeningBurstProjector"), + self.getModifiedItemAttr("durationTargetIlluminationBurstProjector"), + self.getModifiedItemAttr("durationECMJammerBurstProjector"), + self.getModifiedItemAttr("durationWeaponDisruptionBurstProjector"), + 0, # Return 0 if none of the above are valid + ) return speed + @property + def disallowRepeatingAction(self): + return self.getModifiedItemAttr("disallowRepeatingAction", 0) + + @property + def reactivationDelay(self): + return self.getModifiedItemAttr("moduleReactivationDelay", 0) + @property def capUse(self): capNeed = self.getModifiedItemAttr("capacitorNeed") diff --git a/gui/builtinStatsViews/outgoingViewFull.py b/gui/builtinStatsViews/outgoingViewFull.py index 945edd4fe..9e92f2db9 100644 --- a/gui/builtinStatsViews/outgoingViewFull.py +++ b/gui/builtinStatsViews/outgoingViewFull.py @@ -53,10 +53,10 @@ class OutgoingViewFull(StatsView): counter = 0 rr_list = [ - ("RemoteArmor", "Armor:", "armorActive", "Armor hitpoints per second repaired remotely."), - ("RemoteShield", "Shield:", "shieldActive", "Shield hitpoints per second repaired remotely."), - ("RemoteHull", "Hull:", "hullActive", "Hull hitpoints per second repaired remotely."), ("RemoteCapacitor", "Capacitor:", "capacitorInfo", "Capacitor GJ/s per second transferred remotely."), + ("RemoteShield", "Shield:", "shieldActive", "Shield hitpoints per second repaired remotely."), + ("RemoteArmor", "Armor:", "armorActive", "Armor hitpoints per second repaired remotely."), + ("RemoteHull", "Hull:", "hullActive", "Hull hitpoints per second repaired remotely."), ] for outgoingType, label, image, tooltip in rr_list: diff --git a/gui/builtinStatsViews/outgoingViewMinimal.py b/gui/builtinStatsViews/outgoingViewMinimal.py index 945edd4fe..9e92f2db9 100644 --- a/gui/builtinStatsViews/outgoingViewMinimal.py +++ b/gui/builtinStatsViews/outgoingViewMinimal.py @@ -53,10 +53,10 @@ class OutgoingViewFull(StatsView): counter = 0 rr_list = [ - ("RemoteArmor", "Armor:", "armorActive", "Armor hitpoints per second repaired remotely."), - ("RemoteShield", "Shield:", "shieldActive", "Shield hitpoints per second repaired remotely."), - ("RemoteHull", "Hull:", "hullActive", "Hull hitpoints per second repaired remotely."), ("RemoteCapacitor", "Capacitor:", "capacitorInfo", "Capacitor GJ/s per second transferred remotely."), + ("RemoteShield", "Shield:", "shieldActive", "Shield hitpoints per second repaired remotely."), + ("RemoteArmor", "Armor:", "armorActive", "Armor hitpoints per second repaired remotely."), + ("RemoteHull", "Hull:", "hullActive", "Hull hitpoints per second repaired remotely."), ] for outgoingType, label, image, tooltip in rr_list: From 43073069c7461ccbe9d05ea15a056ff78468ec78 Mon Sep 17 00:00:00 2001 From: Ebag333 Date: Fri, 24 Feb 2017 16:25:31 -0800 Subject: [PATCH 12/19] Fix merge conflict. --- eos/saveddata/module.py | 1 + gui/builtinStatsViews/outgoingViewFull.py | 8 ++++---- gui/builtinStatsViews/outgoingViewMinimal.py | 8 ++++---- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/eos/saveddata/module.py b/eos/saveddata/module.py index 1fddabd9d..4735c95c6 100644 --- a/eos/saveddata/module.py +++ b/eos/saveddata/module.py @@ -699,6 +699,7 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut): else: """ Currently no other modules would have a reactivation delay, so for sanities sake don't try and account for it. + Okay, technically cloaks do, but they also have 0 cycle time and cap usage so why do you care? """ effective_reload_time = raw_reload_time diff --git a/gui/builtinStatsViews/outgoingViewFull.py b/gui/builtinStatsViews/outgoingViewFull.py index d18f84678..9e92f2db9 100644 --- a/gui/builtinStatsViews/outgoingViewFull.py +++ b/gui/builtinStatsViews/outgoingViewFull.py @@ -83,10 +83,10 @@ class OutgoingViewFull(StatsView): # If we did anything intresting, we'd update our labels to reflect the new fit's stats here stats = [ - ("labelRemoteArmor", lambda: fit.armorRR, 3, 0, 0, u"%s HP/s", None), - ("labelRemoteShield", lambda: fit.shieldRR, 3, 0, 0, u"%s HP/s", None), - ("labelRemoteHull", lambda: fit.hullRR, 3, 0, 0, u"%s HP/s", None), - ("labelRemoteCapacitor", lambda: fit.capTransfer, 3, 0, 0, u"%s GJ/s", None), + ("labelRemoteArmor", lambda: fit.remoteReps["Armor"], 3, 0, 0, u"%s HP/s", None), + ("labelRemoteShield", lambda: fit.remoteReps["Shield"], 3, 0, 0, u"%s HP/s", None), + ("labelRemoteHull", lambda: fit.remoteReps["Hull"], 3, 0, 0, u"%s HP/s", None), + ("labelRemoteCapacitor", lambda: fit.remoteReps["Capacitor"], 3, 0, 0, u"%s GJ/s", None), ] counter = 0 diff --git a/gui/builtinStatsViews/outgoingViewMinimal.py b/gui/builtinStatsViews/outgoingViewMinimal.py index d18f84678..9e92f2db9 100644 --- a/gui/builtinStatsViews/outgoingViewMinimal.py +++ b/gui/builtinStatsViews/outgoingViewMinimal.py @@ -83,10 +83,10 @@ class OutgoingViewFull(StatsView): # If we did anything intresting, we'd update our labels to reflect the new fit's stats here stats = [ - ("labelRemoteArmor", lambda: fit.armorRR, 3, 0, 0, u"%s HP/s", None), - ("labelRemoteShield", lambda: fit.shieldRR, 3, 0, 0, u"%s HP/s", None), - ("labelRemoteHull", lambda: fit.hullRR, 3, 0, 0, u"%s HP/s", None), - ("labelRemoteCapacitor", lambda: fit.capTransfer, 3, 0, 0, u"%s GJ/s", None), + ("labelRemoteArmor", lambda: fit.remoteReps["Armor"], 3, 0, 0, u"%s HP/s", None), + ("labelRemoteShield", lambda: fit.remoteReps["Shield"], 3, 0, 0, u"%s HP/s", None), + ("labelRemoteHull", lambda: fit.remoteReps["Hull"], 3, 0, 0, u"%s HP/s", None), + ("labelRemoteCapacitor", lambda: fit.remoteReps["Capacitor"], 3, 0, 0, u"%s GJ/s", None), ] counter = 0 From 3411eca1e703b35ced86ab10cfbb29a61d32b498 Mon Sep 17 00:00:00 2001 From: Ebag333 Date: Fri, 24 Feb 2017 16:34:32 -0800 Subject: [PATCH 13/19] Fix a couple pep8 issues, and clean up other folks pep8 misses. :) --- eos/saveddata/fit.py | 1 - eos/saveddata/module.py | 2 +- gui/builtinStatsViews/outgoingViewFull.py | 2 -- gui/builtinStatsViews/outgoingViewMinimal.py | 2 -- service/crest.py | 1 - service/server.py | 1 + 6 files changed, 2 insertions(+), 7 deletions(-) diff --git a/eos/saveddata/fit.py b/eos/saveddata/fit.py index df6652d27..113ff98b5 100644 --- a/eos/saveddata/fit.py +++ b/eos/saveddata/fit.py @@ -18,7 +18,6 @@ # =============================================================================== import time -import math from copy import deepcopy from itertools import chain from math import sqrt, log, asinh diff --git a/eos/saveddata/module.py b/eos/saveddata/module.py index 4735c95c6..55da98d63 100644 --- a/eos/saveddata/module.py +++ b/eos/saveddata/module.py @@ -723,7 +723,7 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut): @property def disallowRepeatingAction(self): - return self.getModifiedItemAttr("disallowRepeatingAction", 0) + return self.getModifiedItemAttr("disallowRepeatingAction", 0) @property def reactivationDelay(self): diff --git a/gui/builtinStatsViews/outgoingViewFull.py b/gui/builtinStatsViews/outgoingViewFull.py index 9e92f2db9..346aacc7a 100644 --- a/gui/builtinStatsViews/outgoingViewFull.py +++ b/gui/builtinStatsViews/outgoingViewFull.py @@ -44,8 +44,6 @@ class OutgoingViewFull(StatsView): parent = self.panel = contentPanel self.headerPanel = headerPanel - panel = "full" - sizerOutgoing = wx.GridSizer(1, 4) contentSizer.Add(sizerOutgoing, 0, wx.EXPAND, 0) diff --git a/gui/builtinStatsViews/outgoingViewMinimal.py b/gui/builtinStatsViews/outgoingViewMinimal.py index 9e92f2db9..346aacc7a 100644 --- a/gui/builtinStatsViews/outgoingViewMinimal.py +++ b/gui/builtinStatsViews/outgoingViewMinimal.py @@ -44,8 +44,6 @@ class OutgoingViewFull(StatsView): parent = self.panel = contentPanel self.headerPanel = headerPanel - panel = "full" - sizerOutgoing = wx.GridSizer(1, 4) contentSizer.Add(sizerOutgoing, 0, wx.EXPAND, 0) diff --git a/service/crest.py b/service/crest.py index bbe8cd1bb..f968df7a3 100644 --- a/service/crest.py +++ b/service/crest.py @@ -1,6 +1,5 @@ # noinspection PyPackageRequirements import wx -import thread import logging import threading import copy diff --git a/service/server.py b/service/server.py index 38ecebfe4..c75892d70 100644 --- a/service/server.py +++ b/service/server.py @@ -55,6 +55,7 @@ else {{ ''' + # https://github.com/fuzzysteve/CREST-Market-Downloader/ class AuthHandler(BaseHTTPServer.BaseHTTPRequestHandler): def do_GET(self): From c24798ad2ffd5abecec41e2d453557d742ab2b80 Mon Sep 17 00:00:00 2001 From: Ebag333 Date: Fri, 24 Feb 2017 17:07:05 -0800 Subject: [PATCH 14/19] Clean up last reference and finish nuking floatfloor. One less method! (ouch my test!) --- eos/mathUtils.py | 31 ------------------------------- eos/saveddata/fit.py | 4 ++-- eos/saveddata/module.py | 3 +-- 3 files changed, 3 insertions(+), 35 deletions(-) delete mode 100644 eos/mathUtils.py diff --git a/eos/mathUtils.py b/eos/mathUtils.py deleted file mode 100644 index 5de12c60f..000000000 --- a/eos/mathUtils.py +++ /dev/null @@ -1,31 +0,0 @@ -# =============================================================================== -# Copyright (C) 2010 Anton Vorobyov -# -# This file is part of eos. -# -# eos is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation, either version 2 of the License, or -# (at your option) any later version. -# -# eos is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with eos. If not, see . -# =============================================================================== - -import decimal - - -def floorFloat(value): - """Round float down to integer""" - # We have to convert float to str to keep compatibility with - # decimal module in python 2.6 - value = str(value) - # Do the conversions for proper rounding down, avoiding float - # representation errors - result = int(decimal.Decimal(value).to_integral_value(rounding=decimal.ROUND_DOWN)) - return result diff --git a/eos/saveddata/fit.py b/eos/saveddata/fit.py index 113ff98b5..de6e8cc58 100644 --- a/eos/saveddata/fit.py +++ b/eos/saveddata/fit.py @@ -1159,8 +1159,8 @@ class Fit(object): @property def remoteReps(self): force_recalc = False - for remoterep_type in self.__remoteReps: - if self.__remoteReps[remoterep_type] is None: + for remote_type in self.__remoteReps: + if self.__remoteReps[remote_type] is None: force_recalc = True break diff --git a/eos/saveddata/module.py b/eos/saveddata/module.py index 55da98d63..a3f85ed5b 100644 --- a/eos/saveddata/module.py +++ b/eos/saveddata/module.py @@ -25,7 +25,6 @@ from math import floor import eos.db from eos.effectHandlerHelpers import HandledItem, HandledCharge from eos.enum import Enum -from eos.mathUtils import floorFloat from eos.modifiedAttributeDict import ModifiedAttributeDict, ItemAttrShortcut, ChargeAttrShortcut from eos.saveddata.citadel import Citadel @@ -233,7 +232,7 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut): chance = self.getModifiedChargeAttr("crystalVolatilityChance") damage = self.getModifiedChargeAttr("crystalVolatilityDamage") crystals = self.numCharges - numShots = floorFloat(float(crystals * hp) / (damage * chance)) + numShots = floor((crystals * hp) / (damage * chance)) else: # Set 0 (infinite) for permanent crystals like t1 laser crystals numShots = 0 From e4d0f2dc6f5e07637a9e0ae033faf92fdd8d00f4 Mon Sep 17 00:00:00 2001 From: Ebag333 Date: Sun, 26 Feb 2017 08:46:23 -0800 Subject: [PATCH 15/19] Fix case where property gets reran multiple times. --- eos/saveddata/fit.py | 7 ++++--- service/crest.py | 1 - 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/eos/saveddata/fit.py b/eos/saveddata/fit.py index b46a2aa6c..aa92ff21a 100644 --- a/eos/saveddata/fit.py +++ b/eos/saveddata/fit.py @@ -1171,6 +1171,10 @@ class Fit(object): if force_recalc is False: return self.__remoteReps + # We are rerunning the recalcs. Explicitly set to 0 to make sure we don't duplicate anything and correctly set all values to 0. + for remote_type in self.__remoteReps: + self.__remoteReps[remote_type] = 0 + for module in self.modules: # Skip empty and non-Active modules if module.isEmpty or module.state < State.ACTIVE: @@ -1213,9 +1217,6 @@ class Fit(object): else: hp = 0 - if self.__remoteReps[remote_type] is None: - self.__remoteReps[remote_type] = 0 - self.__remoteReps[remote_type] += (hp * fueledMultiplier) / duration return self.__remoteReps diff --git a/service/crest.py b/service/crest.py index 8ef51ac3a..27f5b6c5e 100644 --- a/service/crest.py +++ b/service/crest.py @@ -1,7 +1,6 @@ # noinspection PyPackageRequirements import wx from logbook import Logger -import logging import threading import copy import uuid From 7eb193cbbb016a75263a0b84f591c37035f59c38 Mon Sep 17 00:00:00 2001 From: Ebag333 Date: Sun, 26 Feb 2017 08:52:27 -0800 Subject: [PATCH 16/19] Delete test, the method being tested no longer exists. --- tests/test_modules/eos/test_mathUtils.py | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 tests/test_modules/eos/test_mathUtils.py diff --git a/tests/test_modules/eos/test_mathUtils.py b/tests/test_modules/eos/test_mathUtils.py deleted file mode 100644 index c5cf2b0bb..000000000 --- a/tests/test_modules/eos/test_mathUtils.py +++ /dev/null @@ -1,12 +0,0 @@ -from eos.mathUtils import floorFloat - - -def test_floorFloat(): - assert type(floorFloat(1)) is not float - assert type(floorFloat(1)) is int - assert type(floorFloat(1.1)) is not float - assert type(floorFloat(1.1)) is int - assert floorFloat(1.1) == 1 - assert floorFloat(1.9) == 1 - assert floorFloat(1.5) == 1 - assert floorFloat(-1.5) == -2 From fc45cef834d1ff58eda74678faa8db38e5575fc5 Mon Sep 17 00:00:00 2001 From: blitzman Date: Sun, 26 Feb 2017 12:56:31 -0500 Subject: [PATCH 17/19] Change order of RR pane --- gui/statsPane.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gui/statsPane.py b/gui/statsPane.py index c86786f97..36c5c86be 100644 --- a/gui/statsPane.py +++ b/gui/statsPane.py @@ -32,8 +32,8 @@ from gui.pyfatogglepanel import TogglePanel class StatsPane(wx.Panel): DEFAULT_VIEWS = ["resourcesViewFull", "resistancesViewFull", "rechargeViewFull", "firepowerViewFull", - "capacitorViewFull", "targetingmiscViewFull", - "priceViewFull", "outgoingViewFull"] + "outgoingViewFull", "capacitorViewFull", "targetingmiscViewFull", + "priceViewFull"] def fitChanged(self, event): sFit = Fit.getInstance() From b235dddbe006cd4ec2514060c4620081b7150961 Mon Sep 17 00:00:00 2001 From: blitzman Date: Sun, 26 Feb 2017 13:31:56 -0500 Subject: [PATCH 18/19] Clean up to the sorting of implants and bosoters --- gui/builtinContextMenus/metaSwap.py | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/gui/builtinContextMenus/metaSwap.py b/gui/builtinContextMenus/metaSwap.py index 7e2f8edf7..c9fe12be6 100644 --- a/gui/builtinContextMenus/metaSwap.py +++ b/gui/builtinContextMenus/metaSwap.py @@ -58,6 +58,17 @@ class MetaSwap(ContextMenu): def get_metagroup(x): return x.metaGroup.ID if x.metaGroup is not None else 0 + def get_boosterrank(x): + # If we're returning a lot of items, sort my name + if len(self.variations) > 7: + return x.name + # Sort by booster chance to get some sort of pseudorank. + elif 'boosterEffectChance1' in x.attributes: + return x.attributes['boosterEffectChance1'].value + # the "first" rank (Synth) doesn't have boosterEffectChance1. If we're not pulling back all boosters, return 0 for proper sorting + else: + return 0 + m = wx.Menu() # If on Windows we need to bind out events into the root menu, on other @@ -69,8 +80,17 @@ class MetaSwap(ContextMenu): # Sort items by metalevel, and group within that metalevel items = list(self.variations) - items.sort(key=get_metalevel) - items.sort(key=get_metagroup) + print context + if "implantItem" in context: + # sort implants based on name + items.sort(key=lambda x: x.name) + elif "boosterItem" in context: + # boosters don't have meta or anything concrete that we can rank by. Go by chance to inflict side effect + items.sort(key=get_boosterrank) + else: + # sort by group and meta level + items.sort(key=get_metalevel) + items.sort(key=get_metagroup) group = None for item in items: @@ -80,7 +100,7 @@ class MetaSwap(ContextMenu): else: thisgroup = item.metaGroup.name - if thisgroup != group: + if thisgroup != group and context not in ("implantItem", "boosterItem"): group = thisgroup id = ContextMenu.nextID() m.Append(id, u'─ %s ─' % group) From 1826122381eed36f8d517139c042d2e9bf74c8e8 Mon Sep 17 00:00:00 2001 From: blitzman Date: Sun, 26 Feb 2017 14:17:46 -0500 Subject: [PATCH 19/19] Clean up some syntax (use isinstance) and tox stuff --- eos/db/gamedata/queries.py | 1 - gui/builtinContextMenus/cargoAmmo.py | 1 + gui/builtinContextMenus/droneStack.py | 1 + gui/builtinContextMenus/metaSwap.py | 17 ++++++++++------- service/market.py | 4 ++-- 5 files changed, 14 insertions(+), 10 deletions(-) diff --git a/eos/db/gamedata/queries.py b/eos/db/gamedata/queries.py index 5f6cca32e..673f1767f 100644 --- a/eos/db/gamedata/queries.py +++ b/eos/db/gamedata/queries.py @@ -276,7 +276,6 @@ def getVariations(itemids, groupIDs=None, where=None, eager=None): return vars - @cachedQuery(1, "attr") def getAttributeInfo(attr, eager=None): if isinstance(attr, basestring): diff --git a/gui/builtinContextMenus/cargoAmmo.py b/gui/builtinContextMenus/cargoAmmo.py index 6b1233164..573e4c24f 100644 --- a/gui/builtinContextMenus/cargoAmmo.py +++ b/gui/builtinContextMenus/cargoAmmo.py @@ -31,4 +31,5 @@ class CargoAmmo(ContextMenu): self.mainFrame.additionsPane.select("Cargo") wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) + CargoAmmo.register() diff --git a/gui/builtinContextMenus/droneStack.py b/gui/builtinContextMenus/droneStack.py index 687f94906..b7fde1040 100644 --- a/gui/builtinContextMenus/droneStack.py +++ b/gui/builtinContextMenus/droneStack.py @@ -33,4 +33,5 @@ class CargoAmmo(ContextMenu): self.mainFrame.additionsPane.select("Drones") wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) + CargoAmmo.register() diff --git a/gui/builtinContextMenus/metaSwap.py b/gui/builtinContextMenus/metaSwap.py index c9fe12be6..771e94df3 100644 --- a/gui/builtinContextMenus/metaSwap.py +++ b/gui/builtinContextMenus/metaSwap.py @@ -8,6 +8,11 @@ from service.market import Market import gui.mainFrame import gui.globalEvents as GE from gui.contextMenu import ContextMenu +from eos.saveddata.booster import Booster +from eos.saveddata.module import Module +from eos.saveddata.drone import Drone +from eos.saveddata.fighter import Fighter +from eos.saveddata.implant import Implant class MetaSwap(ContextMenu): @@ -124,13 +129,12 @@ class MetaSwap(ContextMenu): fit = sFit.getFit(fitID) for selected_item in self.selection: - if type(selected_item).__name__== 'Module': + if isinstance(selected_item, Module): pos = fit.modules.index(selected_item) sFit.changeModule(fitID, pos, item.ID) - elif type(selected_item).__name__== 'Drone': + elif isinstance(selected_item, Drone): drone_count = None - drone_index = None for idx, drone_stack in enumerate(fit.drones): if drone_stack is selected_item: @@ -141,9 +145,8 @@ class MetaSwap(ContextMenu): if drone_count: sFit.addDrone(fitID, item.ID, drone_count) - elif type(selected_item).__name__== 'Fighter': + elif isinstance(selected_item, Fighter): fighter_count = None - fighter_index = None for idx, fighter_stack in enumerate(fit.fighters): # Right now fighters always will have max stack size. @@ -162,14 +165,14 @@ class MetaSwap(ContextMenu): sFit.addFighter(fitID, item.ID) - elif type(selected_item).__name__== 'Booster': + elif isinstance(selected_item, Booster): for idx, booster_stack in enumerate(fit.boosters): if booster_stack is selected_item: sFit.removeBooster(fitID, idx) sFit.addBooster(fitID, item.ID) break - elif type(selected_item).__name__== 'Implant': + elif isinstance(selected_item, Implant): for idx, implant_stack in enumerate(fit.implants): if implant_stack is selected_item: sFit.removeImplant(fitID, idx) diff --git a/service/market.py b/service/market.py index 925cbf9b4..e311c94e5 100644 --- a/service/market.py +++ b/service/market.py @@ -616,13 +616,13 @@ class Market(object): implant_remove_list.add("Strong ") implant_remove_list.add("Synth ") - for implant_prefix in ("-6","-7","-8","-9","-10"): + for implant_prefix in ("-6", "-7", "-8", "-9", "-10"): for i in range(50): implant_remove_list.add(implant_prefix + str("%02d" % i)) for text_to_remove in implant_remove_list: if text_to_remove in item.name: - variations_limiter.add(item.name.replace(text_to_remove,"")) + variations_limiter.add(item.name.replace(text_to_remove, "")) # Get parent item if alreadyparent is False: