From b3c72736815c2d8332cebd2c56b3681d05e0b8f4 Mon Sep 17 00:00:00 2001 From: Ebag333 Date: Fri, 24 Feb 2017 16:10:54 -0800 Subject: [PATCH] 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: