From c64991fb59e4593fb7788e325c549cacbf49c97e Mon Sep 17 00:00:00 2001 From: PhatPhuckDave Date: Wed, 21 Jan 2026 11:11:07 +0100 Subject: [PATCH] Add a "per second" column to some rep modules Because some have different cycle times, easier to compare --- gui/builtinItemStatsViews/itemCompare.py | 136 +++++++++++++++++++++-- 1 file changed, 124 insertions(+), 12 deletions(-) diff --git a/gui/builtinItemStatsViews/itemCompare.py b/gui/builtinItemStatsViews/itemCompare.py index 87346e482..b0cdee794 100644 --- a/gui/builtinItemStatsViews/itemCompare.py +++ b/gui/builtinItemStatsViews/itemCompare.py @@ -9,6 +9,46 @@ from gui.utils.numberFormatter import formatAmount _t = wx.GetTranslation +# Mapping of repair/transfer amount attributes to their duration attribute and display name +PER_SECOND_ATTRIBUTES = { + "armorDamageAmount": { + "durationAttr": "duration", + "displayName": "Armor Hitpoints Repaired per second", + "unit": "HP/s" + }, + "shieldBonus": { + "durationAttr": "duration", + "displayName": "Shield Hitpoints Repaired per second", + "unit": "HP/s" + }, + "powerTransferAmount": { + "durationAttr": "duration", + "displayName": "Capacitor Transferred per second", + "unit": "GJ/s" + } +} + + +class PerSecondAttributeInfo: + """Helper class to store info about computed per-second attributes""" + def __init__(self, displayName, unit): + self.displayName = displayName + self.unit = PerSecondUnit(unit) + + +class PerSecondUnit: + """Helper class to mimic the Unit class for per-second attributes""" + def __init__(self, displayName): + self.displayName = displayName + self.name = "" + + +class PerSecondAttributeValue: + """Helper class to store computed per-second attribute values""" + def __init__(self, value): + self.value = value + self.info = None # Will be set when adding to attrs + def defaultSort(item): return (item.metaLevel or 0, item.name) @@ -36,6 +76,7 @@ class ItemCompare(wx.Panel): self.item = item self.items = sorted(items, key=defaultSort) self.attrs = {} + self.computedAttrs = {} # Store computed per-second attributes self.HighlightOn = wx.Colour(255, 255, 0, wx.ALPHA_OPAQUE) self.highlightedNames = [] @@ -45,23 +86,66 @@ class ItemCompare(wx.Panel): if item.attributes[attr].info.displayName: self.attrs[attr] = item.attributes[attr].info + # Compute per-second attributes for items that have both the amount and duration + for perSecondKey, config in PER_SECOND_ATTRIBUTES.items(): + amountAttr = perSecondKey + durationAttr = config["durationAttr"] + perSecondAttrName = f"{perSecondKey}_per_second" + + # Check if any item has both attributes + hasPerSecondAttr = False + for item in self.items: + if amountAttr in item.attributes and durationAttr in item.attributes: + hasPerSecondAttr = True + break + + if hasPerSecondAttr: + # Add the per-second attribute info to attrs + perSecondInfo = PerSecondAttributeInfo(config["displayName"], config["unit"]) + self.attrs[perSecondAttrName] = perSecondInfo + self.computedAttrs[perSecondAttrName] = { + "amountAttr": amountAttr, + "durationAttr": durationAttr + } + # Process attributes for items and find ones that differ for attr in list(self.attrs.keys()): value = None for item in self.items: - # we can automatically break here if this item doesn't have the attribute, - # as that means at least one item did - if attr not in item.attributes: - break + # Check if this is a computed attribute + if attr in self.computedAttrs: + computed = self.computedAttrs[attr] + amountAttr = computed["amountAttr"] + durationAttr = computed["durationAttr"] - # this is the first attribute for the item set, set the initial value - if value is None: - value = item.attributes[attr].value - continue + # Item needs both attributes to compute per-second value + if amountAttr not in item.attributes or durationAttr not in item.attributes: + break - if attr not in item.attributes or item.attributes[attr].value != value: - break + # Calculate per-second value + amountValue = item.attributes[amountAttr].value + durationValue = item.attributes[durationAttr].value + # Duration is in milliseconds, convert to seconds + perSecondValue = amountValue / (durationValue / 1000.0) if durationValue > 0 else 0 + + if value is None: + value = perSecondValue + continue + + if perSecondValue != value: + break + else: + # Regular attribute handling + if attr not in item.attributes: + break + + if value is None: + value = item.attributes[attr].value + continue + + if item.attributes[attr].value != value: + break else: # attribute values were all the same, delete del self.attrs[attr] @@ -148,7 +232,14 @@ class ItemCompare(wx.Panel): # Remember to reduce by 1, because the attrs array # starts at 0 while the list has the item name as column 0. attr = str(list(self.attrs.keys())[sort - 1]) - func = lambda _val: _val.attributes[attr].value if attr in _val.attributes else 0.0 + # Handle computed attributes for sorting + if attr in self.computedAttrs: + computed = self.computedAttrs[attr] + amountAttr = computed["amountAttr"] + durationAttr = computed["durationAttr"] + func = lambda _val: (_val.attributes[amountAttr].value / (_val.attributes[durationAttr].value / 1000.0)) if (amountAttr in _val.attributes and durationAttr in _val.attributes and _val.attributes[durationAttr].value > 0) else 0.0 + else: + func = lambda _val: _val.attributes[attr].value if attr in _val.attributes else 0.0 # Clicked on a column that's not part of our array (price most likely) except IndexError: # Price @@ -177,7 +268,28 @@ class ItemCompare(wx.Panel): for item in self.items: i = self.paramList.InsertItem(self.paramList.GetItemCount(), item.name) for x, attr in enumerate(self.attrs.keys()): - if attr in item.attributes: + # Handle computed attributes + if attr in self.computedAttrs: + computed = self.computedAttrs[attr] + amountAttr = computed["amountAttr"] + durationAttr = computed["durationAttr"] + + # Item needs both attributes to display per-second value + if amountAttr in item.attributes and durationAttr in item.attributes: + amountValue = item.attributes[amountAttr].value + durationValue = item.attributes[durationAttr].value + # Duration is in milliseconds, convert to seconds + perSecondValue = amountValue / (durationValue / 1000.0) if durationValue > 0 else 0 + + info = self.attrs[attr] + if self.toggleView == 1: + valueUnit = formatAmount(perSecondValue, 3, 0, 0) + " " + info.unit.displayName + else: + valueUnit = str(perSecondValue) + + self.paramList.SetItem(i, x + 1, valueUnit) + # else: leave cell empty + elif attr in item.attributes: info = self.attrs[attr] value = item.attributes[attr].value if self.toggleView != 1: