Merge branch 'master' into test-3

# Conflicts:
#	eos/capSim.py
#	eos/effects/structurewarpscrambleblockmwdwithnpceffect.py
#	eos/effects/warpdisruptsphere.py
This commit is contained in:
blitzmann
2018-03-25 03:03:59 -04:00
15 changed files with 161 additions and 39 deletions

View File

@@ -72,7 +72,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)
@@ -80,24 +80,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.items():
for (duration, capNeed, clipSize, disableStagger, reloadTime), amount in mods.items():
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
@@ -107,7 +108,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
@@ -144,7 +145,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
@@ -180,7 +181,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

View File

@@ -0,0 +1,9 @@
# doomsdayBeamDOT
#
# Used by:
# Module: Lance type modules
type = "active"
def handler(fit, src, context):
pass

View File

@@ -0,0 +1,9 @@
# doomsdayConeDOT
#
# Used by:
# Module: Bosonic Field Generator
type = "active"
def handler(fit, src, context):
pass

View File

@@ -0,0 +1,9 @@
# doomsdayHOG
#
# Used by:
# Module: GTFO - Gravitational Transportation Field Oscillator
type = "active"
def handler(fit, src, context):
pass

View File

@@ -0,0 +1,9 @@
# doomsdaySlash
#
# Used by:
# Module: Reaper type modules
type = "active"
def handler(fit, src, context):
pass

View File

@@ -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

View File

@@ -11,8 +11,7 @@ def handler(fit, module, context):
fit.ship.increaseItemAttr("warpScrambleStatus", module.getModifiedItemAttr("warpScrambleStrength"))
if module.charge is not None and module.charge.ID == 47336:
for mod in fit.modules:
if not mod.isEmpty and mod.state > State.ONLINE and (
mod.item.requiresSkill("High Speed Maneuvering")
or mod.item.requiresSkill("Micro Jump Drive Operation")
):
if not mod.isEmpty and mod.item.requiresSkill("High Speed Maneuvering") and mod.state > State.ONLINE:
mod.state = State.ONLINE
if not mod.isEmpty and mod.item.requiresSkill("Micro Jump Drive Operation") and mod.state > State.ONLINE:
mod.state = State.ONLINE

View File

@@ -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))

View File

@@ -1,4 +1,3 @@
# warpDisruptSphere
#
# Used by:
@@ -11,7 +10,6 @@ runTime = "early"
def handler(fit, module, context):
if "projected" in context:
fit.ship.increaseItemAttr("warpScrambleStatus", module.getModifiedItemAttr("warpScrambleStrength"))
if module.charge is not None and module.charge.ID == 45010:

View File

@@ -21,3 +21,5 @@ def handler(fit, module, context):
or mod.item.requiresSkill("High Speed Maneuvering")
):
mod.state = State.ONLINE
if not mod.isEmpty and mod.item.requiresSkill("Micro Jump Drive Operation") and mod.state > State.ONLINE:
mod.state = State.ONLINE

View File

@@ -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

View File

@@ -1084,7 +1084,7 @@ class Fit(object):
def calculateSustainableTank(self, effective=True):
if self.__sustainableTank is None:
if self.capStable:
if self.capStable and not self.factorReload:
sustainable = {
"armorRepair" : self.extraAttributes["armorRepair"],
"shieldRepair": self.extraAttributes["shieldRepair"],
@@ -1142,16 +1142,34 @@ class Fit(object):
usesCap = False
except AttributeError:
usesCap = False
# Modules which do not use cap are not penalized based on cap use
if usesCap:
cycleTime = mod.getModifiedItemAttr("duration")
amount = mod.getModifiedItemAttr(groupAttrMap[mod.item.group.name])
cycleTime = mod.rawCycleTime
amount = mod.getModifiedItemAttr(groupAttrMap[mod.item.group.name])
# Normal Repairers
if usesCap and not mod.charge:
sustainable[attr] -= amount / (cycleTime / 1000.0)
repairers.append(mod)
# Ancillary Armor reps etc
elif usesCap and mod.charge:
if mod.charge.name == "Nanite Repair Paste":
multiplier = mod.getModifiedItemAttr("chargedArmorDamageMultiplier") or 1
else:
multiplier = 1
sustainable[attr] -= amount * multiplier / (cycleTime / 1000.0)
repairers.append(mod)
# Ancillary Shield boosters etc
elif not usesCap:
if self.factorReload and mod.charge:
reloadtime = mod.reloadTime
else:
reloadtime = 0.0
offdutycycle = reloadtime / ((max(mod.numShots, 1) * cycleTime) + reloadtime)
sustainable[attr] -= amount * offdutycycle / (cycleTime / 1000.0)
# Sort repairers by efficiency. We want to use the most efficient repairers first
repairers.sort(key=lambda _mod: _mod.getModifiedItemAttr(
groupAttrMap[_mod.item.group.name]) / _mod.getModifiedItemAttr("capacitorNeed"), reverse=True)
groupAttrMap[_mod.item.group.name]) * (_mod.getModifiedItemAttr(
"chargedArmorDamageMultiplier") or 1) / _mod.getModifiedItemAttr("capacitorNeed"), reverse=True)
# Loop through every module until we're above peak recharge
# Most efficient first, as we sorted earlier.
@@ -1160,15 +1178,35 @@ class Fit(object):
for mod in repairers:
if capUsed > totalPeakRecharge:
break
cycleTime = mod.cycleTime
if self.factorReload and mod.charge:
reloadtime = mod.reloadTime
else:
reloadtime = 0.0
cycleTime = mod.rawCycleTime
capPerSec = mod.capUse
if capPerSec is not None and cycleTime is not None:
# Check how much this repper can work
sustainability = min(1, (totalPeakRecharge - capUsed) / capPerSec)
# Add the sustainable amount
amount = mod.getModifiedItemAttr(groupAttrMap[mod.item.group.name])
sustainable[groupStoreMap[mod.item.group.name]] += sustainability * (amount / (cycleTime / 1000.0))
# Add the sustainable amount
if not mod.charge:
sustainable[groupStoreMap[mod.item.group.name]] += sustainability * amount / (
cycleTime / 1000.0)
else:
if mod.charge.name == "Nanite Repair Paste":
multiplier = mod.getModifiedItemAttr("chargedArmorDamageMultiplier") or 1
else:
multiplier = 1
ondutycycle = (max(mod.numShots, 1) * cycleTime) / (
(max(mod.numShots, 1) * cycleTime) + reloadtime)
sustainable[groupStoreMap[
mod.item.group.name]] += sustainability * amount * ondutycycle * multiplier / (
cycleTime / 1000.0)
capUsed += capPerSec
sustainable["passiveShield"] = self.calculateShieldRecharge()
@@ -1186,7 +1224,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 +1234,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 +1252,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 +1264,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:

View File

@@ -337,8 +337,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
@@ -710,7 +717,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)
@@ -720,12 +727,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.

View File

@@ -72,6 +72,7 @@ class AmountChanger(wx.Dialog):
self.input = wx.TextCtrl(self, wx.ID_ANY, style=wx.TE_PROCESS_ENTER)
self.input.SetValue(str(value))
self.input.SelectAll()
bSizer1.Add(self.input, 0, wx.LEFT | wx.RIGHT | wx.EXPAND, 15)
@@ -82,7 +83,6 @@ class AmountChanger(wx.Dialog):
bSizer1.Add(bSizer3, 0, wx.ALL | wx.EXPAND, 10)
self.input.SetFocus()
self.input.SetInsertionPointEnd()
self.input.Bind(wx.EVT_CHAR, self.onChar)
self.input.Bind(wx.EVT_TEXT_ENTER, self.processEnter)
self.SetSizer(bSizer1)

View File

@@ -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: