Refactoring for various EFS export code

This commit is contained in:
Maru Maru
2018-06-16 04:50:55 -04:00
parent f8504cfa6e
commit d61ab0ff5a
7 changed files with 689 additions and 216 deletions

View File

@@ -8,126 +8,174 @@ from math import log
import eos.db
eos.db.saveddata_meta.create_all()
import json
from service.fit import Fit
from service.market import Market
from eos.enum import Enum
from eos.saveddata.module import Hardpoint, Slot, Module
from eos.saveddata.drone import Drone
from eos.effectHandlerHelpers import HandledList
from eos.db import gamedata_session, getItemsByCategory, getCategory, getAttributeInfo, getGroup
from eos.gamedata import Category, Group, Item, Traits, Attribute, Effect, ItemEffect
eos.db.saveddata_meta.create_all()
class RigSize(Enum):
# Matches to item attribute 'rigSize' on ship and rig items
SMALL = 1
MEDIUM = 2
LARGE = 3
CAPITAL = 4
def attrDirectMap(values, target, source):
for val in values:
target[val] = source.itemModifiedAttributes[val]
def getT2MwdSpeed(fit, fitL):
fitID = fit.ID
propID = None
shipHasMedSlots = fit.ship.itemModifiedAttributes['medSlots'] > 0
shipPower = fit.ship.itemModifiedAttributes['powerOutput']
# Monitors have a 99% reduction to prop mod power requirements
if fit.ship.name == 'Monitor':
shipPower *= 100
rigSize = fit.ship.itemModifiedAttributes['rigSize']
if rigSize == 1 and fit.ship.itemModifiedAttributes['medSlots'] > 0:
propID = 440
elif rigSize == 2 and fit.ship.itemModifiedAttributes['medSlots'] > 0:
propID = 12076
elif rigSize == 3 and fit.ship.itemModifiedAttributes['medSlots'] > 0:
propID = 12084
elif rigSize == 4 and fit.ship.itemModifiedAttributes['medSlots'] > 0:
if fit.ship.itemModifiedAttributes['powerOutput'] > 60000:
propID = 41253
else:
propID = 12084
elif rigSize == None and fit.ship.itemModifiedAttributes['medSlots'] > 0:
propID = 440
if propID:
fitL.appendModule(fitID, propID)
fitL.recalc(fit)
fit = eos.db.getFit(fitID)
mwdPropSpeed = fit.maxSpeed
mwdPosition = list(filter(lambda mod: mod.item and mod.item.ID == propID, fit.modules))[0].position
fitL.removeModule(fitID, mwdPosition)
fitL.recalc(fit)
fit = eos.db.getFit(fitID)
return mwdPropSpeed
if not shipHasMedSlots:
return None
filterVal = Item.groupID == getGroup('Propulsion Module').ID
propMods = gamedata_session.query(Item).options().filter(filterVal).all()
mapPropData = lambda propName: \
next(map(lambda propMod: {'id': propMod.typeID, 'powerReq': propMod.attributes['power'].value},
(filter(lambda mod: mod.name == propName, propMods))))
mwd5mn = mapPropData('5MN Microwarpdrive II')
mwd50mn = mapPropData('50MN Microwarpdrive II')
mwd500mn = mapPropData('500MN Microwarpdrive II')
mwd50000mn = mapPropData('50000MN Microwarpdrive II')
if rigSize == RigSize.SMALL or rigSize is None:
propID = mwd5mn['id'] if shipPower > mwd5mn['powerReq'] else None
elif rigSize == RigSize.MEDIUM:
propID = mwd50mn['id'] if shipPower > mwd50mn['powerReq'] else mwd5mn['id']
elif rigSize == RigSize.LARGE:
propID = mwd500mn['id'] if shipPower > mwd500mn['powerReq'] else mwd50mn['id']
elif rigSize == RigSize.CAPITAL:
propID = mwd50000mn['id'] if shipPower > mwd50000mn['powerReq'] else mwd500mn['id']
if propID is None:
return None
fitL.appendModule(fitID, propID)
fitL.recalc(fit)
fit = eos.db.getFit(fitID)
mwdPropSpeed = fit.maxSpeed
mwdPosition = list(filter(lambda mod: mod.item and mod.item.ID == propID, fit.modules))[0].position
fitL.removeModule(fitID, mwdPosition)
fitL.recalc(fit)
fit = eos.db.getFit(fitID)
return mwdPropSpeed
def getPropData(fit, fitL):
fitID = fit.ID
propMods = list(filter(lambda mod: mod.item and mod.item.groupID in [46], fit.modules))
possibleMWD = list(filter(lambda mod: 'signatureRadiusBonus' in mod.item.attributes, propMods))
if len(possibleMWD) > 0 and possibleMWD[0].state > 0:
mwd = possibleMWD[0]
oldMwdState = mwd.state
mwd.state = 0
propGroupId = getGroup('Propulsion Module').ID
propMods = filter(lambda mod: mod.item and mod.item.groupID == propGroupId, fit.modules)
activePropWBloomFilter = lambda mod: mod.state > 0 and 'signatureRadiusBonus' in mod.item.attributes
propWithBloom = next(filter(activePropWBloomFilter, propMods), None)
if propWithBloom is not None:
oldPropState = propWithBloom.state
propWithBloom.state = 0
fitL.recalc(fit)
fit = eos.db.getFit(fitID)
sp = fit.maxSpeed
sig = fit.ship.itemModifiedAttributes['signatureRadius']
mwd.state = oldMwdState
propWithBloom.state = oldPropState
fitL.recalc(fit)
fit = eos.db.getFit(fitID)
return {'usingMWD': True, 'unpropedSpeed': sp, 'unpropedSig': sig}
return {'usingMWD': False, 'unpropedSpeed': fit.maxSpeed, 'unpropedSig': fit.ship.itemModifiedAttributes['signatureRadius']}
return {
'usingMWD': False,
'unpropedSpeed': fit.maxSpeed,
'unpropedSig': fit.ship.itemModifiedAttributes['signatureRadius']
}
def getOutgoingProjectionData(fit):
# This is a subset of module groups capable of projection and a superset of those currently used by efs
projectedModGroupIds = [
41, 52, 65, 67, 68, 71, 80, 201, 208, 291, 325, 379, 585,
842, 899, 1150, 1154, 1189, 1306, 1672, 1697, 1698, 1815, 1894
modGroupNames = [
'Remote Shield Booster', 'Warp Scrambler', 'Stasis Web', 'Remote Capacitor Transmitter',
'Energy Nosferatu', 'Energy Neutralizer', 'Burst Jammer', 'ECM', 'Sensor Dampener',
'Weapon Disruptor', 'Remote Armor Repairer', 'Target Painter', 'Remote Hull Repairer',
'Burst Projectors', 'Warp Disrupt Field Generator', 'Armor Resistance Shift Hardener',
'Target Breaker', 'Micro Jump Drive', 'Ship Modifiers', 'Stasis Grappler',
'Ancillary Remote Shield Booster', 'Ancillary Remote Armor Repairer',
'Titan Phenomena Generator', 'Non-Repeating Hardeners'
]
projectedMods = list(filter(lambda mod: mod.item and mod.item.groupID in projectedModGroupIds, fit.modules))
modGroupIds = list(map(lambda s: getGroup(s).ID, modGroupNames))
modGroupData = dict(map(lambda name, gid: (name, {'name': name, 'id': gid}),
modGroupNames, modGroupIds))
projectedMods = list(filter(lambda mod: mod.item and mod.item.groupID in modGroupIds, fit.modules))
projections = []
for mod in projectedMods:
stats = {}
if mod.item.groupID == 65 or mod.item.groupID == 1672:
if mod.item.groupID in [modGroupData['Stasis Web']['id'], modGroupData['Stasis Grappler']['id']]:
stats['type'] = 'Stasis Web'
stats['optimal'] = mod.itemModifiedAttributes['maxRange']
attrDirectMap(['duration', 'speedFactor'], stats, mod)
elif mod.item.groupID == 291:
elif mod.item.groupID == modGroupData['Weapon Disruptor']['id']:
stats['type'] = 'Weapon Disruptor'
stats['optimal'] = mod.itemModifiedAttributes['maxRange']
stats['falloff'] = mod.itemModifiedAttributes['falloffEffectiveness']
attrDirectMap([
'trackingSpeedBonus', 'maxRangeBonus', 'falloffBonus', 'aoeCloudSizeBonus',\
'aoeVelocityBonus', 'missileVelocityBonus', 'explosionDelayBonus'\
'trackingSpeedBonus', 'maxRangeBonus', 'falloffBonus', 'aoeCloudSizeBonus',
'aoeVelocityBonus', 'missileVelocityBonus', 'explosionDelayBonus'
], stats, mod)
elif mod.item.groupID == 68:
elif mod.item.groupID == modGroupData['Energy Nosferatu']['id']:
stats['type'] = 'Energy Nosferatu'
attrDirectMap(['powerTransferAmount', 'energyNeutralizerSignatureResolution'], stats, mod)
elif mod.item.groupID == 71:
elif mod.item.groupID == modGroupData['Energy Neutralizer']['id']:
stats['type'] = 'Energy Neutralizer'
attrDirectMap([
'energyNeutralizerSignatureResolution','entityCapacitorLevelModifierSmall',\
'entityCapacitorLevelModifierMedium', 'entityCapacitorLevelModifierLarge',\
'energyNeutralizerAmount'\
'energyNeutralizerSignatureResolution', 'entityCapacitorLevelModifierSmall',
'entityCapacitorLevelModifierMedium', 'entityCapacitorLevelModifierLarge',
'energyNeutralizerAmount'
], stats, mod)
elif mod.item.groupID == 41 or mod.item.groupID == 1697:
elif mod.item.groupID in [modGroupData['Remote Shield Booster']['id'],
modGroupData['Ancillary Remote Shield Booster']['id']]:
stats['type'] = 'Remote Shield Booster'
attrDirectMap(['shieldBonus'], stats, mod)
elif mod.item.groupID == 325 or mod.item.groupID == 1698:
elif mod.item.groupID in [modGroupData['Remote Armor Repairer']['id'],
modGroupData['Ancillary Remote Armor Repairer']['id']]:
stats['type'] = 'Remote Armor Repairer'
attrDirectMap(['armorDamageAmount'], stats, mod)
elif mod.item.groupID == 52:
elif mod.item.groupID == modGroupData['Warp Scrambler']['id']:
stats['type'] = 'Warp Scrambler'
attrDirectMap(['activationBlockedStrenght', 'warpScrambleStrength'], stats, mod)
elif mod.item.groupID == 379:
elif mod.item.groupID == modGroupData['Target Painter']['id']:
stats['type'] = 'Target Painter'
attrDirectMap(['signatureRadiusBonus'], stats, mod)
elif mod.item.groupID == 208:
elif mod.item.groupID == modGroupData['Sensor Dampener']['id']:
stats['type'] = 'Sensor Dampener'
attrDirectMap(['maxTargetRangeBonus', 'scanResolutionBonus'], stats, mod)
elif mod.item.groupID == 201:
elif mod.item.groupID == modGroupData['ECM']['id']:
stats['type'] = 'ECM'
attrDirectMap([
'scanGravimetricStrengthBonus', 'scanMagnetometricStrengthBonus',\
'scanRadarStrengthBonus', 'scanLadarStrengthBonus',\
'scanGravimetricStrengthBonus', 'scanMagnetometricStrengthBonus',
'scanRadarStrengthBonus', 'scanLadarStrengthBonus',
], stats, mod)
elif mod.item.groupID == 80:
elif mod.item.groupID == modGroupData['Burst Jammer']['id']:
stats['type'] = 'Burst Jammer'
mod.itemModifiedAttributes['maxRange'] = mod.itemModifiedAttributes['ecmBurstRange']
attrDirectMap([
'scanGravimetricStrengthBonus', 'scanMagnetometricStrengthBonus',\
'scanRadarStrengthBonus', 'scanLadarStrengthBonus',\
'scanGravimetricStrengthBonus', 'scanMagnetometricStrengthBonus',
'scanRadarStrengthBonus', 'scanLadarStrengthBonus',
], stats, mod)
elif mod.item.groupID == 1189:
elif mod.item.groupID == modGroupData['Micro Jump Drive']['id']:
stats['type'] = 'Micro Jump Drive'
mod.itemModifiedAttributes['maxRange'] = 0
attrDirectMap(['moduleReactivationDelay'], stats, mod)
if mod.itemModifiedAttributes['maxRange'] == None:
if mod.itemModifiedAttributes['maxRange'] is None:
print(mod.item.name)
print(mod.itemModifiedAttributes.items())
raise ValueError('Projected module lacks a maxRange')
@@ -137,13 +185,14 @@ def getOutgoingProjectionData(fit):
projections.append(stats)
return projections
def getModuleNames(fit):
moduleNames = []
highSlotNames = []
midSlotNames = []
lowSlotNames = []
rigSlotNames = []
miscSlotNames = [] #subsystems ect
miscSlotNames = [] # subsystems ect
for mod in fit.modules:
if mod.slot == 3:
modSlotNames = highSlotNames
@@ -156,8 +205,8 @@ def getModuleNames(fit):
elif mod.slot == 5:
modSlotNames = miscSlotNames
try:
if mod.item != None:
if mod.charge != None:
if mod.item is not None:
if mod.charge is not None:
modSlotNames.append(mod.item.name + ': ' + mod.charge.name)
else:
modSlotNames.append(mod.item.name)
@@ -167,8 +216,12 @@ def getModuleNames(fit):
print(vars(mod))
print('could not find name for module')
print(fit.modules)
for modInfo in [['High Slots:'], highSlotNames, ['', 'Med Slots:'], midSlotNames, ['', 'Low Slots:'], lowSlotNames, ['', 'Rig Slots:'], rigSlotNames]:
for modInfo in [
['High Slots:'], highSlotNames, ['', 'Med Slots:'], midSlotNames,
['', 'Low Slots:'], lowSlotNames, ['', 'Rig Slots:'], rigSlotNames
]:
moduleNames.extend(modInfo)
if len(miscSlotNames) > 0:
moduleNames.append('')
moduleNames.append('Subsystems:')
@@ -201,19 +254,37 @@ def getModuleNames(fit):
moduleNames.append(commandFit.name)
return moduleNames
def getFighterAbilityData(fighterAttr, fighter, baseRef):
baseRefDam = baseRef + 'Damage'
abilityName = 'RegularAttack' if baseRef == 'fighterAbilityAttackMissile' else 'MissileAttack'
rangeSuffix = 'RangeOptimal' if baseRef == 'fighterAbilityAttackMissile' else 'Range'
reductionRef = baseRef if baseRef == 'fighterAbilityAttackMissile' else baseRefDam
damageReductionFactor = log(fighterAttr[reductionRef + 'ReductionFactor']) / log(fighterAttr[reductionRef + 'ReductionSensitivity'])
damTypes = ['EM', 'Therm', 'Exp', 'Kin']
abBaseDamage = sum(map(lambda damType: fighterAttr[baseRefDam + damType], damTypes))
abDamage = abBaseDamage * fighterAttr[baseRefDam + 'Multiplier']
return {
'name': abilityName, 'volley': abDamage * fighter.amountActive, 'explosionRadius': fighterAttr[baseRef + 'ExplosionRadius'],
'explosionVelocity': fighterAttr[baseRef + 'ExplosionVelocity'], 'optimal': fighterAttr[baseRef + rangeSuffix],
'damageReductionFactor': damageReductionFactor, 'rof': fighterAttr[baseRef + 'Duration'],
}
def getWeaponSystemData(fit):
weaponSystems = []
groups = {}
for mod in fit.modules:
if mod.dps > 0:
# Group weapon + ammo combinations that occur more than once
keystr = str(mod.itemID) + '-' + str(mod.chargeID)
if keystr in groups:
groups[keystr][1] += 1
else:
groups[keystr] = [mod, 1]
for wepGroup in groups:
stats = groups[wepGroup][0]
c = groups[wepGroup][1]
for wepGroup in groups.values():
stats = wepGroup[0]
n = wepGroup[1]
tracking = 0
maxVelocity = 0
explosionDelay = 0
@@ -221,11 +292,12 @@ def getWeaponSystemData(fit):
explosionRadius = 0
explosionVelocity = 0
aoeFieldRange = 0
if stats.hardpoint == 2:
if stats.hardpoint == Hardpoint.TURRET:
tracking = stats.itemModifiedAttributes['trackingSpeed']
typeing = 'Turret'
name = stats.item.name + ', ' + stats.charge.name
elif stats.hardpoint == 1 or 'Bomb Launcher' in stats.item.name:
# Bombs share most attributes with missiles despite not needing the hardpoint
elif stats.hardpoint == Hardpoint.MISSILE or 'Bomb Launcher' in stats.item.name:
maxVelocity = stats.chargeModifiedAttributes['maxVelocity']
explosionDelay = stats.chargeModifiedAttributes['explosionDelay']
damageReductionFactor = stats.chargeModifiedAttributes['aoeDamageReductionFactor']
@@ -233,140 +305,240 @@ def getWeaponSystemData(fit):
explosionVelocity = stats.chargeModifiedAttributes['aoeVelocity']
typeing = 'Missile'
name = stats.item.name + ', ' + stats.charge.name
elif stats.hardpoint == 0:
elif stats.hardpoint == Hardpoint.NONE:
aoeFieldRange = stats.itemModifiedAttributes['empFieldRange']
# This also covers non-bomb weapons with dps values and no hardpoints, most notably targeted doomsdays.
typeing = 'SmartBomb'
name = stats.item.name
statDict = {'dps': stats.dps * c, 'capUse': stats.capUse * c, 'falloff': stats.falloff,\
'type': typeing, 'name': name, 'optimal': stats.maxRange,\
'numCharges': stats.numCharges, 'numShots': stats.numShots, 'reloadTime': stats.reloadTime,\
'cycleTime': stats.cycleTime, 'volley': stats.volley * c, 'tracking': tracking,\
'maxVelocity': maxVelocity, 'explosionDelay': explosionDelay, 'damageReductionFactor': damageReductionFactor,\
'explosionRadius': explosionRadius, 'explosionVelocity': explosionVelocity, 'aoeFieldRange': aoeFieldRange\
statDict = {
'dps': stats.dps * n, 'capUse': stats.capUse * n, 'falloff': stats.falloff,
'type': typeing, 'name': name, 'optimal': stats.maxRange,
'numCharges': stats.numCharges, 'numShots': stats.numShots, 'reloadTime': stats.reloadTime,
'cycleTime': stats.cycleTime, 'volley': stats.volley * n, 'tracking': tracking,
'maxVelocity': maxVelocity, 'explosionDelay': explosionDelay, 'damageReductionFactor': damageReductionFactor,
'explosionRadius': explosionRadius, 'explosionVelocity': explosionVelocity, 'aoeFieldRange': aoeFieldRange
}
weaponSystems.append(statDict)
#if fit.droneDPS > 0:
for drone in fit.drones:
if drone.dps[0] > 0 and drone.amountActive > 0:
newTracking = drone.itemModifiedAttributes['trackingSpeed'] / (drone.itemModifiedAttributes['optimalSigRadius'] / 40000)
statDict = {'dps': drone.dps[0], 'cycleTime': drone.cycleTime, 'type': 'Drone',\
'optimal': drone.maxRange, 'name': drone.item.name, 'falloff': drone.falloff,\
'maxSpeed': drone.itemModifiedAttributes['maxVelocity'], 'tracking': newTracking,\
'volley': drone.dps[1]\
droneAttr = drone.itemModifiedAttributes
# Drones are using the old tracking formula for trackingSpeed. This updates it to match turrets.
newTracking = droneAttr['trackingSpeed'] / (droneAttr['optimalSigRadius'] / 40000)
statDict = {
'dps': drone.dps[0], 'cycleTime': drone.cycleTime, 'type': 'Drone',
'optimal': drone.maxRange, 'name': drone.item.name, 'falloff': drone.falloff,
'maxSpeed': droneAttr['maxVelocity'], 'tracking': newTracking,
'volley': drone.dps[1]
}
weaponSystems.append(statDict)
for fighter in fit.fighters:
if fighter.dps[0] > 0 and fighter.amountActive > 0:
fighterAttr = fighter.itemModifiedAttributes
abilities = []
#for ability in fighter.abilities:
if 'fighterAbilityAttackMissileDamageEM' in fighter.itemModifiedAttributes:
if 'fighterAbilityAttackMissileDamageEM' in fighterAttr:
baseRef = 'fighterAbilityAttackMissile'
baseRefDam = baseRef + 'Damage'
damageReductionFactor = log(fighter.itemModifiedAttributes[baseRef + 'ReductionFactor']) / log(fighter.itemModifiedAttributes[baseRef + 'ReductionSensitivity'])
abBaseDamage = fighter.itemModifiedAttributes[baseRefDam + 'EM'] + fighter.itemModifiedAttributes[baseRefDam + 'Therm'] + fighter.itemModifiedAttributes[baseRefDam + 'Exp'] + fighter.itemModifiedAttributes[baseRefDam + 'Kin']
abDamage = abBaseDamage * fighter.itemModifiedAttributes[baseRefDam + 'Multiplier']
ability = {'name': 'RegularAttack', 'volley': abDamage * fighter.amountActive, 'explosionRadius': fighter.itemModifiedAttributes[baseRef + 'ExplosionRadius'],\
'explosionVelocity': fighter.itemModifiedAttributes[baseRef + 'ExplosionVelocity'], 'optimal': fighter.itemModifiedAttributes[baseRef + 'RangeOptimal'],\
'damageReductionFactor': damageReductionFactor, 'rof': fighter.itemModifiedAttributes[baseRef + 'Duration'],\
}
ability = getFighterAbilityData(fighterAttr, fighter, baseRef)
abilities.append(ability)
if 'fighterAbilityMissilesDamageEM' in fighter.itemModifiedAttributes:
if 'fighterAbilityMissilesDamageEM' in fighterAttr:
baseRef = 'fighterAbilityMissiles'
baseRefDam = baseRef + 'Damage'
damageReductionFactor = log(fighter.itemModifiedAttributes[baseRefDam + 'ReductionFactor']) / log(fighter.itemModifiedAttributes[baseRefDam + 'ReductionSensitivity'])
abBaseDamage = fighter.itemModifiedAttributes[baseRefDam + 'EM'] + fighter.itemModifiedAttributes[baseRefDam + 'Therm'] + fighter.itemModifiedAttributes[baseRefDam + 'Exp'] + fighter.itemModifiedAttributes[baseRefDam + 'Kin']
abDamage = abBaseDamage * fighter.itemModifiedAttributes[baseRefDam + 'Multiplier']
ability = {'name': 'MissileAttack', 'volley': abDamage * fighter.amountActive, 'explosionRadius': fighter.itemModifiedAttributes[baseRef + 'ExplosionRadius'],\
'explosionVelocity': fighter.itemModifiedAttributes[baseRef + 'ExplosionVelocity'], 'optimal': fighter.itemModifiedAttributes[baseRef + 'Range'],\
'damageReductionFactor': damageReductionFactor, 'rof': fighter.itemModifiedAttributes[baseRef + 'Duration'],\
}
ability = getFighterAbilityData(fighterAttr, fighter, baseRef)
abilities.append(ability)
statDict = {'dps': fighter.dps[0], 'type': 'Fighter', 'name': fighter.item.name,\
'maxSpeed': fighter.itemModifiedAttributes['maxVelocity'], 'abilities': abilities, 'ehp': fighter.itemModifiedAttributes['shieldCapacity'] / 0.8875 * fighter.amountActive,\
'volley': fighter.dps[1], 'signatureRadius': fighter.itemModifiedAttributes['signatureRadius']\
statDict = {
'dps': fighter.dps[0], 'type': 'Fighter', 'name': fighter.item.name,
'maxSpeed': fighterAttr['maxVelocity'], 'abilities': abilities,
'ehp': fighterAttr['shieldCapacity'] / 0.8875 * fighter.amountActive,
'volley': fighter.dps[1], 'signatureRadius': fighterAttr['signatureRadius']
}
weaponSystems.append(statDict)
return weaponSystems
def getWeaponBonusMultipliers(fit):
multipliers = {'turret': 1, 'launcher': 1, 'droneBandwidth': 1}
from eos.db import gamedata_session
from eos.gamedata import Traits
filterVal = Traits.typeID == fit.shipID
data = gamedata_session.query(Traits).options().filter(filterVal).all()
roleBonusMode = False
if len(data) == 0:
return multipliers
previousTypedBonus = 0
previousDroneTypeBonus = 0
for bonusText in data[0].traitText.splitlines():
bonusText = bonusText.lower()
if 'per skill level' in bonusText:
roleBonusMode = False
if 'role bonus' in bonusText or 'misc bonus' in bonusText:
roleBonusMode = True
multi = 1
if 'damage' in bonusText and not any(e in bonusText for e in ['control', 'heat']):
splitText = bonusText.split('%')
if (float(splitText[0]) > 0) == False:
print('damage bonus split did not parse correctly!')
print(float(splitText[0]))
if roleBonusMode:
addedMulti = float(splitText[0])
else:
addedMulti = float(splitText[0]) * 5
if any(e in bonusText for e in [' em', 'thermal', 'kinetic', 'explosive']):
if addedMulti > previousTypedBonus:
previousTypedBonus = addedMulti
else:
addedMulti = 0
if any(e in bonusText for e in ['heavy drone', 'medium drone', 'light drone', 'sentry drone']):
if addedMulti > previousDroneTypeBonus:
previousDroneTypeBonus = addedMulti
else:
addedMulti = 0
multi = 1 + (addedMulti / 100)
elif 'rate of fire' in bonusText:
splitText = bonusText.split('%')
if (float(splitText[0]) > 0) == False:
print('rate of fire bonus split did not parse correctly!')
print(float(splitText[0]))
if roleBonusMode:
rofMulti = float(splitText[0])
else:
rofMulti = float(splitText[0]) * 5
multi = 1 / (1 - (rofMulti / 100))
if multi > 1:
if 'drone' in bonusText.lower():
multipliers['droneBandwidth'] *= multi
elif 'turret' in bonusText.lower():
multipliers['turret'] *= multi
elif any(e in bonusText for e in ['missile', 'torpedo']):
multipliers['launcher'] *= multi
return multipliers
def getShipSize(groupID):
# Sizings are somewhat arbitrary but allow for a more managable number of top level groupings in a tree structure.
shipSizes = ['Frigate', 'Destroyer', 'Cruiser', 'Battlecruiser', 'Battleship', 'Capital', 'Industrial', 'Misc']
if groupID in [25, 31, 237, 324, 830, 831, 834, 893, 1283, 1527]:
return shipSizes[0]
elif groupID in [420, 541, 1305, 1534]:
return shipSizes[1]
elif groupID in [26, 358, 832, 833, 894, 906, 963]:
return shipSizes[2]
elif groupID in [419, 540, 1201]:
return shipSizes[3]
elif groupID in [27, 381, 898, 900]:
return shipSizes[4]
elif groupID in [30, 485, 513, 547, 659, 883, 902, 1538]:
return shipSizes[5]
elif groupID in [28, 380, 1202, 463, 543, 941]:
return shipSizes[6]
elif groupID in [29, 1022]:
return shipSizes[7]
wepTestSet = {}
def getTestSet(setType):
def GetT2ItemsWhere(additionalFilter, mustBeOffensive=False, category='Module'):
# Used to obtain a smaller subset of items while still containing examples of each group.
T2_META_LEVEL = 5
metaLevelAttrID = getAttributeInfo('metaLevel').attributeID
categoryID = getCategory(category).categoryID
result = gamedata_session.query(Item).join(ItemEffect, Group, Attribute).\
filter(
additionalFilter,
Attribute.attributeID == metaLevelAttrID,
Attribute.value == T2_META_LEVEL,
Group.categoryID == categoryID,
).all()
if mustBeOffensive:
result = filter(lambda t: t.offensive is True, result)
return list(result)
def getChargeType(item, setType):
if setType == 'turret':
return str(item.attributes['chargeGroup1'].value) + '-' + str(item.attributes['chargeSize'].value)
return str(item.attributes['chargeGroup1'].value)
if setType in wepTestSet.keys():
return wepTestSet[setType]
else:
sizeNotFoundMsg = 'ShipSize not found for groupID: ' + str(groupID)
print(sizeNotFoundMsg)
return sizeNotFoundMsg
wepTestSet[setType] = []
modSet = wepTestSet[setType]
if setType == 'drone':
ilist = GetT2ItemsWhere(True, True, 'Drone')
for item in ilist:
drone = Drone(item)
drone.amount = 1
drone.amountActive = 1
drone.itemModifiedAttributes.parent = drone
modSet.append(drone)
return modSet
turretFittedEffectID = gamedata_session.query(Effect).filter(Effect.name == 'turretFitted').first().effectID
launcherFittedEffectID = gamedata_session.query(Effect).filter(Effect.name == 'launcherFitted').first().effectID
if setType == 'launcher':
effectFilter = ItemEffect.effectID == launcherFittedEffectID
reqOff = False
else:
effectFilter = ItemEffect.effectID == turretFittedEffectID
reqOff = True
ilist = GetT2ItemsWhere(effectFilter, reqOff)
previousChargeTypes = []
# Get modules from item list
for item in ilist:
chargeType = getChargeType(item, setType)
# Only add turrets if we don't already have one with the same size and ammo type.
if setType == 'launcher' or chargeType not in previousChargeTypes:
previousChargeTypes.append(chargeType)
mod = Module(item)
modSet.append(mod)
mkt = Market.getInstance()
# Due to typed missile damage bonuses we'll need to add extra launchers to cover all four types.
additionalLaunchers = []
for mod in modSet:
clist = list(gamedata_session.query(Item).options().
filter(Item.groupID == mod.itemModifiedAttributes['chargeGroup1']).all())
mods = [mod]
charges = [clist[0]]
if setType == 'launcher':
# We don't want variations of missiles we already have
prevCharges = list(mkt.getVariationsByItems(charges))
testCharges = []
for charge in clist:
if charge not in prevCharges:
testCharges.append(charge)
prevCharges += mkt.getVariationsByItems([charge])
for c in testCharges:
charges.append(c)
additionalLauncher = Module(mod.item)
mods.append(additionalLauncher)
for i in range(len(mods)):
mods[i].charge = charges[i]
mods[i].reloadForce = True
mods[i].state = 2
if setType == 'launcher' and i > 0:
additionalLaunchers.append(mods[i])
modSet += additionalLaunchers
return modSet
def getWeaponBonusMultipliers(fit):
def sumDamage(attr):
totalDamage = 0
for damageType in ['emDamage', 'thermalDamage', 'kineticDamage', 'explosiveDamage']:
if attr[damageType] is not None:
totalDamage += attr[damageType]
return totalDamage
def getCurrentMultipliers(tf):
fitMultipliers = {}
getDroneMulti = lambda d: sumDamage(d.itemModifiedAttributes) * d.itemModifiedAttributes['damageMultiplier']
fitMultipliers['drones'] = list(map(getDroneMulti, tf.drones))
getFitTurrets = lambda f: filter(lambda mod: mod.hardpoint == Hardpoint.TURRET, f.modules)
getTurretMulti = lambda mod: mod.itemModifiedAttributes['damageMultiplier'] / mod.cycleTime
fitMultipliers['turrets'] = list(map(getTurretMulti, getFitTurrets(tf)))
getFitLaunchers = lambda f: filter(lambda mod: mod.hardpoint == Hardpoint.MISSILE, f.modules)
getLauncherMulti = lambda mod: sumDamage(mod.chargeModifiedAttributes) / mod.cycleTime
fitMultipliers['launchers'] = list(map(getLauncherMulti, getFitLaunchers(tf)))
return fitMultipliers
multipliers = {'turret': 1, 'launcher': 1, 'droneBandwidth': 1}
drones = getTestSet('drone')
launchers = getTestSet('launcher')
turrets = getTestSet('turret')
for weaponTypeSet in [turrets, launchers, drones]:
for mod in weaponTypeSet:
mod.owner = fit
turrets = list(filter(lambda mod: mod.itemModifiedAttributes['damageMultiplier'], turrets))
launchers = list(filter(lambda mod: sumDamage(mod.chargeModifiedAttributes), launchers))
# Since the effect modules are fairly opaque a mock test fit is used to test the impact of traits.
tf = Fit.getInstance()
tf.modules = HandledList(turrets + launchers)
tf.character = fit.character
tf.ship = fit.ship
tf.drones = HandledList(drones)
tf.fighters = HandledList([])
tf.boosters = HandledList([])
tf.extraAttributes = fit.extraAttributes
tf.mode = fit.mode
preTraitMultipliers = getCurrentMultipliers(tf)
for effect in fit.ship.item.effects.values():
if effect._Effect__effectModule is not None:
effect.handler(tf, tf.ship, [])
# Factor in mode effects for T3 Destroyers
if fit.mode is not None:
for effect in fit.mode.item.effects.values():
if effect._Effect__effectModule is not None:
effect.handler(tf, fit.mode, [])
if fit.ship.item.groupID == getGroup('Strategic Cruiser').ID:
subSystems = list(filter(lambda mod: mod.slot == Slot.SUBSYSTEM and mod.item, fit.modules))
for sub in subSystems:
for effect in sub.item.effects.values():
if effect._Effect__effectModule is not None:
effect.handler(tf, sub, [])
postTraitMultipliers = getCurrentMultipliers(tf)
getMaxRatio = lambda dictA, dictB, key: max(map(lambda a, b: b / a, dictA[key], dictB[key]))
multipliers['turret'] = round(getMaxRatio(preTraitMultipliers, postTraitMultipliers, 'turrets'), 6)
multipliers['launcher'] = round(getMaxRatio(preTraitMultipliers, postTraitMultipliers, 'launchers'), 6)
multipliers['droneBandwidth'] = round(getMaxRatio(preTraitMultipliers, postTraitMultipliers, 'drones'), 6)
tf.recalc(fit)
return multipliers
def getShipSize(groupID):
# Size groupings are somewhat arbitrary but allow for a more managable number of top level groupings in a tree structure.
frigateGroupNames = ['Frigate', 'Shuttle', 'Corvette', 'Assault Frigate', 'Covert Ops', 'Interceptor',
'Stealth Bomber', 'Electronic Attack Ship', 'Expedition Frigate', 'Logistics Frigate']
destroyerGroupNames = ['Destroyer', 'Interdictor', 'Tactical Destroyer', 'Command Destroyer']
cruiserGroupNames = ['Cruiser', 'Heavy Assault Cruiser', 'Logistics', 'Force Recon Ship',
'Heavy Interdiction Cruiser', 'Combat Recon Ship', 'Strategic Cruiser']
bcGroupNames = ['Combat Battlecruiser', 'Command Ship', 'Attack Battlecruiser']
bsGroupNames = ['Battleship', 'Elite Battleship', 'Black Ops', 'Marauder']
capitalGroupNames = ['Titan', 'Dreadnought', 'Freighter', 'Carrier', 'Supercarrier',
'Capital Industrial Ship', 'Jump Freighter', 'Force Auxiliary']
indyGroupNames = ['Industrial', 'Deep Space Transport', 'Blockade Runner',
'Mining Barge', 'Exhumer', 'Industrial Command Ship']
miscGroupNames = ['Capsule', 'Prototype Exploration Ship']
shipSizes = [
{'name': 'Frigate', 'groupIDs': map(lambda s: getGroup(s).ID, frigateGroupNames)},
{'name': 'Destroyer', 'groupIDs': map(lambda s: getGroup(s).ID, destroyerGroupNames)},
{'name': 'Cruiser', 'groupIDs': map(lambda s: getGroup(s).ID, cruiserGroupNames)},
{'name': 'Battlecruiser', 'groupIDs': map(lambda s: getGroup(s).ID, bcGroupNames)},
{'name': 'Battleship', 'groupIDs': map(lambda s: getGroup(s).ID, bsGroupNames)},
{'name': 'Capital', 'groupIDs': map(lambda s: getGroup(s).ID, capitalGroupNames)},
{'name': 'Industrial', 'groupIDs': map(lambda s: getGroup(s).ID, indyGroupNames)},
{'name': 'Misc', 'groupIDs': map(lambda s: getGroup(s).ID, miscGroupNames)}
]
for size in shipSizes:
if groupID in size['groupIDs']:
return size['name']
sizeNotFoundMsg = 'ShipSize not found for groupID: ' + str(groupID)
print(sizeNotFoundMsg)
return sizeNotFoundMsg
def parseNeededFitDetails(fit, groupID):
includeShipTypeData = groupID > 0
@@ -377,13 +549,11 @@ def parseNeededFitDetails(fit, groupID):
fitName = fit.name
print('')
print('name: ' + fit.name)
fitL = Fit()
fitL = Fit.getInstance()
fitL.recalc(fit)
fit = eos.db.getFit(fitID)
fitModAttr = fit.ship.itemModifiedAttributes
propData = getPropData(fit, fitL)
print(fitModAttr['rigSize'])
print(propData)
mwdPropSpeed = fit.maxSpeed
if includeShipTypeData:
mwdPropSpeed = getT2MwdSpeed(fit, fitL)
@@ -395,52 +565,52 @@ def parseNeededFitDetails(fit, groupID):
launcherSlots = fitModAttr['launcherSlotsLeft'] if fitModAttr['launcherSlotsLeft'] is not None else 0
droneBandwidth = fitModAttr['droneBandwidth'] if fitModAttr['droneBandwidth'] is not None else 0
weaponBonusMultipliers = getWeaponBonusMultipliers(fit)
effectiveTurretSlots = round(turretSlots * weaponBonusMultipliers['turret'], 2);
effectiveLauncherSlots = round(launcherSlots * weaponBonusMultipliers['launcher'], 2);
effectiveDroneBandwidth = round(droneBandwidth * weaponBonusMultipliers['droneBandwidth'], 2);
effectiveTurretSlots = round(turretSlots * weaponBonusMultipliers['turret'], 2)
effectiveLauncherSlots = round(launcherSlots * weaponBonusMultipliers['launcher'], 2)
effectiveDroneBandwidth = round(droneBandwidth * weaponBonusMultipliers['droneBandwidth'], 2)
# Assume a T2 siege module for dreads
if groupID == 485:
if groupID == getGroup('Dreadnought').ID:
effectiveTurretSlots *= 9.4
effectiveLauncherSlots *= 15
hullResonance = {
'exp': fitModAttr['explosiveDamageResonance'], 'kin': fitModAttr['kineticDamageResonance'], \
'exp': fitModAttr['explosiveDamageResonance'], 'kin': fitModAttr['kineticDamageResonance'],
'therm': fitModAttr['thermalDamageResonance'], 'em': fitModAttr['emDamageResonance']
}
armorResonance = {
'exp': fitModAttr['armorExplosiveDamageResonance'], 'kin': fitModAttr['armorKineticDamageResonance'], \
'exp': fitModAttr['armorExplosiveDamageResonance'], 'kin': fitModAttr['armorKineticDamageResonance'],
'therm': fitModAttr['armorThermalDamageResonance'], 'em': fitModAttr['armorEmDamageResonance']
}
shieldResonance = {
'exp': fitModAttr['shieldExplosiveDamageResonance'], 'kin': fitModAttr['shieldKineticDamageResonance'], \
'exp': fitModAttr['shieldExplosiveDamageResonance'], 'kin': fitModAttr['shieldKineticDamageResonance'],
'therm': fitModAttr['shieldThermalDamageResonance'], 'em': fitModAttr['shieldEmDamageResonance']
}
resonance = {'hull': hullResonance, 'armor': armorResonance, 'shield': shieldResonance}
shipSize = getShipSize(groupID)
try:
parsable = {
'name': fitName, 'ehp': fit.ehp, 'droneDPS': fit.droneDPS, \
'droneVolley': fit.droneVolley, 'hp': fit.hp, 'maxTargets': fit.maxTargets, \
'maxSpeed': fit.maxSpeed, 'weaponVolley': fit.weaponVolley, 'totalVolley': fit.totalVolley,\
'maxTargetRange': fit.maxTargetRange, 'scanStrength': fit.scanStrength,\
'weaponDPS': fit.weaponDPS, 'alignTime': fit.alignTime, 'signatureRadius': fitModAttr['signatureRadius'],\
'weapons': weaponSystems, 'scanRes': fitModAttr['scanResolution'],\
'projectedModules': fit.projectedModules, 'capUsed': fit.capUsed, 'capRecharge': fit.capRecharge,\
'rigSlots': fitModAttr['rigSlots'], 'lowSlots': fitModAttr['lowSlots'],\
'midSlots': fitModAttr['medSlots'], 'highSlots': fitModAttr['hiSlots'],\
'turretSlots': fitModAttr['turretSlotsLeft'], 'launcherSlots': fitModAttr['launcherSlotsLeft'],\
'powerOutput': fitModAttr['powerOutput'], 'rigSize': fitModAttr['rigSize'],\
'effectiveTurrets': effectiveTurretSlots, 'effectiveLaunchers': effectiveLauncherSlots,\
'effectiveDroneBandwidth': effectiveDroneBandwidth,\
'resonance': resonance, 'typeID': fit.shipID, 'groupID': groupID, 'shipSize': shipSize,\
'droneControlRange': fitModAttr['droneControlRange'], 'mass': fitModAttr['mass'],\
'moduleNames': moduleNames, 'projections': projections,\
'unpropedSpeed': propData['unpropedSpeed'], 'unpropedSig': propData['unpropedSig'],\
dataDict = {
'name': fitName, 'ehp': fit.ehp, 'droneDPS': fit.droneDPS,
'droneVolley': fit.droneVolley, 'hp': fit.hp, 'maxTargets': fit.maxTargets,
'maxSpeed': fit.maxSpeed, 'weaponVolley': fit.weaponVolley, 'totalVolley': fit.totalVolley,
'maxTargetRange': fit.maxTargetRange, 'scanStrength': fit.scanStrength,
'weaponDPS': fit.weaponDPS, 'alignTime': fit.alignTime, 'signatureRadius': fitModAttr['signatureRadius'],
'weapons': weaponSystems, 'scanRes': fitModAttr['scanResolution'],
'projectedModules': fit.projectedModules, 'capUsed': fit.capUsed, 'capRecharge': fit.capRecharge,
'rigSlots': fitModAttr['rigSlots'], 'lowSlots': fitModAttr['lowSlots'],
'midSlots': fitModAttr['medSlots'], 'highSlots': fitModAttr['hiSlots'],
'turretSlots': fitModAttr['turretSlotsLeft'], 'launcherSlots': fitModAttr['launcherSlotsLeft'],
'powerOutput': fitModAttr['powerOutput'], 'rigSize': fitModAttr['rigSize'],
'effectiveTurrets': effectiveTurretSlots, 'effectiveLaunchers': effectiveLauncherSlots,
'effectiveDroneBandwidth': effectiveDroneBandwidth,
'resonance': resonance, 'typeID': fit.shipID, 'groupID': groupID, 'shipSize': shipSize,
'droneControlRange': fitModAttr['droneControlRange'], 'mass': fitModAttr['mass'],
'moduleNames': moduleNames, 'projections': projections,
'unpropedSpeed': propData['unpropedSpeed'], 'unpropedSig': propData['unpropedSig'],
'usingMWD': propData['usingMWD'], 'mwdPropSpeed': mwdPropSpeed
}
except TypeError:
print('Error parsing fit:' + str(fit))
print(TypeError)
parsable = {'name': fitName + 'Fit could not be correctly parsed'}
stringified = json.dumps(parsable, skipkeys=True)
return stringified
export = json.dumps(dataDict, skipkeys=True)
return export