diff --git a/eos/capSim.py b/eos/capSim.py index d57567ae6..3a2f965c3 100644 --- a/eos/capSim.py +++ b/eos/capSim.py @@ -71,7 +71,7 @@ class CapSimulator(object): disable_period = False # Loop over modules, clearing clipSize if applicable, and group modules based on attributes - for (duration, capNeed, clipSize, disableStagger) in self.modules: + for (duration, capNeed, clipSize, disableStagger, reloadTime) in self.modules: if self.scale: duration, capNeed = self.scale_activation(duration, capNeed) @@ -79,24 +79,25 @@ class CapSimulator(object): # a cap booster module. if not self.reload and capNeed > 0: clipSize = 0 + reloadTime = 0 # Group modules based on their properties - if (duration, capNeed, clipSize, disableStagger) in mods: - mods[(duration, capNeed, clipSize, disableStagger)] += 1 + if (duration, capNeed, clipSize, disableStagger, reloadTime) in mods: + mods[(duration, capNeed, clipSize, disableStagger, reloadTime)] += 1 else: - mods[(duration, capNeed, clipSize, disableStagger)] = 1 + mods[(duration, capNeed, clipSize, disableStagger, reloadTime)] = 1 # Loop over grouped modules, configure staggering and push to the simulation state - for (duration, capNeed, clipSize, disableStagger), amount in mods.iteritems(): + for (duration, capNeed, clipSize, disableStagger, reloadTime), amount in mods.iteritems(): if self.stagger and not disableStagger: if clipSize == 0: duration = int(duration / amount) else: - stagger_amount = (duration * clipSize + 10000) / (amount * clipSize) + stagger_amount = (duration * clipSize + reloadTime) / (amount * clipSize) for i in range(1, amount): heapq.heappush(self.state, [i * stagger_amount, duration, - capNeed, 0, clipSize]) + capNeed, 0, clipSize, reloadTime]) else: capNeed *= amount @@ -106,7 +107,7 @@ class CapSimulator(object): if clipSize: disable_period = True - heapq.heappush(self.state, [0, duration, capNeed, 0, clipSize]) + heapq.heappush(self.state, [0, duration, capNeed, 0, clipSize, reloadTime]) if disable_period: self.period = self.t_max @@ -143,7 +144,7 @@ class CapSimulator(object): while 1: activation = pop(state) - t_now, duration, capNeed, shot, clipSize = activation + t_now, duration, capNeed, shot, clipSize, reloadTime = activation if t_now >= t_max: break @@ -179,7 +180,7 @@ class CapSimulator(object): if clipSize: if shot % clipSize == 0: shot = 0 - t_now += 10000 # include reload time + t_now += reloadTime # include reload time activation[0] = t_now activation[3] = shot diff --git a/eos/effects/doomsdaybeamdot.py b/eos/effects/doomsdaybeamdot.py new file mode 100644 index 000000000..fff941579 --- /dev/null +++ b/eos/effects/doomsdaybeamdot.py @@ -0,0 +1,9 @@ +# doomsdayBeamDOT +# +# Used by: +# Module: Lance type modules +type = "active" + + +def handler(fit, src, context): + pass diff --git a/eos/effects/doomsdayconedot.py b/eos/effects/doomsdayconedot.py new file mode 100644 index 000000000..3e92fb8f6 --- /dev/null +++ b/eos/effects/doomsdayconedot.py @@ -0,0 +1,9 @@ +# doomsdayConeDOT +# +# Used by: +# Module: Bosonic Field Generator +type = "active" + + +def handler(fit, src, context): + pass diff --git a/eos/effects/doomsdayhog.py b/eos/effects/doomsdayhog.py new file mode 100644 index 000000000..182d0c29f --- /dev/null +++ b/eos/effects/doomsdayhog.py @@ -0,0 +1,9 @@ +# doomsdayHOG +# +# Used by: +# Module: GTFO - Gravitational Transportation Field Oscillator +type = "active" + + +def handler(fit, src, context): + pass diff --git a/eos/effects/doomsdayslash.py b/eos/effects/doomsdayslash.py new file mode 100644 index 000000000..e6b55ede9 --- /dev/null +++ b/eos/effects/doomsdayslash.py @@ -0,0 +1,9 @@ +# doomsdaySlash +# +# Used by: +# Module: Reaper type modules +type = "active" + + +def handler(fit, src, context): + pass diff --git a/eos/effects/microjumpportaldrive.py b/eos/effects/microjumpportaldrive.py new file mode 100644 index 000000000..40925b491 --- /dev/null +++ b/eos/effects/microjumpportaldrive.py @@ -0,0 +1,9 @@ +# microJumpPortalDrive +# +# Used by: +# Module: MJFG - Micro Jump Field Generator (used on command destroyers) +type = "active" + + +def handler(fit, src, context): + pass diff --git a/eos/effects/usemissiles.py b/eos/effects/usemissiles.py index d77c56e3e..57a58372b 100644 --- a/eos/effects/usemissiles.py +++ b/eos/effects/usemissiles.py @@ -15,12 +15,13 @@ def handler(fit, src, context): if src.item.group.name == 'Missile Launcher Bomb': # Bomb Launcher Cooldown Timer moduleReactivationDelay = src.getModifiedItemAttr("moduleReactivationDelay") + speed = src.getModifiedItemAttr("speed") # Void and Focused Void Bombs neutAmount = src.getModifiedChargeAttr("energyNeutralizerAmount") - if moduleReactivationDelay and neutAmount: - fit.addDrain(src, moduleReactivationDelay, neutAmount, 0) + if moduleReactivationDelay and neutAmount and speed: + fit.addDrain(src, speed + moduleReactivationDelay, neutAmount, 0) # Lockbreaker Bombs ecmStrengthBonus = src.getModifiedChargeAttr("scan{0}StrengthBonus".format(fit.scanType)) diff --git a/eos/saveddata/character.py b/eos/saveddata/character.py index 1f911f57f..3c0e629d1 100644 --- a/eos/saveddata/character.py +++ b/eos/saveddata/character.py @@ -121,8 +121,12 @@ class Character(object): def apiUpdateCharSheet(self, skills, secStatus=0): for skillRow in skills: - skill = self.getSkill(int(skillRow["typeID"])) - skill.setLevel(int(skillRow["level"]), persist=True, ignoreRestrict=True) + try: + skill = self.getSkill(int(skillRow["typeID"])) + skill.setLevel(int(skillRow["level"]), persist=True, ignoreRestrict=True) + except: + # if setting a skill doesn't work, it's not the end of the world, just quietly pass + pass self.secStatus = secStatus diff --git a/eos/saveddata/fit.py b/eos/saveddata/fit.py index efb094966..67fb1f28e 100644 --- a/eos/saveddata/fit.py +++ b/eos/saveddata/fit.py @@ -1186,7 +1186,7 @@ class Fit(object): rechargeRate = self.ship.getModifiedItemAttr("shieldRechargeRate") / 1000.0 return 10 / rechargeRate * sqrt(percent) * (1 - sqrt(percent)) * capacity - def addDrain(self, src, cycleTime, capNeed, clipSize=0): + def addDrain(self, src, cycleTime, capNeed, clipSize=0, reloadTime=0): """ Used for both cap drains and cap fills (fills have negative capNeed) """ energyNeutralizerSignatureResolution = src.getModifiedItemAttr("energyNeutralizerSignatureResolution") @@ -1196,7 +1196,7 @@ class Fit(object): if energyNeutralizerSignatureResolution: capNeed = capNeed * min(1, signatureRadius / energyNeutralizerSignatureResolution) - self.__extraDrains.append((cycleTime, capNeed, clipSize)) + self.__extraDrains.append((cycleTime, capNeed, clipSize, reloadTime)) def removeDrain(self, i): del self.__extraDrains[i] @@ -1214,6 +1214,7 @@ class Fit(object): cycleTime = mod.rawCycleTime or 0 reactivationTime = mod.getModifiedItemAttr("moduleReactivationDelay") or 0 fullCycleTime = cycleTime + reactivationTime + reloadTime = mod.reloadTime if fullCycleTime > 0: capNeed = mod.capUse if capNeed > 0: @@ -1225,11 +1226,11 @@ class Fit(object): disableStagger = mod.hardpoint == Hardpoint.TURRET drains.append((int(fullCycleTime), mod.getModifiedItemAttr("capacitorNeed") or 0, - mod.numShots or 0, disableStagger)) + mod.numShots or 0, disableStagger, reloadTime)) - for fullCycleTime, capNeed, clipSize in self.iterDrains(): + for fullCycleTime, capNeed, clipSize, reloadTime in self.iterDrains(): # Stagger incoming effects for cap simulation - drains.append((int(fullCycleTime), capNeed, clipSize, False)) + drains.append((int(fullCycleTime), capNeed, clipSize, False, reloadTime)) if capNeed > 0: capUsed += capNeed / (fullCycleTime / 1000.0) else: diff --git a/eos/saveddata/module.py b/eos/saveddata/module.py index 17917287d..ced03eb45 100644 --- a/eos/saveddata/module.py +++ b/eos/saveddata/module.py @@ -339,8 +339,15 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut): volley *= self.getModifiedItemAttr("damageMultiplier") or 1 if volley: cycleTime = self.cycleTime + # Some weapons repeat multiple times in one cycle (think doomsdays) + # Get the number of times it fires off + weaponDoT = max( + self.getModifiedItemAttr("doomsdayDamageDuration", 1) / self.getModifiedItemAttr("doomsdayDamageCycleTime", 1), + 1 + ) + self.__volley = volley - self.__dps = volley / (cycleTime / 1000.0) + self.__dps = (volley * weaponDoT) / (cycleTime / 1000.0) return self.__dps, self.__volley @@ -713,7 +720,7 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut): # Module can only fire one shot at a time, think bomb launchers or defender launchers if self.disallowRepeatingAction: - if numShots > 1: + if numShots > 0: """ The actual mechanics behind this is complex. Behavior will be (for 3 ammo): fire, reactivation delay, fire, reactivation delay, fire, max(reactivation delay, reload) @@ -723,12 +730,13 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut): Currently would apply to bomb launchers and defender missiles """ - effective_reload_time = ((self.reactivationDelay * (numShots - 1)) + max(raw_reload_time, self.reactivationDelay, 0)) / numShots + effective_reload_time = ((self.reactivationDelay * (numShots - 1)) + max(raw_reload_time, self.reactivationDelay, 0)) else: """ Applies to MJD/MJFG """ effective_reload_time = max(raw_reload_time, self.reactivationDelay, 0) + speed = speed + effective_reload_time else: """ Currently no other modules would have a reactivation delay, so for sanities sake don't try and account for it. diff --git a/gui/builtinViewColumns/misc.py b/gui/builtinViewColumns/misc.py index e99e89eae..a3c84b4a7 100644 --- a/gui/builtinViewColumns/misc.py +++ b/gui/builtinViewColumns/misc.py @@ -76,6 +76,31 @@ class Miscellanea(ViewColumn): stuff.getModifiedItemAttr("boosterDuration") text = "{0} min".format(formatAmount(stuff.getModifiedItemAttr("boosterDuration") / 1000 / 60, 3, 0, 3)) return text, "Booster Duration" + elif itemGroup in ("Super Weapon", "Structure Doomsday Weapon"): + doomsday_duration = stuff.getModifiedItemAttr("doomsdayDamageDuration", 1) + doomsday_dottime = stuff.getModifiedItemAttr("doomsdayDamageCycleTime", 1) + func = stuff.getModifiedItemAttr + + volley = sum( + map( + lambda attr: (func("%sDamage" % attr) or 0), + ("em", "thermal", "kinetic", "explosive") + ) + ) + volley *= stuff.getModifiedItemAttr("damageMultiplier") or 1 + + if volley <= 0: + text = "" + tooltip = "" + elif max(doomsday_duration / doomsday_dottime, 1) > 1: + text = "{0} dmg over {1} s".format(formatAmount(volley * (doomsday_duration / doomsday_dottime), 3, 0, 3), doomsday_duration / 1000) + tooltip = "Raw damage done over time" + else: + text = "{0} dmg".format(formatAmount(volley * (doomsday_duration / doomsday_dottime), 3, 0, 3)) + tooltip = "Raw damage done" + return text, tooltip + + pass elif itemGroup in ("Energy Weapon", "Hybrid Weapon", "Projectile Weapon", "Combat Drone", "Fighter Drone"): trackingSpeed = stuff.getModifiedItemAttr("trackingSpeed") if not trackingSpeed: