Merge branch 'development' into MorePreferences

This commit is contained in:
blitzman
2017-03-26 13:52:59 -04:00
58 changed files with 1032 additions and 367 deletions

View File

@@ -1,15 +1,29 @@
import sys
from os.path import realpath, join, dirname, abspath
from logbook import Logger
import os
istravis = os.environ.get('TRAVIS') == 'true'
pyfalog = Logger(__name__)
debug = False
gamedataCache = True
saveddataCache = True
gamedata_version = ""
gamedata_connectionstring = 'sqlite:///' + unicode(realpath(join(dirname(abspath(__file__)), "..", "eve.db")),
sys.getfilesystemencoding())
saveddata_connectionstring = 'sqlite:///' + unicode(
realpath(join(dirname(abspath(__file__)), "..", "saveddata", "saveddata.db")), sys.getfilesystemencoding())
gamedata_connectionstring = 'sqlite:///' + unicode(realpath(join(dirname(abspath(__file__)), "..", "eve.db")), sys.getfilesystemencoding())
pyfalog.debug("Gamedata connection string: {0}", gamedata_connectionstring)
if istravis is True or hasattr(sys, '_called_from_test'):
# Running in Travis. Run saveddata database in memory.
saveddata_connectionstring = 'sqlite:///:memory:'
else:
saveddata_connectionstring = 'sqlite:///' + unicode(realpath(join(dirname(abspath(__file__)), "..", "saveddata", "saveddata.db")), sys.getfilesystemencoding())
pyfalog.debug("Saveddata connection string: {0}", saveddata_connectionstring)
settings = {
"setting1": True
}
# Autodetect path, only change if the autodetection bugs out.
path = dirname(unicode(__file__, sys.getfilesystemencoding()))

View File

@@ -2,8 +2,10 @@
#
# Used by:
# Modules from group: Tractor Beam (4 of 4)
from eos.config import settings
type = "active"
def handler(fit, module, context):
print settings['setting1']
pass

View File

@@ -30,7 +30,10 @@ except ImportError:
from utils.compat import OrderedDict
from logbook import Logger
pyfalog = Logger(__name__)
# Keep a list of handlers that fail to import so we don't keep trying repeatedly.
badHandlers = []
class Effect(EqBase):
@@ -158,43 +161,51 @@ class Effect(EqBase):
Grab the handler, type and runTime from the effect code if it exists,
if it doesn't, set dummy values and add a dummy handler
"""
try:
self.__effectModule = effectModule = __import__('eos.effects.' + self.handlerName, fromlist=True)
try:
self.__handler = getattr(effectModule, "handler")
except AttributeError:
print "effect {} exists, but no handler".format(self.handlerName)
raise
global badHandlers
# Skip if we've tried to import before and failed
if self.handlerName not in badHandlers:
try:
self.__runTime = getattr(effectModule, "runTime") or "normal"
except AttributeError:
self.__effectModule = effectModule = __import__('eos.effects.' + self.handlerName, fromlist=True)
self.__handler = getattr(effectModule, "handler", effectDummy)
self.__runTime = getattr(effectModule, "runTime", "normal")
self.__activeByDefault = getattr(effectModule, "activeByDefault", True)
t = getattr(effectModule, "type", None)
t = t if isinstance(t, tuple) or t is None else (t,)
self.__type = t
except (ImportError) as e:
# Effect probably doesn't exist, so create a dummy effect and flag it with a warning.
self.__handler = effectDummy
self.__runTime = "normal"
try:
self.__activeByDefault = getattr(effectModule, "activeByDefault")
except AttributeError:
self.__activeByDefault = True
self.__type = None
pyfalog.debug("ImportError generating handler: {0}", e)
badHandlers.append(self.handlerName)
except (AttributeError) as e:
# Effect probably exists but there is an issue with it. Turn it into a dummy effect so we can continue, but flag it with an error.
self.__handler = effectDummy
self.__runTime = "normal"
self.__activeByDefault = True
self.__type = None
pyfalog.error("AttributeError generating handler: {0}", e)
badHandlers.append(self.handlerName)
except Exception as e:
self.__handler = effectDummy
self.__runTime = "normal"
self.__activeByDefault = True
self.__type = None
pyfalog.critical("Exception generating handler:")
pyfalog.critical(e)
badHandlers.append(self.handlerName)
try:
t = getattr(effectModule, "type")
except AttributeError:
t = None
t = t if isinstance(t, tuple) or t is None else (t,)
self.__type = t
except (ImportError, AttributeError) as e:
self.__generated = True
else:
# We've already failed on this one, just pass a dummy effect back
self.__handler = effectDummy
self.__runTime = "normal"
self.__activeByDefault = True
self.__type = None
pyfalog.debug("ImportError or AttributeError generating handler:")
pyfalog.debug(e)
except Exception as e:
pyfalog.critical("Exception generating handler:")
pyfalog.critical(e)
self.__generated = True
def getattr(self, key):
if not self.__generated:
@@ -292,8 +303,6 @@ class Item(EqBase):
@property
def requiredSkills(self):
if self.__requiredSkills is None:
# This import should be here to make sure it's fully initialized
from eos import db
requiredSkills = OrderedDict()
self.__requiredSkills = requiredSkills
# Map containing attribute IDs we may need for required skills
@@ -304,7 +313,7 @@ class Item(EqBase):
# { attributeID : attributeValue }
skillAttrs = {}
# Get relevant attribute values from db (required skill IDs and levels) for our item
for attrInfo in db.directAttributeRequest((self.ID,), tuple(combinedAttrIDs)):
for attrInfo in eos.db.directAttributeRequest((self.ID,), tuple(combinedAttrIDs)):
attrID = attrInfo[1]
attrVal = attrInfo[2]
skillAttrs[attrID] = attrVal
@@ -315,7 +324,7 @@ class Item(EqBase):
skillID = int(skillAttrs[srqIDAtrr])
skillLvl = skillAttrs[srqLvlAttr]
# Fetch item from database and fill map
item = db.getItem(skillID)
item = eos.db.getItem(skillID)
requiredSkills[item] = skillLvl
return self.__requiredSkills
@@ -348,18 +357,20 @@ class Item(EqBase):
# thus keep old mechanism for now
except KeyError:
# Define race map
map = {1: "caldari",
2: "minmatar",
4: "amarr",
5: "sansha", # Caldari + Amarr
6: "blood", # Minmatar + Amarr
8: "gallente",
9: "guristas", # Caldari + Gallente
10: "angelserp", # Minmatar + Gallente, final race depends on the order of skills
12: "sisters", # Amarr + Gallente
16: "jove",
32: "sansha", # Incrusion Sansha
128: "ore"}
map = {
1 : "caldari",
2 : "minmatar",
4 : "amarr",
5 : "sansha", # Caldari + Amarr
6 : "blood", # Minmatar + Amarr
8 : "gallente",
9 : "guristas", # Caldari + Gallente
10 : "angelserp", # Minmatar + Gallente, final race depends on the order of skills
12 : "sisters", # Amarr + Gallente
16 : "jove",
32 : "sansha", # Incrusion Sansha
128: "ore"
}
# Race is None by default
race = None
# Check primary and secondary required skills' races
@@ -429,7 +440,7 @@ class Item(EqBase):
def __repr__(self):
return "Item(ID={}, name={}) at {}".format(
self.ID, self.name, hex(id(self))
self.ID, self.name, hex(id(self))
)
@@ -454,7 +465,6 @@ class Category(EqBase):
class AlphaClone(EqBase):
@reconstructor
def init(self):
self.skillCache = {}
@@ -482,10 +492,9 @@ class Icon(EqBase):
class MarketGroup(EqBase):
def __repr__(self):
return u"MarketGroup(ID={}, name={}, parent={}) at {}".format(
self.ID, self.name, getattr(self.parent, "name", None), self.name, hex(id(self))
self.ID, self.name, getattr(self.parent, "name", None), self.name, hex(id(self))
).encode('utf8')

View File

@@ -19,6 +19,9 @@
import collections
from math import exp
# TODO: This needs to be moved out, we shouldn't have *ANY* dependencies back to other modules/methods inside eos.
# This also breaks writing any tests. :(
from eos.db.gamedata.queries import getAttributeInfo
defaultValuesCache = {}
cappingAttrKeyCache = {}
@@ -26,22 +29,26 @@ cappingAttrKeyCache = {}
class ItemAttrShortcut(object):
def getModifiedItemAttr(self, key, default=None):
if key in self.itemModifiedAttributes:
return self.itemModifiedAttributes[key]
else:
return default
return_value = self.itemModifiedAttributes.get(key)
if return_value is None and default is not None:
return_value = default
return return_value
class ChargeAttrShortcut(object):
def getModifiedChargeAttr(self, key, default=None):
if key in self.chargeModifiedAttributes:
return self.chargeModifiedAttributes[key]
else:
return default
return_value = self.chargeModifiedAttributes.get(key)
if return_value is None and default is not None:
return_value = default
return return_value
class ModifiedAttributeDict(collections.MutableMapping):
OVERRIDES = False
overrides_enabled = False
class CalculationPlaceholder(object):
def __init__(self):
@@ -98,15 +105,23 @@ class ModifiedAttributeDict(collections.MutableMapping):
def __getitem__(self, key):
# Check if we have final calculated value
if key in self.__modified:
if self.__modified[key] == self.CalculationPlaceholder:
self.__modified[key] = self.__calculateValue(key)
return self.__modified[key]
key_value = self.__modified.get(key)
if key_value is self.CalculationPlaceholder:
key_value = self.__modified[key] = self.__calculateValue(key)
if key_value is not None:
return key_value
# Then in values which are not yet calculated
elif key in self.__intermediary:
return self.__intermediary[key]
# Original value is the least priority
if self.__intermediary:
val = self.__intermediary.get(key)
else:
val = None
if val is not None:
return val
else:
# Original value is the least priority
return self.getOriginal(key)
def __delitem__(self, key):
@@ -115,12 +130,18 @@ class ModifiedAttributeDict(collections.MutableMapping):
if key in self.__intermediary:
del self.__intermediary[key]
def getOriginal(self, key):
if self.OVERRIDES and key in self.__overrides:
return self.__overrides.get(key).value
val = self.__original.get(key)
def getOriginal(self, key, default=None):
if self.overrides_enabled and self.overrides:
val = self.overrides.get(key, None)
else:
val = None
if val is None:
return None
if self.original:
val = self.original.get(key, None)
if val is None and val != default:
val = default
return val.value if hasattr(val, "value") else val
@@ -128,12 +149,12 @@ class ModifiedAttributeDict(collections.MutableMapping):
self.__intermediary[key] = val
def __iter__(self):
all = dict(self.__original, **self.__modified)
return (key for key in all)
all_dict = dict(self.original, **self.__modified)
return (key for key in all_dict)
def __contains__(self, key):
return (self.__original is not None and key in self.__original) or \
key in self.__modified or key in self.__intermediary
return (self.original is not None and key in self.original) or \
key in self.__modified or key in self.__intermediary
def __placehold(self, key):
"""Create calculation placeholder in item's modified attribute dict"""
@@ -141,7 +162,7 @@ class ModifiedAttributeDict(collections.MutableMapping):
def __len__(self):
keys = set()
keys.update(self.__original.iterkeys())
keys.update(self.original.iterkeys())
keys.update(self.__modified.iterkeys())
keys.update(self.__intermediary.iterkeys())
return len(keys)
@@ -152,7 +173,6 @@ class ModifiedAttributeDict(collections.MutableMapping):
try:
cappingKey = cappingAttrKeyCache[key]
except KeyError:
from eos.db.gamedata.queries import getAttributeInfo
attrInfo = getAttributeInfo(key)
if attrInfo is None:
cappingId = cappingAttrKeyCache[key] = None
@@ -166,12 +186,8 @@ class ModifiedAttributeDict(collections.MutableMapping):
cappingKey = None if cappingAttrInfo is None else cappingAttrInfo.name
if cappingKey:
if cappingKey in self.original:
# some items come with their own caps (ie: carriers). If they do, use this
cappingValue = self.original.get(cappingKey).value
else:
# If not, get info about the default value
cappingValue = self.__calculateValue(cappingKey)
cappingValue = self.original.get(cappingKey, self.__calculateValue(cappingKey))
cappingValue = cappingValue.value if hasattr(cappingValue, "value") else cappingValue
else:
cappingValue = None
@@ -183,25 +199,28 @@ class ModifiedAttributeDict(collections.MutableMapping):
force = min(force, cappingValue)
return force
# Grab our values if they're there, otherwise we'll take default values
preIncrease = self.__preIncreases[key] if key in self.__preIncreases else 0
multiplier = self.__multipliers[key] if key in self.__multipliers else 1
penalizedMultiplierGroups = self.__penalizedMultipliers[key] if key in self.__penalizedMultipliers else {}
postIncrease = self.__postIncreases[key] if key in self.__postIncreases else 0
preIncrease = self.__preIncreases.get(key, 0)
multiplier = self.__multipliers.get(key, 1)
penalizedMultiplierGroups = self.__penalizedMultipliers.get(key, {})
postIncrease = self.__postIncreases.get(key, 0)
# Grab initial value, priorities are:
# Results of ongoing calculation > preAssign > original > 0
try:
default = defaultValuesCache[key]
except KeyError:
from eos.db.gamedata.queries import getAttributeInfo
attrInfo = getAttributeInfo(key)
if attrInfo is None:
default = defaultValuesCache[key] = 0.0
else:
dv = attrInfo.defaultValue
default = defaultValuesCache[key] = dv if dv is not None else 0.0
val = self.__intermediary[key] if key in self.__intermediary else self.__preAssigns[
key] if key in self.__preAssigns else self.getOriginal(key) if key in self.__original else default
val = self.__intermediary.get(key,
self.__preAssigns.get(key,
self.getOriginal(key, default)
)
)
# We'll do stuff in the following order:
# preIncrease > multiplier > stacking penalized multipliers > postIncrease
@@ -254,7 +273,7 @@ class ModifiedAttributeDict(collections.MutableMapping):
return skill.level
def getAfflictions(self, key):
return self.__affectedBy[key] if key in self.__affectedBy else {}
return self.__affectedBy.get(key, {})
def iterAfflictions(self):
return self.__affectedBy.__iter__()
@@ -360,6 +379,6 @@ class ModifiedAttributeDict(collections.MutableMapping):
class Affliction(object):
def __init__(self, type, amount):
self.type = type
def __init__(self, affliction_type, amount):
self.type = affliction_type
self.amount = amount

View File

@@ -128,9 +128,9 @@ class Fit(object):
self.__capRecharge = None
self.__calculatedTargets = []
self.__remoteReps = {
"Armor": None,
"Shield": None,
"Hull": None,
"Armor" : None,
"Shield" : None,
"Hull" : None,
"Capacitor": None,
}
self.factorReload = False
@@ -370,9 +370,11 @@ class Fit(object):
@validates("ID", "ownerID", "shipID")
def validator(self, key, val):
map = {"ID": lambda _val: isinstance(_val, int),
"ownerID": lambda _val: isinstance(_val, int) or _val is None,
"shipID": lambda _val: isinstance(_val, int) or _val is None}
map = {
"ID" : lambda _val: isinstance(_val, int),
"ownerID": lambda _val: isinstance(_val, int) or _val is None,
"shipID" : lambda _val: isinstance(_val, int) or _val is None
}
if not map[key](val):
raise ValueError(str(val) + " is not a valid value for " + key)
@@ -408,15 +410,15 @@ class Fit(object):
self.ship.clear()
c = chain(
self.modules,
self.drones,
self.fighters,
self.boosters,
self.implants,
self.projectedDrones,
self.projectedModules,
self.projectedFighters,
(self.character, self.extraAttributes),
self.modules,
self.drones,
self.fighters,
self.boosters,
self.implants,
self.projectedDrones,
self.projectedModules,
self.projectedFighters,
(self.character, self.extraAttributes),
)
for stuff in c:
@@ -476,11 +478,11 @@ class Fit(object):
if warfareBuffID == 11: # Shield Burst: Active Shielding: Repair Duration/Capacitor
self.modules.filteredItemBoost(
lambda mod: mod.item.requiresSkill("Shield Operation") or mod.item.requiresSkill(
"Shield Emission Systems"), "capacitorNeed", value)
lambda mod: mod.item.requiresSkill("Shield Operation") or mod.item.requiresSkill(
"Shield Emission Systems"), "capacitorNeed", value)
self.modules.filteredItemBoost(
lambda mod: mod.item.requiresSkill("Shield Operation") or mod.item.requiresSkill(
"Shield Emission Systems"), "duration", value)
lambda mod: mod.item.requiresSkill("Shield Operation") or mod.item.requiresSkill(
"Shield Emission Systems"), "duration", value)
if warfareBuffID == 12: # Shield Burst: Shield Extension: Shield HP
self.ship.boostItemAttr("shieldCapacity", value, stackingPenalties=True)
@@ -506,26 +508,26 @@ class Fit(object):
if warfareBuffID == 17: # Information Burst: Electronic Superiority: EWAR Range and Strength
groups = ("ECM", "Sensor Dampener", "Weapon Disruptor", "Target Painter")
self.modules.filteredItemBoost(lambda mod: mod.item.group.name in groups, "maxRange", value,
stackingPenalties=True)
stackingPenalties=True)
self.modules.filteredItemBoost(lambda mod: mod.item.group.name in groups,
"falloffEffectiveness", value, stackingPenalties=True)
"falloffEffectiveness", value, stackingPenalties=True)
for scanType in ("Magnetometric", "Radar", "Ladar", "Gravimetric"):
self.modules.filteredItemBoost(lambda mod: mod.item.group.name == "ECM",
"scan%sStrengthBonus" % scanType, value,
stackingPenalties=True)
"scan%sStrengthBonus" % scanType, value,
stackingPenalties=True)
for attr in ("missileVelocityBonus", "explosionDelayBonus", "aoeVelocityBonus", "falloffBonus",
"maxRangeBonus", "aoeCloudSizeBonus", "trackingSpeedBonus"):
self.modules.filteredItemBoost(lambda mod: mod.item.group.name == "Weapon Disruptor",
attr, value)
attr, value)
for attr in ("maxTargetRangeBonus", "scanResolutionBonus"):
self.modules.filteredItemBoost(lambda mod: mod.item.group.name == "Sensor Dampener",
attr, value)
attr, value)
self.modules.filteredItemBoost(lambda mod: mod.item.group.name == "Target Painter",
"signatureRadiusBonus", value, stackingPenalties=True)
"signatureRadiusBonus", value, stackingPenalties=True)
if warfareBuffID == 18: # Information Burst: Electronic Hardening: Scan Strength
for scanType in ("Gravimetric", "Radar", "Ladar", "Magnetometric"):
@@ -543,35 +545,33 @@ class Fit(object):
if warfareBuffID == 21: # Skirmish Burst: Interdiction Maneuvers: Tackle Range
groups = ("Stasis Web", "Warp Scrambler")
self.modules.filteredItemBoost(lambda mod: mod.item.group.name in groups, "maxRange", value,
stackingPenalties=True)
self.modules.filteredItemBoost(lambda mod: mod.item.group.name in groups, "maxRange", value, stackingPenalties=True)
if warfareBuffID == 22: # Skirmish Burst: Rapid Deployment: AB/MWD Speed Increase
self.modules.filteredItemBoost(
lambda mod: mod.item.requiresSkill("Afterburner") or mod.item.requiresSkill(
"High Speed Maneuvering"), "speedFactor", value, stackingPenalties=True)
self.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Afterburner") or mod.item.requiresSkill("High Speed Maneuvering"),
"speedFactor", value, stackingPenalties=True)
if warfareBuffID == 23: # Mining Burst: Mining Laser Field Enhancement: Mining/Survey Range
self.modules.filteredItemBoost(
lambda mod: mod.item.requiresSkill("Mining") or mod.item.requiresSkill(
"Ice Harvesting") or mod.item.requiresSkill("Gas Cloud Harvesting"), "maxRange",
value, stackingPenalties=True)
self.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("CPU Management"),
"surveyScanRange", value, stackingPenalties=True)
self.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Mining") or
mod.item.requiresSkill("Ice Harvesting") or
mod.item.requiresSkill("Gas Cloud Harvesting"),
"maxRange", value, stackingPenalties=True)
self.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("CPU Management"), "surveyScanRange", value, stackingPenalties=True)
if warfareBuffID == 24: # Mining Burst: Mining Laser Optimization: Mining Capacitor/Duration
self.modules.filteredItemBoost(
lambda mod: mod.item.requiresSkill("Mining") or mod.item.requiresSkill(
"Ice Harvesting") or mod.item.requiresSkill("Gas Cloud Harvesting"),
"capacitorNeed", value, stackingPenalties=True)
self.modules.filteredItemBoost(
lambda mod: mod.item.requiresSkill("Mining") or mod.item.requiresSkill(
"Ice Harvesting") or mod.item.requiresSkill("Gas Cloud Harvesting"), "duration",
value, stackingPenalties=True)
self.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Mining") or
mod.item.requiresSkill("Ice Harvesting") or
mod.item.requiresSkill("Gas Cloud Harvesting"),
"capacitorNeed", value, stackingPenalties=True)
self.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Mining") or
mod.item.requiresSkill("Ice Harvesting") or
mod.item.requiresSkill("Gas Cloud Harvesting"),
"duration", value, stackingPenalties=True)
if warfareBuffID == 25: # Mining Burst: Mining Equipment Preservation: Crystal Volatility
self.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Mining"),
"crystalVolatilityChance", value, stackingPenalties=True)
self.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Mining"), "crystalVolatilityChance", value, stackingPenalties=True)
if warfareBuffID == 60: # Skirmish Burst: Evasive Maneuvers: Agility
self.ship.boostItemAttr("agility", value, stackingPenalties=True)
@@ -844,15 +844,17 @@ class Fit(object):
return amount
slots = {Slot.LOW: "lowSlots",
Slot.MED: "medSlots",
Slot.HIGH: "hiSlots",
Slot.RIG: "rigSlots",
Slot.SUBSYSTEM: "maxSubSystems",
Slot.SERVICE: "serviceSlots",
Slot.F_LIGHT: "fighterLightSlots",
Slot.F_SUPPORT: "fighterSupportSlots",
Slot.F_HEAVY: "fighterHeavySlots"}
slots = {
Slot.LOW : "lowSlots",
Slot.MED : "medSlots",
Slot.HIGH : "hiSlots",
Slot.RIG : "rigSlots",
Slot.SUBSYSTEM: "maxSubSystems",
Slot.SERVICE : "serviceSlots",
Slot.F_LIGHT : "fighterLightSlots",
Slot.F_SUPPORT: "fighterSupportSlots",
Slot.F_HEAVY : "fighterHeavySlots"
}
def getSlotsFree(self, type, countDummies=False):
if type in (Slot.MODE, Slot.SYSTEM):
@@ -927,20 +929,19 @@ class Fit(object):
return amount
# Expresses how difficult a target is to probe down with scan probes
# If this is <1.08, the ship is unproabeable
@property
def probeSize(self):
"""
Expresses how difficult a target is to probe down with scan probes
"""
sigRad = self.ship.getModifiedItemAttr("signatureRadius")
sensorStr = float(self.scanStrength)
probeSize = sigRad / sensorStr if sensorStr != 0 else None
# http://www.eveonline.com/ingameboard.asp?a=topic&threadID=1532170&page=2#42
if probeSize is not None:
# http://forum.eve-ru.com/index.php?showtopic=74195&view=findpost&p=1333691
# http://forum.eve-ru.com/index.php?showtopic=74195&view=findpost&p=1333763
# Tests by tester128 and several conclusions by me, prove that cap is in range
# from 1.1 to 1.12, we're picking average value
probeSize = max(probeSize, 1.11)
# Probe size is capped at 1.08
probeSize = max(probeSize, 1.08)
return probeSize
@property
@@ -1002,29 +1003,35 @@ class Fit(object):
def calculateSustainableTank(self, effective=True):
if self.__sustainableTank is None:
if self.capStable:
sustainable = {"armorRepair": self.extraAttributes["armorRepair"],
"shieldRepair": self.extraAttributes["shieldRepair"],
"hullRepair": self.extraAttributes["hullRepair"]}
sustainable = {
"armorRepair" : self.extraAttributes["armorRepair"],
"shieldRepair": self.extraAttributes["shieldRepair"],
"hullRepair" : self.extraAttributes["hullRepair"]
}
else:
sustainable = {}
repairers = []
# Map a repairer type to the attribute it uses
groupAttrMap = {"Armor Repair Unit": "armorDamageAmount",
"Ancillary Armor Repairer": "armorDamageAmount",
"Hull Repair Unit": "structureDamageAmount",
"Shield Booster": "shieldBonus",
"Ancillary Shield Booster": "shieldBonus",
"Remote Armor Repairer": "armorDamageAmount",
"Remote Shield Booster": "shieldBonus"}
groupAttrMap = {
"Armor Repair Unit" : "armorDamageAmount",
"Ancillary Armor Repairer": "armorDamageAmount",
"Hull Repair Unit" : "structureDamageAmount",
"Shield Booster" : "shieldBonus",
"Ancillary Shield Booster": "shieldBonus",
"Remote Armor Repairer" : "armorDamageAmount",
"Remote Shield Booster" : "shieldBonus"
}
# Map repairer type to attribute
groupStoreMap = {"Armor Repair Unit": "armorRepair",
"Hull Repair Unit": "hullRepair",
"Shield Booster": "shieldRepair",
"Ancillary Shield Booster": "shieldRepair",
"Remote Armor Repairer": "armorRepair",
"Remote Shield Booster": "shieldRepair",
"Ancillary Armor Repairer": "armorRepair", }
groupStoreMap = {
"Armor Repair Unit" : "armorRepair",
"Hull Repair Unit" : "hullRepair",
"Shield Booster" : "shieldRepair",
"Ancillary Shield Booster": "shieldRepair",
"Remote Armor Repairer" : "armorRepair",
"Remote Shield Booster" : "shieldRepair",
"Ancillary Armor Repairer": "armorRepair",
}
capUsed = self.capUsed
for attr in ("shieldRepair", "armorRepair", "hullRepair"):
@@ -1052,7 +1059,7 @@ class Fit(object):
# 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("capacitorNeed"), reverse=True)
# Loop through every module until we're above peak recharge
# Most efficient first, as we sorted earlier.
@@ -1365,10 +1372,10 @@ class Fit(object):
def __repr__(self):
return u"Fit(ID={}, ship={}, name={}) at {}".format(
self.ID, self.ship.item.name, self.name, hex(id(self))
self.ID, self.ship.item.name, self.name, hex(id(self))
).encode('utf8')
def __str__(self):
return u"{} ({})".format(
self.name, self.ship.item.name
self.name, self.ship.item.name
).encode('utf8')

View File

@@ -173,7 +173,7 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
charges = 0
else:
charges = floor(containerCapacity / chargeVolume)
return charges
return int(charges)
@property
def numShots(self):
@@ -689,7 +689,7 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
Currently would apply to bomb launchers and defender missiles
"""
effective_reload_time = ((self.reactivationDelay * numShots) + raw_reload_time) / numShots
effective_reload_time = ((self.reactivationDelay * (numShots - 1)) + max(raw_reload_time, self.reactivationDelay, 0)) / numShots
else:
"""
Applies to MJD/MJFG