Implement module cycle parameters logic for modules
This commit is contained in:
@@ -186,7 +186,7 @@ class Drone(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
|
|||||||
rrAmount = 0
|
rrAmount = 0
|
||||||
if rrAmount:
|
if rrAmount:
|
||||||
droneAmount = self.amount if ignoreState else self.amountActive
|
droneAmount = self.amount if ignoreState else self.amountActive
|
||||||
rrAmount *= droneAmount / (self.cycleTime / 1000)
|
rrAmount *= droneAmount / (self.cycleParameters.averageTime / 1000)
|
||||||
self.__baseRemoteReps = (rrType, rrAmount)
|
self.__baseRemoteReps = (rrType, rrAmount)
|
||||||
return self.__baseRemoteReps
|
return self.__baseRemoteReps
|
||||||
|
|
||||||
|
|||||||
@@ -17,21 +17,22 @@
|
|||||||
# along with eos. If not, see <http://www.gnu.org/licenses/>.
|
# along with eos. If not, see <http://www.gnu.org/licenses/>.
|
||||||
# ===============================================================================
|
# ===============================================================================
|
||||||
|
|
||||||
from math import floor
|
|
||||||
|
|
||||||
from logbook import Logger
|
from logbook import Logger
|
||||||
|
import math
|
||||||
from sqlalchemy.orm import reconstructor, validates
|
from sqlalchemy.orm import reconstructor, validates
|
||||||
|
|
||||||
import eos.db
|
import eos.db
|
||||||
from eos.const import FittingModuleState, FittingHardpoint, FittingSlot
|
from eos.const import FittingHardpoint, FittingModuleState, FittingSlot
|
||||||
from eos.effectHandlerHelpers import HandledCharge, HandledItem
|
from eos.effectHandlerHelpers import HandledCharge, HandledItem
|
||||||
from eos.modifiedAttributeDict import ChargeAttrShortcut, ItemAttrShortcut, ModifiedAttributeDict
|
from eos.modifiedAttributeDict import ChargeAttrShortcut, ItemAttrShortcut, ModifiedAttributeDict
|
||||||
from eos.saveddata.citadel import Citadel
|
from eos.saveddata.citadel import Citadel
|
||||||
from eos.saveddata.mutator import Mutator
|
from eos.saveddata.mutator import Mutator
|
||||||
|
from eos.utils.cycles import CycleInfo, CycleSequence
|
||||||
from eos.utils.float import floatUnerr
|
from eos.utils.float import floatUnerr
|
||||||
from eos.utils.spoolSupport import calculateSpoolup, resolveSpoolOptions
|
from eos.utils.spoolSupport import calculateSpoolup, resolveSpoolOptions
|
||||||
from eos.utils.stats import DmgTypes
|
from eos.utils.stats import DmgTypes
|
||||||
|
|
||||||
|
|
||||||
pyfalog = Logger(__name__)
|
pyfalog = Logger(__name__)
|
||||||
|
|
||||||
ProjectedMap = {
|
ProjectedMap = {
|
||||||
@@ -287,7 +288,7 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
|
|||||||
# numcycles = math.floor(module_capacity / (module_volume * module_chargerate))
|
# numcycles = math.floor(module_capacity / (module_volume * module_chargerate))
|
||||||
chargeRate = self.getModifiedItemAttr("chargeRate")
|
chargeRate = self.getModifiedItemAttr("chargeRate")
|
||||||
numCharges = self.numCharges
|
numCharges = self.numCharges
|
||||||
numShots = floor(numCharges / chargeRate)
|
numShots = math.floor(numCharges / chargeRate)
|
||||||
else:
|
else:
|
||||||
numShots = None
|
numShots = None
|
||||||
return numShots
|
return numShots
|
||||||
@@ -300,7 +301,7 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
|
|||||||
chance = self.getModifiedChargeAttr("crystalVolatilityChance")
|
chance = self.getModifiedChargeAttr("crystalVolatilityChance")
|
||||||
damage = self.getModifiedChargeAttr("crystalVolatilityDamage")
|
damage = self.getModifiedChargeAttr("crystalVolatilityDamage")
|
||||||
crystals = self.numCharges
|
crystals = self.numCharges
|
||||||
numShots = floor((crystals * hp) / (damage * chance))
|
numShots = math.floor((crystals * hp) / (damage * chance))
|
||||||
else:
|
else:
|
||||||
# Set 0 (infinite) for permanent crystals like t1 laser crystals
|
# Set 0 (infinite) for permanent crystals like t1 laser crystals
|
||||||
numShots = 0
|
numShots = 0
|
||||||
@@ -400,7 +401,7 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
|
|||||||
volley = self.getModifiedItemAttr("specialtyMiningAmount") or self.getModifiedItemAttr(
|
volley = self.getModifiedItemAttr("specialtyMiningAmount") or self.getModifiedItemAttr(
|
||||||
"miningAmount") or 0
|
"miningAmount") or 0
|
||||||
if volley:
|
if volley:
|
||||||
cycleTime = self.cycleTime
|
cycleTime = self.cycleParameters.averageTime
|
||||||
self.__miningyield = volley / (cycleTime / 1000.0)
|
self.__miningyield = volley / (cycleTime / 1000.0)
|
||||||
else:
|
else:
|
||||||
self.__miningyield = 0
|
self.__miningyield = 0
|
||||||
@@ -439,7 +440,7 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
|
|||||||
return DmgTypes(0, 0, 0, 0)
|
return DmgTypes(0, 0, 0, 0)
|
||||||
# Some weapons repeat multiple times in one cycle (bosonic doomsdays). Get the number of times it fires off
|
# Some weapons repeat multiple times in one cycle (bosonic doomsdays). Get the number of times it fires off
|
||||||
volleysPerCycle = max(self.getModifiedItemAttr("doomsdayDamageDuration", 1) / self.getModifiedItemAttr("doomsdayDamageCycleTime", 1), 1)
|
volleysPerCycle = max(self.getModifiedItemAttr("doomsdayDamageDuration", 1) / self.getModifiedItemAttr("doomsdayDamageCycleTime", 1), 1)
|
||||||
dpsFactor = volleysPerCycle / (self.cycleTime / 1000)
|
dpsFactor = volleysPerCycle / (self.cycleParameters.averageTime / 1000)
|
||||||
dps = DmgTypes(
|
dps = DmgTypes(
|
||||||
em=volley.em * dpsFactor,
|
em=volley.em * dpsFactor,
|
||||||
thermal=volley.thermal * dpsFactor,
|
thermal=volley.thermal * dpsFactor,
|
||||||
@@ -474,7 +475,7 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
|
|||||||
else:
|
else:
|
||||||
return None, 0
|
return None, 0
|
||||||
if rrAmount:
|
if rrAmount:
|
||||||
rrAmount *= 1 / (self.cycleTime / 1000)
|
rrAmount *= 1 / (self.cycleParameters.averageTime / 1000)
|
||||||
if module.item.group.name == "Ancillary Remote Armor Repairer" and module.charge:
|
if module.item.group.name == "Ancillary Remote Armor Repairer" and module.charge:
|
||||||
rrAmount *= module.getModifiedItemAttr("chargedArmorDamageMultiplier", 1)
|
rrAmount *= module.getModifiedItemAttr("chargedArmorDamageMultiplier", 1)
|
||||||
|
|
||||||
@@ -820,48 +821,56 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
|
|||||||
effect.handler(fit, self, context)
|
effect.handler(fit, self, context)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def cycleTime(self):
|
def cycleParameters(self):
|
||||||
|
"""Copied from new eos as well"""
|
||||||
# Determine if we'll take into account reload time or not
|
# Determine if we'll take into account reload time or not
|
||||||
factorReload = self.owner.factorReload if self.forceReload is None else self.forceReload
|
factorReload = self.owner.factorReload if self.forceReload is None else self.forceReload
|
||||||
|
|
||||||
numShots = self.numShots
|
cycles_until_reload = self.numShots
|
||||||
speed = self.rawCycleTime
|
if cycles_until_reload == 0:
|
||||||
|
cycles_until_reload = math.inf
|
||||||
|
|
||||||
if factorReload and self.charge:
|
active_time = self.rawCycleTime
|
||||||
raw_reload_time = self.reloadTime
|
forced_inactive_time = self.reactivationDelay
|
||||||
|
reload_time = self.reloadTime
|
||||||
|
# Effects which cannot be reloaded have the same processing whether
|
||||||
|
# caller wants to take reload time into account or not
|
||||||
|
if reload_time is None and cycles_until_reload < math.inf:
|
||||||
|
final_cycles = 1
|
||||||
|
early_cycles = cycles_until_reload - final_cycles
|
||||||
|
# Single cycle until effect cannot run anymore
|
||||||
|
if early_cycles == 0:
|
||||||
|
return CycleInfo(active_time, 0, 1)
|
||||||
|
# Multiple cycles with the same parameters
|
||||||
|
if forced_inactive_time == 0:
|
||||||
|
return CycleInfo(active_time, 0, cycles_until_reload)
|
||||||
|
# Multiple cycles with different parameters
|
||||||
|
return CycleSequence((
|
||||||
|
CycleInfo(active_time, forced_inactive_time, early_cycles),
|
||||||
|
CycleInfo(active_time, 0, final_cycles)
|
||||||
|
), 1)
|
||||||
|
# Module cycles the same way all the time in 3 cases:
|
||||||
|
# 1) caller doesn't want to take into account reload time
|
||||||
|
# 2) effect does not have to reload anything to keep running
|
||||||
|
# 3) effect has enough time to reload during inactivity periods
|
||||||
|
if (
|
||||||
|
not factorReload or
|
||||||
|
cycles_until_reload == math.inf or
|
||||||
|
forced_inactive_time >= reload_time
|
||||||
|
):
|
||||||
|
return CycleInfo(active_time, forced_inactive_time, math.inf)
|
||||||
|
# We've got to take reload into consideration
|
||||||
else:
|
else:
|
||||||
raw_reload_time = 0.0
|
final_cycles = 1
|
||||||
|
early_cycles = cycles_until_reload - final_cycles
|
||||||
# Module can only fire one shot at a time, think bomb launchers or defender launchers
|
# If effect has to reload after each its cycle, then its parameters
|
||||||
if self.disallowRepeatingAction:
|
# are the same all the time
|
||||||
if numShots > 0:
|
if early_cycles == 0:
|
||||||
"""
|
return CycleInfo(active_time, reload_time, math.inf)
|
||||||
The actual mechanics behind this is complex. Behavior will be (for 3 ammo):
|
return CycleSequence((
|
||||||
fire, reactivation delay, fire, reactivation delay, fire, max(reactivation delay, reload)
|
CycleInfo(active_time, forced_inactive_time, early_cycles),
|
||||||
so your effective reload time depends on where you are at in the cycle.
|
CycleInfo(active_time, reload_time, final_cycles)
|
||||||
|
), math.inf)
|
||||||
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 - 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.
|
|
||||||
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
|
|
||||||
|
|
||||||
if numShots > 0 and self.charge:
|
|
||||||
speed = (speed * numShots + effective_reload_time) / numShots
|
|
||||||
|
|
||||||
return speed
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def rawCycleTime(self):
|
def rawCycleTime(self):
|
||||||
@@ -887,7 +896,7 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
|
|||||||
def capUse(self):
|
def capUse(self):
|
||||||
capNeed = self.getModifiedItemAttr("capacitorNeed")
|
capNeed = self.getModifiedItemAttr("capacitorNeed")
|
||||||
if capNeed and self.state >= FittingModuleState.ACTIVE:
|
if capNeed and self.state >= FittingModuleState.ACTIVE:
|
||||||
cycleTime = self.cycleTime
|
cycleTime = self.cycleParameters.averageTime
|
||||||
if cycleTime > 0:
|
if cycleTime > 0:
|
||||||
capUsed = capNeed / (cycleTime / 1000.0)
|
capUsed = capNeed / (cycleTime / 1000.0)
|
||||||
return capUsed
|
return capUsed
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ class Miscellanea(ViewColumn):
|
|||||||
return "+ " + ", ".join(info), "Slot Modifiers"
|
return "+ " + ", ".join(info), "Slot Modifiers"
|
||||||
elif itemGroup == "Energy Neutralizer":
|
elif itemGroup == "Energy Neutralizer":
|
||||||
neutAmount = stuff.getModifiedItemAttr("energyNeutralizerAmount")
|
neutAmount = stuff.getModifiedItemAttr("energyNeutralizerAmount")
|
||||||
cycleTime = stuff.cycleTime
|
cycleTime = stuff.cycleParameters.averageTime
|
||||||
if not neutAmount or not cycleTime:
|
if not neutAmount or not cycleTime:
|
||||||
return "", None
|
return "", None
|
||||||
capPerSec = float(-neutAmount) * 1000 / cycleTime
|
capPerSec = float(-neutAmount) * 1000 / cycleTime
|
||||||
@@ -149,7 +149,7 @@ class Miscellanea(ViewColumn):
|
|||||||
return text, tooltip
|
return text, tooltip
|
||||||
elif itemGroup == "Energy Nosferatu":
|
elif itemGroup == "Energy Nosferatu":
|
||||||
neutAmount = stuff.getModifiedItemAttr("powerTransferAmount")
|
neutAmount = stuff.getModifiedItemAttr("powerTransferAmount")
|
||||||
cycleTime = stuff.cycleTime
|
cycleTime = stuff.cycleParameters.averageTime
|
||||||
if not neutAmount or not cycleTime:
|
if not neutAmount or not cycleTime:
|
||||||
return "", None
|
return "", None
|
||||||
capPerSec = float(-neutAmount) * 1000 / cycleTime
|
capPerSec = float(-neutAmount) * 1000 / cycleTime
|
||||||
|
|||||||
@@ -356,7 +356,7 @@ class EfsPort:
|
|||||||
"dps": stats.getDps(spoolOptions=spoolOptions).total * n, "capUse": stats.capUse * n, "falloff": stats.falloff,
|
"dps": stats.getDps(spoolOptions=spoolOptions).total * n, "capUse": stats.capUse * n, "falloff": stats.falloff,
|
||||||
"type": typeing, "name": name, "optimal": maxRange,
|
"type": typeing, "name": name, "optimal": maxRange,
|
||||||
"numCharges": stats.numCharges, "numShots": stats.numShots, "reloadTime": stats.reloadTime,
|
"numCharges": stats.numCharges, "numShots": stats.numShots, "reloadTime": stats.reloadTime,
|
||||||
"cycleTime": stats.cycleTime, "volley": stats.getVolley(spoolOptions=spoolOptions).total * n, "tracking": tracking,
|
"cycleTime": stats.cycleParameters.averageTime, "volley": stats.getVolley(spoolOptions=spoolOptions).total * n, "tracking": tracking,
|
||||||
"maxVelocity": maxVelocity, "explosionDelay": explosionDelay, "damageReductionFactor": damageReductionFactor,
|
"maxVelocity": maxVelocity, "explosionDelay": explosionDelay, "damageReductionFactor": damageReductionFactor,
|
||||||
"explosionRadius": explosionRadius, "explosionVelocity": explosionVelocity, "aoeFieldRange": aoeFieldRange,
|
"explosionRadius": explosionRadius, "explosionVelocity": explosionVelocity, "aoeFieldRange": aoeFieldRange,
|
||||||
"damageMultiplierBonusMax": stats.getModifiedItemAttr("damageMultiplierBonusMax"),
|
"damageMultiplierBonusMax": stats.getModifiedItemAttr("damageMultiplierBonusMax"),
|
||||||
@@ -369,7 +369,7 @@ class EfsPort:
|
|||||||
# Drones are using the old tracking formula for trackingSpeed. This updates it to match turrets.
|
# Drones are using the old tracking formula for trackingSpeed. This updates it to match turrets.
|
||||||
newTracking = droneAttr("trackingSpeed") / (droneAttr("optimalSigRadius") / 40000)
|
newTracking = droneAttr("trackingSpeed") / (droneAttr("optimalSigRadius") / 40000)
|
||||||
statDict = {
|
statDict = {
|
||||||
"dps": drone.getDps().total, "cycleTime": drone.cycleTime, "type": "Drone",
|
"dps": drone.getDps().total, "cycleTime": drone.cycleParameters.averageTime, "type": "Drone",
|
||||||
"optimal": drone.maxRange, "name": drone.item.name, "falloff": drone.falloff,
|
"optimal": drone.maxRange, "name": drone.item.name, "falloff": drone.falloff,
|
||||||
"maxSpeed": droneAttr("maxVelocity"), "tracking": newTracking,
|
"maxSpeed": droneAttr("maxVelocity"), "tracking": newTracking,
|
||||||
"volley": drone.getVolley().total
|
"volley": drone.getVolley().total
|
||||||
@@ -498,11 +498,11 @@ class EfsPort:
|
|||||||
fitMultipliers["drones"] = list(map(getDroneMulti, tf.drones))
|
fitMultipliers["drones"] = list(map(getDroneMulti, tf.drones))
|
||||||
|
|
||||||
getFitTurrets = lambda f: filter(lambda mod: mod.hardpoint == FittingHardpoint.TURRET, f.modules)
|
getFitTurrets = lambda f: filter(lambda mod: mod.hardpoint == FittingHardpoint.TURRET, f.modules)
|
||||||
getTurretMulti = lambda mod: mod.getModifiedItemAttr("damageMultiplier") / mod.cycleTime
|
getTurretMulti = lambda mod: mod.getModifiedItemAttr("damageMultiplier") / mod.cycleParameters.averageTime
|
||||||
fitMultipliers["turrets"] = list(map(getTurretMulti, getFitTurrets(tf)))
|
fitMultipliers["turrets"] = list(map(getTurretMulti, getFitTurrets(tf)))
|
||||||
|
|
||||||
getFitLaunchers = lambda f: filter(lambda mod: mod.hardpoint == FittingHardpoint.MISSILE, f.modules)
|
getFitLaunchers = lambda f: filter(lambda mod: mod.hardpoint == FittingHardpoint.MISSILE, f.modules)
|
||||||
getLauncherMulti = lambda mod: sumDamage(mod.getModifiedChargeAttr) / mod.cycleTime
|
getLauncherMulti = lambda mod: sumDamage(mod.getModifiedChargeAttr) / mod.cycleParameters.averageTime
|
||||||
fitMultipliers["launchers"] = list(map(getLauncherMulti, getFitLaunchers(tf)))
|
fitMultipliers["launchers"] = list(map(getLauncherMulti, getFitLaunchers(tf)))
|
||||||
return fitMultipliers
|
return fitMultipliers
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user