Merge tag 'v2.4.0' into commandRefactor
# Conflicts: # gui/builtinViews/fittingView.py # service/fit.py
@@ -24,10 +24,10 @@ saveInRoot = False
|
||||
|
||||
# Version data
|
||||
|
||||
version = "2.3.1"
|
||||
version = "2.4.0"
|
||||
tag = "Stable"
|
||||
expansionName = "YC120.7"
|
||||
expansionVersion = "1.2"
|
||||
expansionName = "YC120.8"
|
||||
expansionVersion = "1.0"
|
||||
evemonMinVersion = "4081"
|
||||
|
||||
minItemSearchLength = 3
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# boosterShieldCapacityPenalty
|
||||
#
|
||||
# Used by:
|
||||
# Implants from group: Booster (12 of 66)
|
||||
# Implants from group: Booster (12 of 65)
|
||||
type = "boosterSideEffect"
|
||||
|
||||
# User-friendly name for the side effect
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
# Used by:
|
||||
# Ships from group: Black Ops (5 of 5)
|
||||
# Ships from group: Blockade Runner (4 of 4)
|
||||
# Ships from group: Covert Ops (7 of 7)
|
||||
# Ships from group: Covert Ops (8 of 8)
|
||||
# Ships from group: Expedition Frigate (2 of 2)
|
||||
# Ships from group: Force Recon Ship (8 of 8)
|
||||
# Ships from group: Force Recon Ship (9 of 9)
|
||||
# Ships from group: Stealth Bomber (5 of 5)
|
||||
# Ships named like: Stratios (2 of 2)
|
||||
# Subsystems named like: Defensive Covert Reconfiguration (4 of 4)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# covertOpsCloakCpuPercentBonus1
|
||||
#
|
||||
# Used by:
|
||||
# Ships from group: Covert Ops (5 of 7)
|
||||
# Ships from group: Covert Ops (6 of 8)
|
||||
type = "passive"
|
||||
runTime = "early"
|
||||
|
||||
|
||||
9
eos/effects/covertopswarpresistance.py
Normal file
@@ -0,0 +1,9 @@
|
||||
# covertOpsWarpResistance
|
||||
#
|
||||
# Used by:
|
||||
# Ships from group: Covert Ops (5 of 8)
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, src, context):
|
||||
fit.ship.increaseItemAttr("warpFactor", src.getModifiedItemAttr("eliteBonusCovertOps1"), skill="Covert Ops")
|
||||
@@ -1,7 +1,7 @@
|
||||
# cynosuralDurationBonus
|
||||
#
|
||||
# Used by:
|
||||
# Ships from group: Force Recon Ship (7 of 8)
|
||||
# Ships from group: Force Recon Ship (8 of 9)
|
||||
type = "passive"
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# cynosuralTheoryConsumptionBonus
|
||||
#
|
||||
# Used by:
|
||||
# Ships from group: Force Recon Ship (7 of 8)
|
||||
# Ships from group: Force Recon Ship (8 of 9)
|
||||
# Skill: Cynosural Field Theory
|
||||
type = "passive"
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# eliteBonusCoverOpsScanProbeStrength2
|
||||
#
|
||||
# Used by:
|
||||
# Ships from group: Covert Ops (7 of 7)
|
||||
# Ships from group: Covert Ops (8 of 8)
|
||||
type = "passive"
|
||||
|
||||
|
||||
|
||||
10
eos/effects/elitebonusmaxdmgmultibonusadd.py
Normal file
@@ -0,0 +1,10 @@
|
||||
# eliteBonusMaxDmgMultiBonusAdd
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Hydra
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, src, context):
|
||||
fit.modules.filteredItemIncrease(lambda mod: mod.item.requiresSkill("Small Precursor Weapon"), "damageMultiplierBonusMax",
|
||||
src.getModifiedItemAttr("eliteBonusCovertOps3"), skill="Covert Ops")
|
||||
10
eos/effects/elitebonusreconmaxdmgmultimaxhpt.py
Normal file
@@ -0,0 +1,10 @@
|
||||
# eliteBonusReconMaxDmgMultiMaxHPT
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Tiamat
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, src, context):
|
||||
fit.modules.filteredItemIncrease(lambda mod: mod.item.requiresSkill("Medium Precursor Weapon"), "damageMultiplierBonusMax",
|
||||
src.getModifiedItemAttr("eliteBonusReconShip3"), skill="Recon Ships")
|
||||
10
eos/effects/elitebonusreconscanprobestrength2.py
Normal file
@@ -0,0 +1,10 @@
|
||||
# eliteBonusReconScanProbeStrength2
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Tiamat
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, src, context):
|
||||
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Astrometrics"), "baseSensorStrength",
|
||||
src.getModifiedItemAttr("eliteBonusReconShip2"), skill="Recon Ships")
|
||||
@@ -1,7 +1,7 @@
|
||||
# minigameVirusStrengthBonus
|
||||
#
|
||||
# Used by:
|
||||
# Ships from group: Covert Ops (7 of 7)
|
||||
# Ships from group: Covert Ops (7 of 8)
|
||||
# Ships named like: Stratios (2 of 2)
|
||||
# Subsystems named like: Defensive Covert Reconfiguration (4 of 4)
|
||||
# Ship: Astero
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# reconShipCloakCpuBonus1
|
||||
#
|
||||
# Used by:
|
||||
# Ships from group: Force Recon Ship (6 of 8)
|
||||
# Ships from group: Force Recon Ship (7 of 9)
|
||||
type = "passive"
|
||||
runTime = "early"
|
||||
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Damavik
|
||||
# Ship: Hydra
|
||||
# Ship: Leshak
|
||||
# Ship: Tiamat
|
||||
# Ship: Vedmak
|
||||
type = "passive"
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# shipbonusPCTDamagePC1
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Tiamat
|
||||
# Ship: Vedmak
|
||||
type = "passive"
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Damavik
|
||||
# Ship: Hydra
|
||||
type = "passive"
|
||||
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Damavik
|
||||
# Ship: Hydra
|
||||
type = "passive"
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# shipbonusPCTTrackingPC2
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Tiamat
|
||||
# Ship: Vedmak
|
||||
type = "passive"
|
||||
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Damavik
|
||||
# Ship: Hydra
|
||||
# Ship: Leshak
|
||||
# Ship: Tiamat
|
||||
# Ship: Vedmak
|
||||
type = "passive"
|
||||
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Damavik
|
||||
# Ship: Hydra
|
||||
# Ship: Leshak
|
||||
# Ship: Tiamat
|
||||
# Ship: Vedmak
|
||||
type = "passive"
|
||||
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Damavik
|
||||
# Ship: Hydra
|
||||
# Ship: Leshak
|
||||
# Ship: Tiamat
|
||||
# Ship: Vedmak
|
||||
type = "passive"
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# shipBonusSurveyProbeExplosionDelaySkillSurveyCovertOps3
|
||||
#
|
||||
# Used by:
|
||||
# Ships from group: Covert Ops (5 of 7)
|
||||
# Ships from group: Covert Ops (5 of 8)
|
||||
type = "passive"
|
||||
|
||||
|
||||
|
||||
@@ -29,19 +29,21 @@ class CopySelectDialog(wx.Dialog):
|
||||
copyFormatDna = 3
|
||||
copyFormatEsi = 4
|
||||
copyFormatMultiBuy = 5
|
||||
copyFormatEfs = 6
|
||||
|
||||
def __init__(self, parent):
|
||||
wx.Dialog.__init__(self, parent, id=wx.ID_ANY, title="Select a format", size=(-1, -1),
|
||||
style=wx.DEFAULT_DIALOG_STYLE)
|
||||
mainSizer = wx.BoxSizer(wx.VERTICAL)
|
||||
|
||||
copyFormats = ["EFT", "EFT (Implants)", "XML", "DNA", "ESI", "MultiBuy"]
|
||||
copyFormats = ["EFT", "EFT (Implants)", "XML", "DNA", "ESI", "MultiBuy", "EFS"]
|
||||
copyFormatTooltips = {CopySelectDialog.copyFormatEft: "EFT text format",
|
||||
CopySelectDialog.copyFormatEftImps: "EFT text format",
|
||||
CopySelectDialog.copyFormatXml: "EVE native XML format",
|
||||
CopySelectDialog.copyFormatDna: "A one-line text format",
|
||||
CopySelectDialog.copyFormatEsi: "A JSON format used for EVE CREST",
|
||||
CopySelectDialog.copyFormatMultiBuy: "MultiBuy text format"}
|
||||
CopySelectDialog.copyFormatMultiBuy: "MultiBuy text format",
|
||||
CopySelectDialog.copyFormatEfs: "JSON data format used by EFS"}
|
||||
selector = wx.RadioBox(self, wx.ID_ANY, label="Copy to the clipboard using:", choices=copyFormats,
|
||||
style=wx.RA_SPECIFY_ROWS)
|
||||
selector.Bind(wx.EVT_RADIOBOX, self.Selected)
|
||||
|
||||
@@ -77,6 +77,7 @@ from eos.modifiedAttributeDict import ModifiedAttributeDict
|
||||
from eos.db.saveddata.loadDefaultDatabaseValues import DefaultDatabaseValues
|
||||
from eos.db.saveddata.queries import getFit as db_getFit
|
||||
from service.port import Port, IPortUser
|
||||
from service.efsPort import EfsPort
|
||||
from service.settings import HTMLExportSettings
|
||||
|
||||
from time import gmtime, strftime
|
||||
@@ -734,6 +735,10 @@ class MainFrame(wx.Frame):
|
||||
fit = db_getFit(self.getActiveFit())
|
||||
toClipboard(Port.exportMultiBuy(fit))
|
||||
|
||||
def clipboardEfs(self):
|
||||
fit = db_getFit(self.getActiveFit())
|
||||
toClipboard(EfsPort.exportEfs(fit, 0))
|
||||
|
||||
def importFromClipboard(self, event):
|
||||
clipboard = fromClipboard()
|
||||
try:
|
||||
@@ -749,7 +754,8 @@ class MainFrame(wx.Frame):
|
||||
CopySelectDialog.copyFormatXml: self.clipboardXml,
|
||||
CopySelectDialog.copyFormatDna: self.clipboardDna,
|
||||
CopySelectDialog.copyFormatEsi: self.clipboardEsi,
|
||||
CopySelectDialog.copyFormatMultiBuy: self.clipboardMultiBuy}
|
||||
CopySelectDialog.copyFormatMultiBuy: self.clipboardMultiBuy,
|
||||
CopySelectDialog.copyFormatEfs: self.clipboardEfs}
|
||||
dlg = CopySelectDialog(self)
|
||||
dlg.ShowModal()
|
||||
selected = dlg.GetSelected()
|
||||
|
||||
BIN
imgs/icons/10160.png
Normal file
|
After Width: | Height: | Size: 783 B |
BIN
imgs/icons/10851.png
Normal file
|
After Width: | Height: | Size: 682 B |
BIN
imgs/icons/21785.png
Normal file
|
After Width: | Height: | Size: 739 B |
BIN
imgs/icons/22029.png
Normal file
|
After Width: | Height: | Size: 883 B |
BIN
imgs/icons/22030.png
Normal file
|
After Width: | Height: | Size: 723 B |
BIN
imgs/icons/22031.png
Normal file
|
After Width: | Height: | Size: 874 B |
BIN
imgs/icons/22034.png
Normal file
|
After Width: | Height: | Size: 574 B |
BIN
imgs/icons/22036.png
Normal file
|
After Width: | Height: | Size: 812 B |
BIN
imgs/icons/22041.png
Normal file
|
After Width: | Height: | Size: 545 B |
BIN
imgs/renders/21344.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
imgs/renders/21362.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
imgs/renders/21405.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
imgs/renders/21406.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
@@ -141,6 +141,7 @@ def get_icon_file(res_path, size):
|
||||
icon for it. Return as PIL image object down-
|
||||
scaled for use in pyfa.
|
||||
"""
|
||||
res_path = res_path.replace('//', '/') #1703
|
||||
if res_path not in res_index:
|
||||
return None
|
||||
res_icon = res_index[res_path]
|
||||
@@ -192,7 +193,10 @@ if toadd:
|
||||
print(('Adding {} icons...'.format(len(toadd))))
|
||||
missing = set()
|
||||
for fname in sorted(toadd):
|
||||
icon = icon_json[str(fname)]
|
||||
icon = icon_json.get(str(fname), None)
|
||||
if icon is None:
|
||||
print("Can't find iconID {}".format(fname))
|
||||
continue
|
||||
key = icon['iconFile'].lower()
|
||||
icon = get_icon_file(key, ICON_SIZE)
|
||||
if icon is None:
|
||||
|
||||
@@ -25,7 +25,7 @@ import re
|
||||
|
||||
# Add eos root path to sys.path so we can import ourselves
|
||||
path = os.path.dirname(__file__)
|
||||
sys.path.insert(0, os.path.realpath(os.path.join(path, "..")))
|
||||
sys.path.insert(0, os.path.realpath(os.path.join(path, '..')))
|
||||
|
||||
import json
|
||||
import argparse
|
||||
@@ -54,65 +54,65 @@ def main(db, json_path):
|
||||
|
||||
# Config dict
|
||||
tables = {
|
||||
"clonegrades": eos.gamedata.AlphaCloneSkill,
|
||||
"dgmattribs": eos.gamedata.AttributeInfo,
|
||||
"dgmeffects": eos.gamedata.Effect,
|
||||
"dgmtypeattribs": eos.gamedata.Attribute,
|
||||
"dgmtypeeffects": eos.gamedata.ItemEffect,
|
||||
"dgmunits": eos.gamedata.Unit,
|
||||
"evecategories": eos.gamedata.Category,
|
||||
"evegroups": eos.gamedata.Group,
|
||||
"invmetagroups": eos.gamedata.MetaGroup,
|
||||
"invmetatypes": eos.gamedata.MetaType,
|
||||
"evetypes": eos.gamedata.Item,
|
||||
"phbtraits": eos.gamedata.Traits,
|
||||
"phbmetadata": eos.gamedata.MetaData,
|
||||
"mapbulk_marketGroups": eos.gamedata.MarketGroup,
|
||||
'clonegrades': eos.gamedata.AlphaCloneSkill,
|
||||
'dgmattribs': eos.gamedata.AttributeInfo,
|
||||
'dgmeffects': eos.gamedata.Effect,
|
||||
'dgmtypeattribs': eos.gamedata.Attribute,
|
||||
'dgmtypeeffects': eos.gamedata.ItemEffect,
|
||||
'dgmunits': eos.gamedata.Unit,
|
||||
'evecategories': eos.gamedata.Category,
|
||||
'evegroups': eos.gamedata.Group,
|
||||
'invmetagroups': eos.gamedata.MetaGroup,
|
||||
'invmetatypes': eos.gamedata.MetaType,
|
||||
'evetypes': eos.gamedata.Item,
|
||||
'phbtraits': eos.gamedata.Traits,
|
||||
'phbmetadata': eos.gamedata.MetaData,
|
||||
'mapbulk_marketGroups': eos.gamedata.MarketGroup,
|
||||
}
|
||||
|
||||
fieldMapping = {
|
||||
"dgmattribs": {
|
||||
"displayName_en-us": "displayName"
|
||||
'dgmattribs': {
|
||||
'displayName_en-us': 'displayName'
|
||||
},
|
||||
"dgmeffects": {
|
||||
"displayName_en-us": "displayName",
|
||||
"description_en-us": "description"
|
||||
'dgmeffects': {
|
||||
'displayName_en-us': 'displayName',
|
||||
'description_en-us': 'description'
|
||||
},
|
||||
"dgmunits": {
|
||||
"displayName_en-us": "displayName"
|
||||
'dgmunits': {
|
||||
'displayName_en-us': 'displayName'
|
||||
},
|
||||
#icons???
|
||||
"evecategories": {
|
||||
"categoryName_en-us": "categoryName"
|
||||
'evecategories': {
|
||||
'categoryName_en-us': 'categoryName'
|
||||
},
|
||||
"evegroups": {
|
||||
"groupName_en-us": "groupName"
|
||||
'evegroups': {
|
||||
'groupName_en-us': 'groupName'
|
||||
},
|
||||
"invmetagroups": {
|
||||
"metaGroupName_en-us": "metaGroupName"
|
||||
'invmetagroups': {
|
||||
'metaGroupName_en-us': 'metaGroupName'
|
||||
},
|
||||
"evetypes": {
|
||||
"typeName_en-us": "typeName",
|
||||
"description_en-us": "description"
|
||||
'evetypes': {
|
||||
'typeName_en-us': 'typeName',
|
||||
'description_en-us': 'description'
|
||||
},
|
||||
#phbtraits???
|
||||
"mapbulk_marketGroups": {
|
||||
"marketGroupName_en-us": "marketGroupName",
|
||||
"description_en-us": "description"
|
||||
'mapbulk_marketGroups': {
|
||||
'marketGroupName_en-us': 'marketGroupName',
|
||||
'description_en-us': 'description'
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
rowsInValues = (
|
||||
"evetypes",
|
||||
"evegroups",
|
||||
"evecategories"
|
||||
'evetypes',
|
||||
'evegroups',
|
||||
'evecategories'
|
||||
)
|
||||
|
||||
def convertIcons(data):
|
||||
new = []
|
||||
for k, v in list(data.items()):
|
||||
v["iconID"] = k
|
||||
v['iconID'] = k
|
||||
new.append(v)
|
||||
return new
|
||||
|
||||
@@ -126,23 +126,23 @@ def main(db, json_path):
|
||||
check = {}
|
||||
|
||||
for ID in data:
|
||||
for skill in data[ID]["skills"]:
|
||||
for skill in data[ID]['skills']:
|
||||
newData.append({
|
||||
"alphaCloneID": int(ID),
|
||||
"alphaCloneName": "Alpha Clone",
|
||||
"typeID": skill["typeID"],
|
||||
"level": skill["level"]})
|
||||
'alphaCloneID': int(ID),
|
||||
'alphaCloneName': 'Alpha Clone',
|
||||
'typeID': skill['typeID'],
|
||||
'level': skill['level']})
|
||||
if ID not in check:
|
||||
check[ID] = {}
|
||||
check[ID][int(skill["typeID"])] = int(skill["level"])
|
||||
check[ID][int(skill['typeID'])] = int(skill['level'])
|
||||
|
||||
if not functools.reduce(lambda a, b: a if a == b else False, [v for _, v in check.items()]):
|
||||
raise Exception("Alpha Clones not all equal")
|
||||
raise Exception('Alpha Clones not all equal')
|
||||
|
||||
newData = [x for x in newData if x['alphaCloneID'] == 1]
|
||||
|
||||
if len(newData) == 0:
|
||||
raise Exception("Alpha Clone processing failed")
|
||||
raise Exception('Alpha Clone processing failed')
|
||||
|
||||
return newData
|
||||
|
||||
@@ -150,28 +150,28 @@ def main(db, json_path):
|
||||
|
||||
def convertSection(sectionData):
|
||||
sectionLines = []
|
||||
headerText = "<b>{}</b>".format(sectionData["header"])
|
||||
headerText = '<b>{}</b>'.format(sectionData['header'])
|
||||
sectionLines.append(headerText)
|
||||
for bonusData in sectionData["bonuses"]:
|
||||
prefix = "{} ".format(bonusData["number"]) if "number" in bonusData else ""
|
||||
bonusText = "{}{}".format(prefix, bonusData["text"].replace("\u00B7", "\u2022 "))
|
||||
for bonusData in sectionData['bonuses']:
|
||||
prefix = '{} '.format(bonusData['number']) if 'number' in bonusData else ''
|
||||
bonusText = '{}{}'.format(prefix, bonusData['text'].replace('\u00B7', '\u2022 '))
|
||||
sectionLines.append(bonusText)
|
||||
sectionLine = "<br />\n".join(sectionLines)
|
||||
sectionLine = '<br />\n'.join(sectionLines)
|
||||
return sectionLine
|
||||
|
||||
newData = []
|
||||
for row in data:
|
||||
typeLines = []
|
||||
typeId = row["typeID"]
|
||||
traitData = row["traits"]
|
||||
for skillData in sorted(traitData.get("skills", ()), key=lambda i: i["header"]):
|
||||
typeId = row['typeID']
|
||||
traitData = row['traits_en-us']
|
||||
for skillData in sorted(traitData.get('skills', ()), key=lambda i: i['header']):
|
||||
typeLines.append(convertSection(skillData))
|
||||
if "role" in traitData:
|
||||
typeLines.append(convertSection(traitData["role"]))
|
||||
if "misc" in traitData:
|
||||
typeLines.append(convertSection(traitData["misc"]))
|
||||
traitLine = "<br />\n<br />\n".join(typeLines)
|
||||
newRow = {"typeID": typeId, "traitText": traitLine}
|
||||
if 'role' in traitData:
|
||||
typeLines.append(convertSection(traitData['role']))
|
||||
if 'misc' in traitData:
|
||||
typeLines.append(convertSection(traitData['misc']))
|
||||
traitLine = '<br />\n<br />\n'.join(typeLines)
|
||||
newRow = {'typeID': typeId, 'traitText': traitLine}
|
||||
newData.append(newRow)
|
||||
return newData
|
||||
|
||||
@@ -179,15 +179,15 @@ def main(db, json_path):
|
||||
|
||||
# Dump all data to memory so we can easely cross check ignored rows
|
||||
for jsonName, cls in tables.items():
|
||||
with open(os.path.join(jsonPath, "{}.json".format(jsonName)), encoding="utf-8") as f:
|
||||
with open(os.path.join(jsonPath, '{}.json'.format(jsonName)), encoding='utf-8') as f:
|
||||
tableData = json.load(f)
|
||||
if jsonName in rowsInValues:
|
||||
tableData = list(tableData.values())
|
||||
if jsonName == "icons":
|
||||
if jsonName == 'icons':
|
||||
tableData = convertIcons(tableData)
|
||||
if jsonName == "phbtraits":
|
||||
if jsonName == 'phbtraits':
|
||||
tableData = convertTraits(tableData)
|
||||
if jsonName == "clonegrades":
|
||||
if jsonName == 'clonegrades':
|
||||
tableData = convertClones(tableData)
|
||||
data[jsonName] = tableData
|
||||
|
||||
@@ -195,23 +195,23 @@ def main(db, json_path):
|
||||
# Sometimes CCP unpublishes some items we want to have published, we
|
||||
# can do it here - just add them to initial set
|
||||
eveTypes = set()
|
||||
for row in data["evetypes"]:
|
||||
if (row["published"]
|
||||
for row in data['evetypes']:
|
||||
if (row['published']
|
||||
or row['groupID'] == 1306 # group Ship Modifiers, for items like tactical t3 ship modes
|
||||
or row['typeName'].startswith('Civilian') # Civilian weapons
|
||||
or row['typeName_en-us'].startswith('Civilian') # Civilian weapons
|
||||
or row['typeID'] in (41549, 41548, 41551, 41550) # Micro Bombs (Fighters)
|
||||
or row['groupID'] in (
|
||||
1882,
|
||||
1975,
|
||||
1971,
|
||||
1983 # the "container" for the abysmal environments
|
||||
) # Abysmal weather (environment)
|
||||
1983 # the "container" for the abyssal environments
|
||||
) # Abyssal weather (environment)
|
||||
):
|
||||
eveTypes.add(row["typeID"])
|
||||
eveTypes.add(row['typeID'])
|
||||
|
||||
# ignore checker
|
||||
def isIgnored(file, row):
|
||||
if file in ("evetypes", "dgmtypeeffects", "dgmtypeattribs", "invmetatypes") and row['typeID'] not in eveTypes:
|
||||
if file in ('evetypes', 'dgmtypeeffects', 'dgmtypeattribs', 'invmetatypes') and row['typeID'] not in eveTypes:
|
||||
return True
|
||||
return False
|
||||
|
||||
@@ -220,31 +220,31 @@ def main(db, json_path):
|
||||
fieldMap = fieldMapping.get(jsonName, {})
|
||||
tmp = []
|
||||
|
||||
print("processing {}".format(jsonName))
|
||||
print('processing {}'.format(jsonName))
|
||||
|
||||
for row in table:
|
||||
# We don't care about some kind of rows, filter it out if so
|
||||
if not isIgnored(jsonName, row):
|
||||
if jsonName == 'evetypes' and row["typeName"].startswith('Civilian'): # Apparently people really want Civilian modules available
|
||||
row["published"] = True
|
||||
if jsonName == 'evetypes' and row['typeName_en-us'].startswith('Civilian'): # Apparently people really want Civilian modules available
|
||||
row['published'] = True
|
||||
|
||||
instance = tables[jsonName]()
|
||||
# fix for issue 80
|
||||
if jsonName is "icons" and "res:/ui/texture/icons/" in str(row["iconFile"]).lower():
|
||||
row["iconFile"] = row["iconFile"].lower().replace("res:/ui/texture/icons/", "").replace(".png", "")
|
||||
if jsonName is 'icons' and 'res:/ui/texture/icons/' in str(row['iconFile']).lower():
|
||||
row['iconFile'] = row['iconFile'].lower().replace('res:/ui/texture/icons/', '').replace('.png', '')
|
||||
# with res:/ui... references, it points to the actual icon file (including it's size variation of #_size_#)
|
||||
# strip this info out and get the identifying info
|
||||
split = row['iconFile'].split('_')
|
||||
if len(split) == 3:
|
||||
row['iconFile'] = "{}_{}".format(split[0], split[2])
|
||||
if jsonName is "icons" and "modules/" in str(row["iconFile"]).lower():
|
||||
row["iconFile"] = row["iconFile"].lower().replace("modules/", "").replace(".png", "")
|
||||
row['iconFile'] = '{}_{}'.format(split[0], split[2])
|
||||
if jsonName is 'icons' and 'modules/' in str(row['iconFile']).lower():
|
||||
row['iconFile'] = row['iconFile'].lower().replace('modules/', '').replace('.png', '')
|
||||
|
||||
if jsonName is "clonegrades":
|
||||
if (row["alphaCloneID"] not in tmp):
|
||||
if jsonName is 'clonegrades':
|
||||
if (row['alphaCloneID'] not in tmp):
|
||||
cloneParent = eos.gamedata.AlphaClone()
|
||||
setattr(cloneParent, "alphaCloneID", row["alphaCloneID"])
|
||||
setattr(cloneParent, "alphaCloneName", row["alphaCloneName"])
|
||||
setattr(cloneParent, 'alphaCloneID', row['alphaCloneID'])
|
||||
setattr(cloneParent, 'alphaCloneName', row['alphaCloneName'])
|
||||
eos.db.gamedata_session.add(cloneParent)
|
||||
tmp.append(row['alphaCloneID'])
|
||||
|
||||
@@ -256,7 +256,7 @@ def main(db, json_path):
|
||||
eos.db.gamedata_session.add(instance)
|
||||
|
||||
# quick and dirty hack to get this data in
|
||||
with open(os.path.join(jsonPath, "dynamicAttributes.json"), encoding="utf-8") as f:
|
||||
with open(os.path.join(jsonPath, 'dynamicAttributes.json'), encoding='utf-8') as f:
|
||||
bulkdata = json.load(f)
|
||||
for mutaID, data in bulkdata.items():
|
||||
muta = eos.gamedata.DynamicItem()
|
||||
@@ -283,25 +283,25 @@ def main(db, json_path):
|
||||
# CCP still has 5 subsystems assigned to T3Cs, even though only 4 are available / usable. They probably have some
|
||||
# old legacy requirement or assumption that makes it difficult for them to change this value in the data. But for
|
||||
# pyfa, we can do it here as a post-processing step
|
||||
eos.db.gamedata_engine.execute("UPDATE dgmtypeattribs SET value = 4.0 WHERE attributeID = ?", (1367,))
|
||||
eos.db.gamedata_engine.execute('UPDATE dgmtypeattribs SET value = 4.0 WHERE attributeID = ?', (1367,))
|
||||
|
||||
eos.db.gamedata_engine.execute("UPDATE invtypes SET published = 0 WHERE typeName LIKE '%abyssal%'")
|
||||
eos.db.gamedata_engine.execute('UPDATE invtypes SET published = 0 WHERE typeName LIKE \'%abyssal%\'')
|
||||
|
||||
print()
|
||||
for x in CATEGORIES_TO_REMOVE:
|
||||
cat = eos.db.gamedata_session.query(eos.gamedata.Category).filter(eos.gamedata.Category.ID == x).first()
|
||||
print ("Removing Category: {}".format(cat.name))
|
||||
print ('Removing Category: {}'.format(cat.name))
|
||||
eos.db.gamedata_session.delete(cat)
|
||||
|
||||
eos.db.gamedata_session.commit()
|
||||
eos.db.gamedata_engine.execute("VACUUM")
|
||||
eos.db.gamedata_engine.execute('VACUUM')
|
||||
|
||||
print("done")
|
||||
print('done')
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description="This scripts dumps effects from an sqlite cache dump to mongo")
|
||||
parser.add_argument("-d", "--db", required=True, type=str, help="The sqlalchemy connectionstring, example: sqlite:///c:/tq.db")
|
||||
parser.add_argument("-j", "--json", required=True, type=str, help="The path to the json dump")
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(description='This scripts dumps effects from an sqlite cache dump to mongo')
|
||||
parser.add_argument('-d', '--db', required=True, type=str, help='The sqlalchemy connectionstring, example: sqlite:///c:/tq.db')
|
||||
parser.add_argument('-j', '--json', required=True, type=str, help='The path to the json dump')
|
||||
args = parser.parse_args()
|
||||
|
||||
main(args.db, args.json)
|
||||
|
||||
640
service/efsPort.py
Executable file
@@ -0,0 +1,640 @@
|
||||
import inspect
|
||||
import os
|
||||
import platform
|
||||
import re
|
||||
import sys
|
||||
import traceback
|
||||
import json
|
||||
import eos.db
|
||||
|
||||
from math import log
|
||||
from config import version as pyfaVersion
|
||||
from service.fit import Fit
|
||||
from service.market import Market
|
||||
from eos.enum import Enum
|
||||
from eos.saveddata.module import Hardpoint, Slot, Module, State
|
||||
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
|
||||
from logbook import Logger
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
class RigSize(Enum):
|
||||
# Matches to item attribute "rigSize" on ship and rig items
|
||||
SMALL = 1
|
||||
MEDIUM = 2
|
||||
LARGE = 3
|
||||
CAPITAL = 4
|
||||
|
||||
|
||||
class EfsPort():
|
||||
wepTestSet = {}
|
||||
version = 0.01
|
||||
|
||||
@staticmethod
|
||||
def attrDirectMap(values, target, source):
|
||||
for val in values:
|
||||
target[val] = source.getModifiedItemAttr(val)
|
||||
|
||||
@staticmethod
|
||||
def getT2MwdSpeed(fit, sFit):
|
||||
fitID = fit.ID
|
||||
propID = None
|
||||
shipHasMedSlots = fit.ship.getModifiedItemAttr("medSlots") > 0
|
||||
shipPower = fit.ship.getModifiedItemAttr("powerOutput")
|
||||
# Monitors have a 99% reduction to prop mod power requirements
|
||||
if fit.ship.name == "Monitor":
|
||||
shipPower *= 100
|
||||
rigSize = fit.ship.getModifiedItemAttr("rigSize")
|
||||
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
|
||||
sFit.appendModule(fitID, propID)
|
||||
sFit.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
|
||||
sFit.removeModule(fitID, mwdPosition)
|
||||
sFit.recalc(fit)
|
||||
fit = eos.db.getFit(fitID)
|
||||
return mwdPropSpeed
|
||||
|
||||
@staticmethod
|
||||
def getPropData(fit, sFit):
|
||||
fitID = fit.ID
|
||||
propMods = filter(lambda mod: mod.item and mod.item.group.name == "Propulsion Module", 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 = State.ONLINE
|
||||
sFit.recalc(fit)
|
||||
fit = eos.db.getFit(fitID)
|
||||
sp = fit.maxSpeed
|
||||
sig = fit.ship.getModifiedItemAttr("signatureRadius")
|
||||
propWithBloom.state = oldPropState
|
||||
sFit.recalc(fit)
|
||||
fit = eos.db.getFit(fitID)
|
||||
return {"usingMWD": True, "unpropedSpeed": sp, "unpropedSig": sig}
|
||||
return {
|
||||
"usingMWD": False,
|
||||
"unpropedSpeed": fit.maxSpeed,
|
||||
"unpropedSig": fit.ship.getModifiedItemAttr("signatureRadius")
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def getOutgoingProjectionData(fit):
|
||||
# This is a subset of module groups capable of projection and a superset of those currently used by efs
|
||||
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.group.name in modGroupNames, fit.modules))
|
||||
projections = []
|
||||
for mod in projectedMods:
|
||||
maxRangeDefault = 0
|
||||
falloffDefault = 0
|
||||
stats = {}
|
||||
if mod.item.group.name in ["Stasis Web", "Stasis Grappler"]:
|
||||
stats["type"] = "Stasis Web"
|
||||
stats["optimal"] = mod.getModifiedItemAttr("maxRange")
|
||||
EfsPort.attrDirectMap(["duration", "speedFactor"], stats, mod)
|
||||
elif mod.item.group.name == "Weapon Disruptor":
|
||||
stats["type"] = "Weapon Disruptor"
|
||||
stats["optimal"] = mod.getModifiedItemAttr("maxRange")
|
||||
stats["falloff"] = mod.getModifiedItemAttr("falloffEffectiveness")
|
||||
EfsPort.attrDirectMap([
|
||||
"trackingSpeedBonus", "maxRangeBonus", "falloffBonus", "aoeCloudSizeBonus",
|
||||
"aoeVelocityBonus", "missileVelocityBonus", "explosionDelayBonus"
|
||||
], stats, mod)
|
||||
elif mod.item.group.name == "Energy Nosferatu":
|
||||
stats["type"] = "Energy Nosferatu"
|
||||
EfsPort.attrDirectMap(["powerTransferAmount", "energyNeutralizerSignatureResolution"], stats, mod)
|
||||
elif mod.item.group.name == "Energy Neutralizer":
|
||||
stats["type"] = "Energy Neutralizer"
|
||||
EfsPort.attrDirectMap([
|
||||
"energyNeutralizerSignatureResolution", "entityCapacitorLevelModifierSmall",
|
||||
"entityCapacitorLevelModifierMedium", "entityCapacitorLevelModifierLarge",
|
||||
"energyNeutralizerAmount"
|
||||
], stats, mod)
|
||||
elif mod.item.group.name in ["Remote Shield Booster", "Ancillary Remote Shield Booster"]:
|
||||
stats["type"] = "Remote Shield Booster"
|
||||
EfsPort.attrDirectMap(["shieldBonus"], stats, mod)
|
||||
elif mod.item.group.name in ["Remote Armor Repairer", "Ancillary Remote Armor Repairer"]:
|
||||
stats["type"] = "Remote Armor Repairer"
|
||||
EfsPort.attrDirectMap(["armorDamageAmount"], stats, mod)
|
||||
elif mod.item.group.name == "Warp Scrambler":
|
||||
stats["type"] = "Warp Scrambler"
|
||||
EfsPort.attrDirectMap(["activationBlockedStrenght", "warpScrambleStrength"], stats, mod)
|
||||
elif mod.item.group.name == "Target Painter":
|
||||
stats["type"] = "Target Painter"
|
||||
EfsPort.attrDirectMap(["signatureRadiusBonus"], stats, mod)
|
||||
elif mod.item.group.name == "Sensor Dampener":
|
||||
stats["type"] = "Sensor Dampener"
|
||||
EfsPort.attrDirectMap(["maxTargetRangeBonus", "scanResolutionBonus"], stats, mod)
|
||||
elif mod.item.group.name == "ECM":
|
||||
stats["type"] = "ECM"
|
||||
EfsPort.attrDirectMap([
|
||||
"scanGravimetricStrengthBonus", "scanMagnetometricStrengthBonus",
|
||||
"scanRadarStrengthBonus", "scanLadarStrengthBonus",
|
||||
], stats, mod)
|
||||
elif mod.item.group.name == "Burst Jammer":
|
||||
stats["type"] = "Burst Jammer"
|
||||
maxRangeDefault = mod.getModifiedItemAttr("ecmBurstRange")
|
||||
EfsPort.attrDirectMap([
|
||||
"scanGravimetricStrengthBonus", "scanMagnetometricStrengthBonus",
|
||||
"scanRadarStrengthBonus", "scanLadarStrengthBonus",
|
||||
], stats, mod)
|
||||
elif mod.item.group.name == "Micro Jump Drive":
|
||||
stats["type"] = "Micro Jump Drive"
|
||||
EfsPort.attrDirectMap(["moduleReactivationDelay"], stats, mod)
|
||||
else:
|
||||
pyfalog.error("Projected module {0} lacks efs export implementation".format(mod.item.name))
|
||||
if mod.getModifiedItemAttr("maxRange", None) is None:
|
||||
pyfalog.error("Projected module {0} has no maxRange".format(mod.item.name))
|
||||
stats["optimal"] = mod.getModifiedItemAttr("maxRange", maxRangeDefault)
|
||||
stats["falloff"] = mod.getModifiedItemAttr("falloffEffectiveness", falloffDefault)
|
||||
EfsPort.attrDirectMap(["duration", "capacitorNeed"], stats, mod)
|
||||
projections.append(stats)
|
||||
return projections
|
||||
|
||||
# Note that unless padTypeIDs is True all 0s will be removed from modTypeIDs in the return.
|
||||
# They always are added initally for the sake of brevity, as this option may not be retained long term.
|
||||
@staticmethod
|
||||
def getModuleInfo(fit, padTypeIDs=False):
|
||||
moduleNames = []
|
||||
modTypeIDs = []
|
||||
moduleNameSets = {Slot.LOW: [], Slot.MED: [], Slot.HIGH: [], Slot.RIG: [], Slot.SUBSYSTEM: []}
|
||||
modTypeIDSets = {Slot.LOW: [], Slot.MED: [], Slot.HIGH: [], Slot.RIG: [], Slot.SUBSYSTEM: []}
|
||||
for mod in fit.modules:
|
||||
try:
|
||||
if mod.item is not None:
|
||||
if mod.charge is not None:
|
||||
modTypeIDSets[mod.slot].append([mod.item.typeID, mod.charge.typeID])
|
||||
moduleNameSets[mod.slot].append(mod.item.name + ": " + mod.charge.name)
|
||||
else:
|
||||
modTypeIDSets[mod.slot].append(mod.item.typeID)
|
||||
moduleNameSets[mod.slot].append(mod.item.name)
|
||||
else:
|
||||
modTypeIDSets[mod.slot].append(0)
|
||||
moduleNameSets[mod.slot].append("Empty Slot")
|
||||
except:
|
||||
pyfalog.error("Could not find name for module {0}".format(vars(mod)))
|
||||
|
||||
for modInfo in [
|
||||
["High Slots:"], moduleNameSets[Slot.HIGH], ["", "Med Slots:"], moduleNameSets[Slot.MED],
|
||||
["", "Low Slots:"], moduleNameSets[Slot.LOW], ["", "Rig Slots:"], moduleNameSets[Slot.RIG]
|
||||
]:
|
||||
moduleNames.extend(modInfo)
|
||||
if len(moduleNameSets[Slot.SUBSYSTEM]) > 0:
|
||||
moduleNames.extend(["", "Subsystems:"])
|
||||
moduleNames.extend(moduleNameSets[Slot.SUBSYSTEM])
|
||||
|
||||
for slotType in [Slot.HIGH, Slot.MED, Slot.LOW, Slot.RIG, Slot.SUBSYSTEM]:
|
||||
if slotType is not Slot.SUBSYSTEM or len(modTypeIDSets[slotType]) > 0:
|
||||
modTypeIDs.extend([0, 0] if slotType is not Slot.HIGH else [0])
|
||||
modTypeIDs.extend(modTypeIDSets[slotType])
|
||||
|
||||
droneNames = []
|
||||
droneIDs = []
|
||||
fighterNames = []
|
||||
fighterIDs = []
|
||||
for drone in fit.drones:
|
||||
if drone.amountActive > 0:
|
||||
droneIDs.append(drone.item.typeID)
|
||||
droneNames.append("%s x%s" % (drone.item.name, drone.amount))
|
||||
for fighter in fit.fighters:
|
||||
if fighter.amountActive > 0:
|
||||
fighterIDs.append(fighter.item.typeID)
|
||||
fighterNames.append("%s x%s" % (fighter.item.name, fighter.amountActive))
|
||||
if len(droneNames) > 0:
|
||||
modTypeIDs.extend([0, 0])
|
||||
modTypeIDs.extend(droneIDs)
|
||||
moduleNames.extend(["", "Drones:"])
|
||||
moduleNames.extend(droneNames)
|
||||
if len(fighterNames) > 0:
|
||||
modTypeIDs.extend([0, 0])
|
||||
modTypeIDs.extend(fighterIDs)
|
||||
moduleNames.extend(["", "Fighters:"])
|
||||
moduleNames.extend(fighterNames)
|
||||
if len(fit.implants) > 0:
|
||||
modTypeIDs.extend([0, 0])
|
||||
moduleNames.extend(["", "Implants:"])
|
||||
for implant in fit.implants:
|
||||
modTypeIDs.append(implant.item.typeID)
|
||||
moduleNames.append(implant.item.name)
|
||||
if len(fit.boosters) > 0:
|
||||
modTypeIDs.extend([0, 0])
|
||||
moduleNames.extend(["", "Boosters:"])
|
||||
for booster in fit.boosters:
|
||||
modTypeIDs.append(booster.item.typeID)
|
||||
moduleNames.append(booster.item.name)
|
||||
if len(fit.commandFits) > 0:
|
||||
modTypeIDs.extend([0, 0])
|
||||
moduleNames.extend(["", "Command Fits:"])
|
||||
for commandFit in fit.commandFits:
|
||||
modTypeIDs.append(commandFit.ship.item.typeID)
|
||||
moduleNames.append(commandFit.name)
|
||||
if len(fit.projectedModules) > 0:
|
||||
modTypeIDs.extend([0, 0])
|
||||
moduleNames.extend(["", "Projected Modules:"])
|
||||
for mod in fit.projectedModules:
|
||||
modTypeIDs.append(mod.item.typeID)
|
||||
moduleNames.append(mod.item.name)
|
||||
|
||||
if fit.character.name != "All 5":
|
||||
modTypeIDs.extend([0, 0, 0])
|
||||
moduleNames.extend(["", "Character:"])
|
||||
moduleNames.append(fit.character.name)
|
||||
if padTypeIDs is not True:
|
||||
modTypeIDsUnpadded = [mod for mod in modTypeIDs if mod != 0]
|
||||
modTypeIDs = modTypeIDsUnpadded
|
||||
return {"moduleNames": moduleNames, "modTypeIDs": modTypeIDs}
|
||||
|
||||
@staticmethod
|
||||
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"),
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
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.values():
|
||||
stats = wepGroup[0]
|
||||
n = wepGroup[1]
|
||||
tracking = 0
|
||||
maxVelocity = 0
|
||||
explosionDelay = 0
|
||||
damageReductionFactor = 0
|
||||
explosionRadius = 0
|
||||
explosionVelocity = 0
|
||||
aoeFieldRange = 0
|
||||
if stats.hardpoint == Hardpoint.TURRET:
|
||||
tracking = stats.getModifiedItemAttr("trackingSpeed")
|
||||
typeing = "Turret"
|
||||
name = stats.item.name + ", " + stats.charge.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.getModifiedChargeAttr("maxVelocity")
|
||||
explosionDelay = stats.getModifiedChargeAttr("explosionDelay")
|
||||
damageReductionFactor = stats.getModifiedChargeAttr("aoeDamageReductionFactor")
|
||||
explosionRadius = stats.getModifiedChargeAttr("aoeCloudSize")
|
||||
explosionVelocity = stats.getModifiedChargeAttr("aoeVelocity")
|
||||
typeing = "Missile"
|
||||
name = stats.item.name + ", " + stats.charge.name
|
||||
elif stats.hardpoint == Hardpoint.NONE:
|
||||
aoeFieldRange = stats.getModifiedItemAttr("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 * 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,
|
||||
"damageMultiplierBonusMax": stats.getModifiedItemAttr("damageMultiplierBonusMax"),
|
||||
"damageMultiplierBonusPerCycle": stats.getModifiedItemAttr("damageMultiplierBonusPerCycle")
|
||||
}
|
||||
weaponSystems.append(statDict)
|
||||
for drone in fit.drones:
|
||||
if drone.dps[0] > 0 and drone.amountActive > 0:
|
||||
droneAttr = drone.getModifiedItemAttr
|
||||
# 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.getModifiedItemAttr
|
||||
abilities = []
|
||||
if "fighterAbilityAttackMissileDamageEM" in fighter.item.attributes.keys():
|
||||
baseRef = "fighterAbilityAttackMissile"
|
||||
ability = EfsPort.getFighterAbilityData(fighterAttr, fighter, baseRef)
|
||||
abilities.append(ability)
|
||||
if "fighterAbilityMissilesDamageEM" in fighter.item.attributes.keys():
|
||||
baseRef = "fighterAbilityMissiles"
|
||||
ability = EfsPort.getFighterAbilityData(fighterAttr, fighter, baseRef)
|
||||
abilities.append(ability)
|
||||
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
|
||||
|
||||
@staticmethod
|
||||
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 EfsPort.wepTestSet.keys():
|
||||
return EfsPort.wepTestSet[setType]
|
||||
else:
|
||||
EfsPort.wepTestSet[setType] = []
|
||||
modSet = EfsPort.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)
|
||||
|
||||
sMkt = 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.getModifiedItemAttr("chargeGroup1")).all())
|
||||
mods = [mod]
|
||||
charges = [clist[0]]
|
||||
if setType == "launcher":
|
||||
# We don"t want variations of missiles we already have
|
||||
prevCharges = list(sMkt.getVariationsByItems(charges))
|
||||
testCharges = []
|
||||
for charge in clist:
|
||||
if charge not in prevCharges:
|
||||
testCharges.append(charge)
|
||||
prevCharges += sMkt.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
|
||||
|
||||
@staticmethod
|
||||
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.getModifiedItemAttr) * d.getModifiedItemAttr("damageMultiplier")
|
||||
fitMultipliers["drones"] = list(map(getDroneMulti, tf.drones))
|
||||
|
||||
getFitTurrets = lambda f: filter(lambda mod: mod.hardpoint == Hardpoint.TURRET, f.modules)
|
||||
getTurretMulti = lambda mod: mod.getModifiedItemAttr("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.getModifiedChargeAttr) / mod.cycleTime
|
||||
fitMultipliers["launchers"] = list(map(getLauncherMulti, getFitLaunchers(tf)))
|
||||
return fitMultipliers
|
||||
|
||||
multipliers = {"turret": 1, "launcher": 1, "droneBandwidth": 1}
|
||||
drones = EfsPort.getTestSet("drone")
|
||||
launchers = EfsPort.getTestSet("launcher")
|
||||
turrets = EfsPort.getTestSet("turret")
|
||||
for weaponTypeSet in [turrets, launchers, drones]:
|
||||
for mod in weaponTypeSet:
|
||||
mod.owner = fit
|
||||
turrets = list(filter(lambda mod: mod.getModifiedItemAttr("damageMultiplier"), turrets))
|
||||
launchers = list(filter(lambda mod: sumDamage(mod.getModifiedChargeAttr), launchers))
|
||||
|
||||
# Since the effect modules are fairly opaque a mock test fit is used to test the impact of traits.
|
||||
# standin class used to prevent . notation causing issues when used as an arg
|
||||
class standin():
|
||||
pass
|
||||
tf = standin()
|
||||
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)
|
||||
Fit.getInstance().recalc(fit)
|
||||
return multipliers
|
||||
|
||||
@staticmethod
|
||||
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)
|
||||
return sizeNotFoundMsg
|
||||
|
||||
@staticmethod
|
||||
def exportEfs(fit, typeNotFitFlag):
|
||||
sFit = Fit.getInstance()
|
||||
includeShipTypeData = typeNotFitFlag > 0
|
||||
if includeShipTypeData:
|
||||
fitName = fit.name
|
||||
else:
|
||||
fitName = fit.ship.name + ": " + fit.name
|
||||
pyfalog.info("Creating Eve Fleet Simulator data for: " + fit.name)
|
||||
fitModAttr = fit.ship.getModifiedItemAttr
|
||||
propData = EfsPort.getPropData(fit, sFit)
|
||||
mwdPropSpeed = fit.maxSpeed
|
||||
if includeShipTypeData:
|
||||
mwdPropSpeed = EfsPort.getT2MwdSpeed(fit, sFit)
|
||||
projections = EfsPort.getOutgoingProjectionData(fit)
|
||||
modInfo = EfsPort.getModuleInfo(fit)
|
||||
moduleNames = modInfo["moduleNames"]
|
||||
modTypeIDs = modInfo["modTypeIDs"]
|
||||
weaponSystems = EfsPort.getWeaponSystemData(fit)
|
||||
|
||||
turretSlots = fitModAttr("turretSlotsLeft") if fitModAttr("turretSlotsLeft") is not None else 0
|
||||
launcherSlots = fitModAttr("launcherSlotsLeft") if fitModAttr("launcherSlotsLeft") is not None else 0
|
||||
droneBandwidth = fitModAttr("droneBandwidth") if fitModAttr("droneBandwidth") is not None else 0
|
||||
weaponBonusMultipliers = EfsPort.getWeaponBonusMultipliers(fit)
|
||||
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 fit.ship.item.group.name == "Dreadnought":
|
||||
effectiveTurretSlots *= 9.4
|
||||
effectiveLauncherSlots *= 15
|
||||
hullResonance = {
|
||||
"exp": fitModAttr("explosiveDamageResonance"), "kin": fitModAttr("kineticDamageResonance"),
|
||||
"therm": fitModAttr("thermalDamageResonance"), "em": fitModAttr("emDamageResonance")
|
||||
}
|
||||
armorResonance = {
|
||||
"exp": fitModAttr("armorExplosiveDamageResonance"), "kin": fitModAttr("armorKineticDamageResonance"),
|
||||
"therm": fitModAttr("armorThermalDamageResonance"), "em": fitModAttr("armorEmDamageResonance")
|
||||
}
|
||||
shieldResonance = {
|
||||
"exp": fitModAttr("shieldExplosiveDamageResonance"), "kin": fitModAttr("shieldKineticDamageResonance"),
|
||||
"therm": fitModAttr("shieldThermalDamageResonance"), "em": fitModAttr("shieldEmDamageResonance")
|
||||
}
|
||||
resonance = {"hull": hullResonance, "armor": armorResonance, "shield": shieldResonance}
|
||||
shipSize = EfsPort.getShipSize(fit.ship.item.groupID)
|
||||
try:
|
||||
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"),
|
||||
"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"), "cpuOutput": fitModAttr("cpuOutput"),
|
||||
"rigSize": fitModAttr("rigSize"), "effectiveTurrets": effectiveTurretSlots,
|
||||
"effectiveLaunchers": effectiveLauncherSlots, "effectiveDroneBandwidth": effectiveDroneBandwidth,
|
||||
"resonance": resonance, "typeID": fit.shipID, "groupID": fit.ship.item.groupID, "shipSize": shipSize,
|
||||
"droneControlRange": fitModAttr("droneControlRange"), "mass": fitModAttr("mass"),
|
||||
"unpropedSpeed": propData["unpropedSpeed"], "unpropedSig": propData["unpropedSig"],
|
||||
"usingMWD": propData["usingMWD"], "mwdPropSpeed": mwdPropSpeed, "projections": projections,
|
||||
"modTypeIDs": modTypeIDs, "moduleNames": moduleNames,
|
||||
"pyfaVersion": pyfaVersion, "efsExportVersion": EfsPort.version
|
||||
}
|
||||
except TypeError:
|
||||
pyfalog.error("Error parsing fit:" + str(fit))
|
||||
pyfalog.error(TypeError)
|
||||
dataDict = {"name": fitName + "Fit could not be correctly parsed"}
|
||||
export = json.dumps(dataDict, skipkeys=True)
|
||||
return export
|
||||
@@ -208,11 +208,11 @@ class Fit(FitDeprecated):
|
||||
# error during the command loop
|
||||
refreshFits = set()
|
||||
for projection in list(fit.projectedOnto.values()):
|
||||
if projection.victim_fit != fit and projection.victim_fit in eos.db.saveddata_session: # GH issue #359
|
||||
if projection.victim_fit and projection.victim_fit != fit and projection.victim_fit in eos.db.saveddata_session: # GH issue #359
|
||||
refreshFits.add(projection.victim_fit)
|
||||
|
||||
for booster in list(fit.boostedOnto.values()):
|
||||
if booster.boosted_fit != fit and booster.boosted_fit in eos.db.saveddata_session: # GH issue #359
|
||||
if booster.boosted_fit and booster.boosted_fit != fit and booster.boosted_fit in eos.db.saveddata_session: # GH issue #359
|
||||
refreshFits.add(booster.boosted_fit)
|
||||
|
||||
eos.db.remove(fit)
|
||||
|
||||
@@ -277,15 +277,8 @@ class Market(object):
|
||||
# Dictionary of items with forced market group (service assumes they have no
|
||||
# market group assigned in db, otherwise they'll appear in both original and forced groups)
|
||||
self.ITEMS_FORCEDMARKETGROUP = {
|
||||
"Advanced Cerebral Accelerator" : 977, # Implants & Boosters > Booster
|
||||
"Civilian Damage Control" : 615, # Ship Equipment > Hull & Armor > Damage Controls
|
||||
"Civilian EM Ward Field" : 1695,
|
||||
# Ship Equipment > Shield > Shield Hardeners > EM Shield Hardeners
|
||||
"Civilian Explosive Deflection Field" : 1694,
|
||||
# Ship Equipment > Shield > Shield Hardeners > Explosive Shield Hardeners
|
||||
"Advanced Cerebral Accelerator" : 2487, # Implants & Boosters > Booster > Cerebral Accelerators
|
||||
"Civilian Hobgoblin" : 837, # Drones > Combat Drones > Light Scout Drones
|
||||
"Civilian Kinetic Deflection Field" : 1693,
|
||||
# Ship Equipment > Shield > Shield Hardeners > Kinetic Shield Hardeners
|
||||
"Civilian Light Missile Launcher" : 640,
|
||||
# Ship Equipment > Turrets & Bays > Missile Launchers > Light Missile Launchers
|
||||
"Civilian Scourge Light Missile" : 920,
|
||||
@@ -293,8 +286,6 @@ class Market(object):
|
||||
"Civilian Small Remote Armor Repairer" : 1059,
|
||||
# Ship Equipment > Hull & Armor > Remote Armor Repairers > Small
|
||||
"Civilian Small Remote Shield Booster" : 603, # Ship Equipment > Shield > Remote Shield Boosters > Small
|
||||
"Civilian Stasis Webifier" : 683, # Ship Equipment > Electronic Warfare > Stasis Webifiers
|
||||
"Civilian Warp Disruptor" : 1935, # Ship Equipment > Electronic Warfare > Warp Disruptors
|
||||
"Hardwiring - Zainou 'Sharpshooter' ZMX10" : 1493,
|
||||
# Implants & Boosters > Implants > Skill Hardwiring > Missile Implants > Implant Slot 06
|
||||
"Hardwiring - Zainou 'Sharpshooter' ZMX100" : 1493,
|
||||
@@ -307,11 +298,9 @@ class Market(object):
|
||||
# Implants & Boosters > Implants > Skill Hardwiring > Missile Implants > Implant Slot 06
|
||||
"Hardwiring - Zainou 'Sharpshooter' ZMX1100": 1493,
|
||||
# Implants & Boosters > Implants > Skill Hardwiring > Missile Implants > Implant Slot 06
|
||||
"Nugoehuvi Synth Blue Pill Booster" : 977, # Implants & Boosters > Booster
|
||||
"Prototype Cerebral Accelerator" : 977, # Implants & Boosters > Booster
|
||||
"Prototype Cerebral Accelerator" : 2487, # Implants & Boosters > Booster > Cerebral Accelerators
|
||||
"Prototype Iris Probe Launcher" : 712, # Ship Equipment > Turrets & Bays > Scan Probe Launchers
|
||||
"Shadow" : 1310, # Drones > Combat Drones > Fighter Bombers
|
||||
"Standard Cerebral Accelerator" : 977, # Implants & Boosters > Booster
|
||||
"Standard Cerebral Accelerator" : 2487, # Implants & Boosters > Booster > Cerebral Accelerators
|
||||
}
|
||||
|
||||
self.ITEMS_FORCEDMARKETGROUP_R = self.__makeRevDict(self.ITEMS_FORCEDMARKETGROUP)
|
||||
@@ -538,7 +527,7 @@ class Market(object):
|
||||
categories = ['Drone', 'Fighter', 'Implant']
|
||||
|
||||
for item in items:
|
||||
if item.category.ID == 20: # Implants and Boosters
|
||||
if item.category.ID == 20 and item.group.ID != 303: # Implants not Boosters
|
||||
implant_remove_list = set()
|
||||
implant_remove_list.add("Low-Grade ")
|
||||
implant_remove_list.add("Low-grade ")
|
||||
@@ -552,15 +541,6 @@ class Market(object):
|
||||
implant_remove_list.add(" - Elite")
|
||||
implant_remove_list.add(" - Improved")
|
||||
implant_remove_list.add(" - Standard")
|
||||
implant_remove_list.add("Copper ")
|
||||
implant_remove_list.add("Gold ")
|
||||
implant_remove_list.add("Silver ")
|
||||
implant_remove_list.add("Advanced ")
|
||||
implant_remove_list.add("Improved ")
|
||||
implant_remove_list.add("Prototype ")
|
||||
implant_remove_list.add("Standard ")
|
||||
implant_remove_list.add("Strong ")
|
||||
implant_remove_list.add("Synth ")
|
||||
|
||||
for implant_prefix in ("-6", "-7", "-8", "-9", "-10"):
|
||||
for i in range(50):
|
||||
@@ -596,6 +576,16 @@ class Market(object):
|
||||
if trimmed_variations_list:
|
||||
variations_list = trimmed_variations_list
|
||||
|
||||
# If the items are boosters then filter variations to only include boosters for the same slot.
|
||||
BOOSTER_GROUP_ID = 303
|
||||
if all(map(lambda i: i.group.ID == BOOSTER_GROUP_ID, items)) and len(items) > 0:
|
||||
# 'boosterness' is the database's attribute name for Booster Slot
|
||||
reqSlot = next(items.__iter__()).getAttribute('boosterness')
|
||||
# If the item and it's variation both have a marketGroupID it should match for the variation to be considered valid.
|
||||
marketGroupID = [next(filter(None, map(lambda i: i.marketGroupID, items)), None), None]
|
||||
matchSlotAndMktGrpID = lambda v: v.getAttribute('boosterness') == reqSlot and v.marketGroupID in marketGroupID
|
||||
variations_list = list(filter(matchSlotAndMktGrpID, variations_list))
|
||||
|
||||
variations.update(variations_list)
|
||||
return variations
|
||||
|
||||
@@ -657,6 +647,12 @@ class Market(object):
|
||||
def marketGroupHasTypesCheck(self, mg):
|
||||
"""If market group has any items, return true"""
|
||||
if mg and mg.ID in self.ITEMS_FORCEDMARKETGROUP_R:
|
||||
# This shouldn't occur normally but makes errors more mild when ITEMS_FORCEDMARKETGROUP is outdated.
|
||||
if len(mg.children) > 0 and len(mg.items) == 0:
|
||||
pyfalog.error(("Market group \"{0}\" contains no items and has children. "
|
||||
"ITEMS_FORCEDMARKETGROUP is likely outdated and will need to be "
|
||||
"updated for {1} to display correctly.").format(mg, self.ITEMS_FORCEDMARKETGROUP_R[mg.ID]))
|
||||
return False
|
||||
return True
|
||||
elif len(mg.items) > 0:
|
||||
return True
|
||||
|
||||
@@ -306,8 +306,11 @@ class Port(object):
|
||||
fit.character = sFit.character
|
||||
fit.damagePattern = sFit.pattern
|
||||
fit.targetResists = sFit.targetResists
|
||||
useCharImplants = sFit.serviceFittingOptions["useCharacterImplantsByDefault"]
|
||||
fit.implantLocation = ImplantLocation.CHARACTER if useCharImplants else ImplantLocation.FIT
|
||||
if len(fit.implants) > 0:
|
||||
fit.implantLocation = ImplantLocation.FIT
|
||||
else:
|
||||
useCharImplants = sFit.serviceFittingOptions["useCharacterImplantsByDefault"]
|
||||
fit.implantLocation = ImplantLocation.CHARACTER if useCharImplants else ImplantLocation.FIT
|
||||
db.save(fit)
|
||||
# IDs.append(fit.ID)
|
||||
if iportuser: # Pulse
|
||||
@@ -339,8 +342,11 @@ class Port(object):
|
||||
fit.character = sFit.character
|
||||
fit.damagePattern = sFit.pattern
|
||||
fit.targetResists = sFit.targetResists
|
||||
useCharImplants = sFit.serviceFittingOptions["useCharacterImplantsByDefault"]
|
||||
fit.implantLocation = ImplantLocation.CHARACTER if useCharImplants else ImplantLocation.FIT
|
||||
if len(fit.implants) > 0:
|
||||
fit.implantLocation = ImplantLocation.FIT
|
||||
else:
|
||||
useCharImplants = sFit.serviceFittingOptions["useCharacterImplantsByDefault"]
|
||||
fit.implantLocation = ImplantLocation.CHARACTER if useCharImplants else ImplantLocation.FIT
|
||||
db.save(fit)
|
||||
return fits
|
||||
|
||||
|
||||