Merge branch 'i18n' into singularity

This commit is contained in:
DarkPhoenix
2020-10-23 19:53:36 +03:00
217 changed files with 3886327 additions and 3131869 deletions

View File

@@ -27,6 +27,9 @@ install:
# done from inside the powershell script as it would require to restart
# the parent CMD process).
- cmd: "SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%"
- cmd: "appveyor DownloadFile https://github.com/mlocati/gettext-iconv-windows/releases/download/v0.20.2-v1.16/gettext0.20.2-iconv1.16-shared-64.zip"
- cmd: "7z x gettext0.20.2-iconv1.16-shared-64.zip -ogettext"
- cmd: "SET PATH=gettext;%PATH%"
- cmd: "python --version"
- cmd: "python -c \"import struct; print(struct.calcsize('P') * 8)\""
@@ -53,7 +56,12 @@ before_build:
build_script:
- ps: echo("Build pyfa:")
# Build gamedata DB
- ps: Get-ChildItem locale/*.po -Recurse -File| Foreach {msgen $_.fullname -o $_.fullname}
# Build language files
- cmd: "python scripts/compile_lang.py"
# Dump language progress
- cmd: "python scripts/dump_crowdin_progress.py"
# Build gamedata DB
- cmd: "python db_update.py"
# Build command for PyInstaller
- cmd: "python -m PyInstaller --noupx --clean --windowed --noconsole -y pyfa.spec"

6
.gitattributes vendored
View File

@@ -1,11 +1,9 @@
# Set the default behavior, in case people don't have core.autocrlf set.
* text=auto
# Explicitly declare text files you want to always be normalized and converted
# to native line endings on checkout.
# *.c text
# *.h text
# Declare files that will always have CRLF line endings on checkout.
# Source files
# ============
@@ -15,7 +13,6 @@
*.pyw text eol=crlf
*.pyx text eol=crlf
pyfa.py text eol=lf
# Denote all files that are truly binary and should not be modified.
# Binary files
# ============
@@ -25,12 +22,10 @@ pyfa.py text eol=lf
*.pyc binary
*.pyd binary
*.pyo binary
# Note: .db, .p, and .pkl files are associated
# with the python modules ``pickle``, ``dbm.*``,
# ``shelve``, ``marshal``, ``anydbm``, & ``bsddb``
# (among others).
# Denote all files that are truly binary and should not be modified.
# Image files
# ============
@@ -38,3 +33,4 @@ pyfa.py text eol=lf
*.jpg binary
*.icns binary
*.ico binary

2
.gitignore vendored
View File

@@ -67,7 +67,6 @@ coverage.xml
# Translations
*.mo
*.pot
# Django stuff:
*.log
@@ -123,3 +122,4 @@ gitversion
*.swp
*.fsdbinary
/locale/progress.json

View File

@@ -10,11 +10,14 @@ matrix:
osx_image: xcode11.3
language: generic
before_install:
- bash scripts/setup-osx.sh
- bash scripts/osx-translations.sh
- bash scripts/osx-setup.sh
install:
- python3 scripts/compile_lang.py
- python3 scripts/dump_crowdin_progress.py
- python3 db_update.py
- export PYFA_VERSION="$(python3 scripts/dump_version.py)"
- bash scripts/package-osx.sh
- bash scripts/osx-package.sh
before_deploy:
- export RELEASE_PKG_FILE=$(ls *.deb)
- echo "deploying $RELEASE_PKG_FILE to GitHub releases"

View File

@@ -3,7 +3,6 @@
<option name="RIGHT_MARGIN" value="165" />
<Python>
<option name="NEW_LINE_AFTER_COLON" value="true" />
<option name="DICT_ALIGNMENT" value="2" />
<option name="DICT_NEW_LINE_AFTER_LEFT_BRACE" value="true" />
<option name="DICT_NEW_LINE_BEFORE_RIGHT_BRACE" value="true" />
<option name="USE_CONTINUATION_INDENT_FOR_ARGUMENTS" value="true" />

View File

@@ -1,54 +1,61 @@
<profile version="1.0">
<option name="myName" value="Pyfa" />
<inspection_tool class="IgnoreUnusedEntry" enabled="false" level="UNUSED ENTRY" enabled_by_default="false" />
<inspection_tool class="InconsistentLineSeparators" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="ProblematicWhitespace" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="PyBehaveInspection" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="PyClassicStyleClassInspection" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="PyCompatibilityInspection" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ourVersions">
<value>
<list size="1">
<item index="0" class="java.lang.String" itemvalue="2.7" />
<profile version="1.0">
<option name="myName" value="Pyfa" />
<inspection_tool class="IgnoreUnusedEntry" enabled="false" level="UNUSED ENTRY" enabled_by_default="false" />
<inspection_tool class="InconsistentLineSeparators" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="ProblematicWhitespace" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="PyBehaveInspection" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="PyClassicStyleClassInspection" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="PyCompatibilityInspection" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ourVersions">
<value>
<list size="1">
<item index="0" class="java.lang.String" itemvalue="2.7" />
</list>
</value>
</option>
</inspection_tool>
<inspection_tool class="PyMissingTypeHintsInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="PyPackageRequirementsInspection" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoredPackages">
<value>
<list size="1">
<item index="0" class="java.lang.String" itemvalue="wxPython" />
</list>
</value>
</option>
</inspection_tool>
<inspection_tool class="PyPep8Inspection" enabled="true" level="TYPO" enabled_by_default="true">
<option name="ignoredErrors">
<list>
<option value="E203" />
<option value="E127" />
<option value="E128" />
<option value="E126" />
</list>
</value>
</option>
</inspection_tool>
<inspection_tool class="PyMissingTypeHintsInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="PyPackageRequirementsInspection" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoredPackages">
<value>
<list size="1">
<item index="0" class="java.lang.String" itemvalue="wxPython" />
</option>
</inspection_tool>
<inspection_tool class="PyPep8NamingInspection" enabled="true" level="TYPO" enabled_by_default="true">
<option name="ignoredErrors">
<list>
<option value="N802" />
<option value="N806" />
<option value="N803" />
<option value="N814" />
</list>
</value>
</option>
</inspection_tool>
<inspection_tool class="PyPep8Inspection" enabled="true" level="TYPO" enabled_by_default="true">
<option name="ignoredErrors">
<list>
<option value="E203" />
<option value="E127" />
<option value="E128" />
<option value="E126" />
</list>
</option>
</inspection_tool>
<inspection_tool class="PyPep8NamingInspection" enabled="true" level="TYPO" enabled_by_default="true">
<option name="ignoredErrors">
<list>
<option value="N802" />
<option value="N806" />
<option value="N803" />
<option value="N814" />
</list>
</option>
</inspection_tool>
<inspection_tool class="PyShadowingBuiltinsInspection" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="PyShadowingNamesInspection" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">
<option name="processCode" value="true" />
<option name="processLiterals" value="true" />
<option name="processComments" value="true" />
</inspection_tool>
</profile>
</option>
</inspection_tool>
<inspection_tool class="PyShadowingBuiltinsInspection" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="PyShadowingNamesInspection" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="PyUnresolvedReferencesInspection" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoredIdentifiers">
<list>
<option value="_" />
</list>
</option>
</inspection_tool>
<inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">
<option name="processCode" value="true" />
<option name="processLiterals" value="true" />
<option name="processComments" value="true" />
</inspection_tool>
</profile>

View File

@@ -41,6 +41,7 @@ cipher = None
clientHash = None
experimentalFeatures = None
version = None
language = None
ESI_CACHE = 'esi_cache'
@@ -52,6 +53,8 @@ LOGLEVEL_MAP = {
"debug": DEBUG,
}
CATALOG = 'lang'
slotColourMap = {
FittingSlot.LOW: wx.Colour(250, 235, 204), # yellow = low slots
FittingSlot.MED: wx.Colour(188, 215, 241), # blue = mid slots
@@ -106,6 +109,7 @@ def defPaths(customSavePath=None):
global clientHash
global version
global experimentalFeatures
global language
pyfalog.debug("Configuring Pyfa")
@@ -185,9 +189,15 @@ def defPaths(customSavePath=None):
eos.config.gamedata_connectionstring = "sqlite:///" + gameDB + "?check_same_thread=False"
# initialize the settings
from service.settings import EOSSettings
from service.settings import EOSSettings, LocaleSettings
eos.config.settings = EOSSettings.getInstance().EOSSettings # this is kind of confusing, but whatever
# set langauge, taking the passed argument or falling back to what's saved in the settings
localeSettings = LocaleSettings.getInstance()
language = language or localeSettings.get('locale')
# sets the lang for eos, using the mapped langauge.
eos.config.set_lang(localeSettings.get_eos_locale())
def defLogging():
global debug

3
crowdin.yml Normal file
View File

@@ -0,0 +1,3 @@
files:
- source: /locale/*.pot
translation: /locale/%locale_with_underscore%/LC_MESSAGES/lang.po

View File

@@ -28,6 +28,8 @@ import sqlite3
import sys
# todo: need to set the EOS language to en, becasuse this assumes it's being run within an English context
# Need to know what that would do if called from pyfa
ROOT_DIR = os.path.realpath(os.path.dirname(__file__))
DB_PATH = os.path.join(ROOT_DIR, 'eve.db')
JSON_DIR = os.path.join(ROOT_DIR, 'staticdata')
@@ -39,7 +41,7 @@ GAMEDATA_SCHEMA_VERSION = 4
def db_needs_update():
"""True if needs, false if it does not, none if we cannot check it."""
try:
with open(os.path.join(JSON_DIR, 'phobos', 'metadata.json')) as f:
with open(os.path.join(JSON_DIR, 'phobos', 'metadata.0.json')) as f:
data_version = next((r['field_value'] for r in json.load(f) if r['field_name'] == 'client_build'))
except (KeyboardInterrupt, SystemExit):
raise
@@ -85,18 +87,31 @@ def update_db():
import eos.db
import eos.gamedata
import eos.config
# Create the database tables
eos.db.gamedata_meta.create_all()
def _readData(minerName, jsonName, keyIdName=None):
with open(os.path.join(JSON_DIR, minerName, '{}.json'.format(jsonName)), encoding='utf-8') as f:
rawData = json.load(f)
compiled_data = None
for i in itertools.count(0):
try:
with open(os.path.join(JSON_DIR, minerName, '{}.{}.json'.format(jsonName, i)), encoding='utf-8') as f:
rawData = json.load(f)
if i == 0:
compiled_data = {} if type(rawData) == dict else []
if type(rawData) == dict:
compiled_data.update(rawData)
else:
compiled_data.extend(rawData)
except FileNotFoundError:
break
if not keyIdName:
return rawData
return compiled_data
# IDs in keys, rows in values
data = []
for k, v in rawData.items():
for k, v in compiled_data.items():
row = {}
row.update(v)
if keyIdName not in row:
@@ -121,13 +136,13 @@ def update_db():
for row in data:
if (
# Apparently people really want Civilian modules available
(row['typeName'].startswith('Civilian') and "Shuttle" not in row['typeName']) or
row['typeName'] == 'Capsule' or
(row['typeName_en-us'].startswith('Civilian') and "Shuttle" not in row['typeName_en-us']) or
row['typeName_en-us'] == 'Capsule' or
row['groupID'] == 4033 # destructible effect beacons
):
row['published'] = True
# Nearly useless and clutter search results too much
elif row['typeName'].startswith('Limited Synth '):
elif row['typeName_en-us'].startswith('Limited Synth '):
row['published'] = False
newData = []
@@ -146,25 +161,34 @@ def update_db():
1983) # the "container" for the abyssal environments
):
newData.append(row)
_addRows(newData, eos.gamedata.Item)
map = {'typeName_en-us': 'typeName', 'description_en-us': '_description'}
map.update({'description'+v: '_description'+v for (k, v) in eos.config.translation_mapping.items() if k != 'en'})
_addRows(newData, eos.gamedata.Item, fieldMap=map)
return newData
def processEveGroups():
print('processing evegroups')
data = _readData('fsd_lite', 'evegroups', keyIdName='groupID')
_addRows(data, eos.gamedata.Group)
map = {'groupName_en-us': 'name'}
map.update({'groupName'+v: 'name'+v for (k, v) in eos.config.translation_mapping.items() if k != 'en'})
_addRows(data, eos.gamedata.Group, fieldMap=map)
return data
def processEveCategories():
print('processing evecategories')
data = _readData('fsd_lite', 'evecategories', keyIdName='categoryID')
_addRows(data, eos.gamedata.Category)
map = { 'categoryName_en-us': 'name' }
map.update({'categoryName'+v: 'name'+v for (k, v) in eos.config.translation_mapping.items() if k != 'en'})
_addRows(data, eos.gamedata.Category, fieldMap=map)
def processDogmaAttributes():
print('processing dogmaattributes')
data = _readData('fsd_binary', 'dogmaattributes', keyIdName='attributeID')
_addRows(data, eos.gamedata.AttributeInfo)
map = {
'displayName_en-us': 'displayName',
# 'tooltipDescription_en-us': 'tooltipDescription'
}
_addRows(data, eos.gamedata.AttributeInfo, fieldMap=map)
def processDogmaTypeAttributes(eveTypesData):
print('processing dogmatypeattributes')
@@ -239,17 +263,28 @@ def update_db():
def processDogmaUnits():
print('processing dogmaunits')
data = _readData('fsd_binary', 'dogmaunits', keyIdName='unitID')
_addRows(data, eos.gamedata.Unit, fieldMap={'name': 'unitName'})
_addRows(data, eos.gamedata.Unit, fieldMap={
'name': 'unitName',
'displayName_en-us': 'displayName'
})
def processMarketGroups():
print('processing marketgroups')
data = _readData('fsd_binary', 'marketgroups', keyIdName='marketGroupID')
_addRows(data, eos.gamedata.MarketGroup, fieldMap={'name': 'marketGroupName'})
map = {
'name_en-us': 'marketGroupName',
'description_en-us': '_description',
}
map.update({'name'+v: 'marketGroupName'+v for (k, v) in eos.config.translation_mapping.items() if k != 'en'})
map.update({'description' + v: '_description' + v for (k, v) in eos.config.translation_mapping.items() if k != 'en'})
_addRows(data, eos.gamedata.MarketGroup, fieldMap=map)
def processMetaGroups():
print('processing metagroups')
data = _readData('fsd_binary', 'metagroups', keyIdName='metaGroupID')
_addRows(data, eos.gamedata.MetaGroup)
map = {'name_en-us': 'metaGroupName'}
map.update({'name' + v: 'metaGroupName' + v for (k, v) in eos.config.translation_mapping.items() if k != 'en'})
_addRows(data, eos.gamedata.MetaGroup, fieldMap=map)
def processCloneGrades():
print('processing clonegrades')
@@ -303,20 +338,28 @@ def update_db():
newData = []
for row in data:
typeLines = []
typeId = row['typeID']
traitData = row['traits']
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}
newData.append(newRow)
try:
newRow = {
'typeID': row['typeID'],
}
for (k, v) in eos.config.translation_mapping.items():
if v == '':
v = '_en-us'
typeLines = []
traitData = row['traits{}'.format(v)]
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['traitText{}'.format(v)] = traitLine
_addRows(newData, eos.gamedata.Traits)
newData.append(newRow)
except:
pass
_addRows(newData, eos.gamedata.Traits, fieldMap={'traitText_en-us': 'traitText'})
def processMetadata():
print('processing metadata')
@@ -483,7 +526,7 @@ def update_db():
continue
if row.get('groupID') not in implant_groups:
continue
typeName = row.get('typeName', '')
typeName = row.get('typeName_en-us', '')
# Regular sets matching
m = re.match('(?P<grade>(High|Mid|Low)-grade) (?P<set>\w+) (?P<implant>(Alpha|Beta|Gamma|Delta|Epsilon|Omega))', typeName, re.IGNORECASE)
if m:

View File

@@ -20,6 +20,7 @@ added_files = [
('../../imgs/renders/*.png', 'imgs/renders'),
('../../dist_assets/win/pyfa.ico', '.'),
('../../service/jargon/*.yaml', 'service/jargon'),
('../../locale', 'locale'),
(requests.certs.where(), '.'), # is this needed anymore?
('../../eve.db', '.'),
('../../README.md', '.'),

View File

@@ -13,6 +13,24 @@ saveddataCache = True
gamedata_version = ""
gamedata_date = ""
gamedata_connectionstring = 'sqlite:///' + realpath(join(dirname(abspath(__file__)), "..", "eve.db"))
lang = ""
# Maps supported langauges to their suffix in the database
translation_mapping = {
"en": "",
"fr": "_fr",
# "it": "_it",
"ja": "_ja",
"ko": "_ko",
"ru": "_ru",
"zh": "_zh",
}
def set_lang(i18n_lang):
global lang
lang = translation_mapping.get(i18n_lang, translation_mapping.get("en"))
pyfalog.debug("Gamedata connection string: {0}", gamedata_connectionstring)
if istravis is True or hasattr(sys, '_called_from_test'):

View File

@@ -23,7 +23,7 @@ from sqlalchemy.orm import relation, mapper, synonym, deferred
from eos.db import gamedata_meta
from eos.gamedata import Attribute, AttributeInfo, Unit
import eos.config
typeattributes_table = Table("dgmtypeattribs", gamedata_meta,
Column("value", Float),
Column("typeID", Integer, ForeignKey("invtypes.typeID"), primary_key=True, index=True),
@@ -36,11 +36,11 @@ attributes_table = Table("dgmattribs", gamedata_meta,
Column("maxAttributeID", Integer, ForeignKey("dgmattribs.attributeID")),
Column("description", Unicode),
Column("published", Boolean),
Column("displayName", String),
*[Column("displayName{}".format(lang), String) for lang in eos.config.translation_mapping.values()],
Column("highIsGood", Boolean),
Column("iconID", Integer),
Column("attributeCategory", Integer),
Column("tooltipDescription", Integer),
# Column("tooltipDescription", Integer), # deprecated...?
Column("unitID", Integer, ForeignKey("dgmunits.unitID")))
mapper(Attribute, typeattributes_table,
@@ -51,14 +51,14 @@ mapper(AttributeInfo, attributes_table,
"unit" : relation(Unit),
"ID" : synonym("attributeID"),
"name" : synonym("attributeName"),
"description": deferred(attributes_table.c.description)
"description": deferred(attributes_table.c.description),
})
Attribute.ID = association_proxy("info", "attributeID")
Attribute.name = association_proxy("info", "attributeName")
Attribute.description = association_proxy("info", "description")
Attribute.published = association_proxy("info", "published")
Attribute.displayName = association_proxy("info", "displayName")
Attribute.displayName = association_proxy("info", "displayName{}".format(eos.config.lang))
Attribute.highIsGood = association_proxy("info", "highIsGood")
Attribute.iconID = association_proxy("info", "iconID")
Attribute.icon = association_proxy("info", "icon")

View File

@@ -22,17 +22,18 @@ from sqlalchemy.orm import deferred, mapper, synonym
from eos.db import gamedata_meta
from eos.gamedata import Category
import eos.config
categories_table = Table("invcategories", gamedata_meta,
Column("categoryID", Integer, primary_key=True),
Column("categoryName", String),
Column("description", String),
*[Column("name{}".format(lang), String) for lang in eos.config.translation_mapping.values()],
# Column("description", String), # deprecated
Column("published", Boolean),
Column("iconID", Integer))
mapper(Category, categories_table,
properties={
"ID" : synonym("categoryID"),
"name" : synonym("categoryName"),
"description": deferred(categories_table.c.description)
"displayName": synonym("name{}".format(eos.config.lang)),
# "description": deferred(categories_table.c.description) # deprecated
})

View File

@@ -22,11 +22,12 @@ from sqlalchemy.orm import relation, mapper, synonym, deferred, backref
from eos.db import gamedata_meta
from eos.gamedata import Category, Group
import eos.config
groups_table = Table("invgroups", gamedata_meta,
Column("groupID", Integer, primary_key=True),
Column("groupName", String),
Column("description", String),
*[Column("name{}".format(lang), String) for lang in eos.config.translation_mapping.values()],
# Column("description", String), # deprecated
Column("published", Boolean),
Column("categoryID", Integer, ForeignKey("invcategories.categoryID")),
Column("iconID", Integer))
@@ -35,6 +36,6 @@ mapper(Group, groups_table,
properties={
"category" : relation(Category, backref=backref("groups", cascade="all,delete")),
"ID" : synonym("groupID"),
"name" : synonym("groupName"),
"description": deferred(groups_table.c.description)
"displayName" : synonym("name{}".format(eos.config.lang)),
# "description": deferred(groups_table.c.description) # deprecated
})

View File

@@ -27,10 +27,12 @@ from eos.db.gamedata.dynamicAttributes import dynamicApplicable_table
from eos.db.gamedata.effect import typeeffects_table
from eos.gamedata import Attribute, DynamicItem, Effect, Group, Item, Traits, MetaGroup
import eos.config
items_table = Table("invtypes", gamedata_meta,
Column("typeID", Integer, primary_key=True),
Column("typeName", String, index=True),
Column("description", String),
*[Column("typeName{}".format(lang), String, index=True) for lang in eos.config.translation_mapping.values()],
*[Column("typeDescription{}".format(lang), String) for lang in eos.config.translation_mapping.values()],
Column("raceID", Integer),
Column("factionID", Integer),
Column("published", Boolean),
@@ -43,27 +45,38 @@ items_table = Table("invtypes", gamedata_meta,
Column("variationParentTypeID", Integer, ForeignKey("invtypes.typeID"), index=True),
Column("replacements", String),
Column("reqskills", String),
Column("requiredfor", String))
Column("requiredfor", String),
)
from .traits import traits_table # noqa
mapper(Item, items_table,
properties={
"group" : relation(Group, backref=backref("items", cascade="all,delete")),
props = {
"group": relation(Group, backref=backref("items", cascade="all,delete")),
"_Item__attributes": relation(Attribute, cascade='all, delete, delete-orphan', collection_class=attribute_mapped_collection('name')),
"effects": relation(Effect, secondary=typeeffects_table, collection_class=attribute_mapped_collection('name')),
"metaGroup" : relation(MetaGroup, backref=backref("items", cascade="all,delete")),
"varParent" : relation(Item, backref=backref("varChildren", cascade="all,delete"), remote_side=items_table.c.typeID),
"ID" : synonym("typeID"),
"name" : synonym("typeName"),
"description" : deferred(items_table.c.description),
"traits" : relation(Traits,
primaryjoin=traits_table.c.typeID == items_table.c.typeID,
uselist=False),
"mutaplasmids": relation(DynamicItem,
primaryjoin=dynamicApplicable_table.c.applicableTypeID == items_table.c.typeID,
secondaryjoin=dynamicApplicable_table.c.typeID == DynamicItem.typeID,
secondary=dynamicApplicable_table,
backref="applicableItems")})
"metaGroup": relation(MetaGroup, backref=backref("items", cascade="all,delete")),
"varParent": relation(Item, backref=backref("varChildren", cascade="all,delete"), remote_side=items_table.c.typeID),
"ID": synonym("typeID"),
"name": synonym("typeName{}".format(eos.config.lang)),
"description" : synonym("_description{}".format(eos.config.lang)),
"traits": relation(
Traits,
primaryjoin=traits_table.c.typeID == items_table.c.typeID,
uselist=False
),
"mutaplasmids": relation(
DynamicItem,
primaryjoin=dynamicApplicable_table.c.applicableTypeID == items_table.c.typeID,
secondaryjoin=dynamicApplicable_table.c.typeID == DynamicItem.typeID,
secondary=dynamicApplicable_table,
backref="applicableItems"
)
}
# Create deferred columns shadowing all the description fields. The literal `description` property will dynamically
# be assigned as synonym to one of these
props.update({'_description' + v: deferred(items_table.c['typeDescription' + v]) for (k, v) in eos.config.translation_mapping.items()})
mapper(Item, items_table, properties=props)
Item.category = association_proxy("group", "category")

View File

@@ -22,22 +22,34 @@ from sqlalchemy.orm import relation, mapper, synonym, deferred
from eos.db import gamedata_meta
from eos.gamedata import Item, MarketGroup
import eos.config
marketgroups_table = Table("invmarketgroups", gamedata_meta,
Column("marketGroupID", Integer, primary_key=True),
Column("marketGroupName", String),
Column("description", String),
*[Column("marketGroupName{}".format(lang), String) for lang in eos.config.translation_mapping.values()],
*[Column("marketGroupDescription{}".format(lang), String) for lang in eos.config.translation_mapping.values()],
Column("hasTypes", Boolean),
Column("parentGroupID", Integer,
ForeignKey("invmarketgroups.marketGroupID", initially="DEFERRED", deferrable=True)),
ForeignKey("invmarketgroups.marketGroupID", initially="DEFERRED", deferrable=True)),
Column("iconID", Integer))
mapper(MarketGroup, marketgroups_table,
properties={
"items" : relation(Item, backref="marketGroup"),
"parent" : relation(MarketGroup, backref="children",
remote_side=[marketgroups_table.c.marketGroupID]),
"ID" : synonym("marketGroupID"),
"name" : synonym("marketGroupName"),
"description": deferred(marketgroups_table.c.description)
})
props = {
"items": relation(Item, backref="marketGroup"),
"parent": relation(MarketGroup, backref="children", remote_side=[marketgroups_table.c.marketGroupID]),
"ID": synonym("marketGroupID"),
"name": synonym("marketGroupName{}".format(eos.config.lang)),
"description": synonym("_description{}".format(eos.config.lang)),
}
# Create deferred columns shadowing all the description fields. The literal `description` property will dynamically
# be assigned as synonym to one of these
# this is mostly here to allow the db_update to be language-agnostic
# todo: determine if we ever use market group descriptions... can we just get with of these?
props.update({'_description' + v: deferred(marketgroups_table.c['marketGroupDescription' + v]) for (k, v) in eos.config.translation_mapping.items()})
mapper(
MarketGroup,
marketgroups_table,
properties=props
)

View File

@@ -22,12 +22,20 @@ from sqlalchemy.orm import mapper, synonym
from eos.db import gamedata_meta
from eos.gamedata import MetaGroup
import eos.config
metagroups_table = Table("invmetagroups", gamedata_meta,
Column("metaGroupID", Integer, primary_key=True),
Column("metaGroupName", String))
metagroups_table = Table(
"invmetagroups",
gamedata_meta,
Column("metaGroupID", Integer, primary_key=True),
*[Column("metaGroupName{}".format(lang), String) for lang in eos.config.translation_mapping.values()],
)
mapper(MetaGroup, metagroups_table,
properties={
"ID" : synonym("metaGroupID"),
"name": synonym("metaGroupName")})
mapper(
MetaGroup,
metagroups_table,
properties={
"ID" : synonym("metaGroupID"),
"name": synonym("metaGroupName{}".format(eos.config.lang))
}
)

View File

@@ -91,7 +91,7 @@ def getItem(lookfor, eager=None):
item = get_gamedata_session().query(Item).options(*processEager(eager)).filter(Item.ID == id).first()
else:
# Item names are unique, so we can use first() instead of one()
item = get_gamedata_session().query(Item).options(*processEager(eager)).filter(Item.name == lookfor).first()
item = get_gamedata_session().query(Item).options(*processEager(eager)).filter(Item.typeName == lookfor).first()
if item is not None:
itemNameMap[lookfor] = item.ID
else:
@@ -265,7 +265,7 @@ def getMetaGroup(lookfor, eager=None):
else:
# MetaGroup names are unique, so we can use first() instead of one()
metaGroup = get_gamedata_session().query(MetaGroup).options(*processEager(eager)).filter(
MetaGroup.name == lookfor).first()
MetaGroup.metaGroupName == lookfor).first()
if metaGroup is not None:
metaGroupNameMap[lookfor] = metaGroup.ID
else:

View File

@@ -1,11 +1,21 @@
from sqlalchemy import Column, Table, Integer, String, ForeignKey
from sqlalchemy.orm import mapper
from sqlalchemy.orm import mapper, synonym
from eos.db import gamedata_meta
from eos.gamedata import Traits
import eos.config
traits_table = Table("invtraits", gamedata_meta,
Column("typeID", Integer, ForeignKey("invtypes.typeID"), primary_key=True),
Column("traitText", String))
traits_table = Table(
"invtraits",
gamedata_meta,
Column("typeID", Integer, ForeignKey("invtypes.typeID"), primary_key=True),
*[Column("traitText{}".format(lang), String) for lang in eos.config.translation_mapping.values()],
)
mapper(Traits, traits_table)
mapper(
Traits,
traits_table,
properties={
"display": synonym("traitText{}".format(eos.config.lang)),
}
)

View File

@@ -22,11 +22,13 @@ from sqlalchemy.orm import mapper, synonym
from eos.db import gamedata_meta
from eos.gamedata import Unit
import eos.config
groups_table = Table("dgmunits", gamedata_meta,
Column("unitID", Integer, primary_key=True),
Column("unitName", String),
Column("displayName", String))
*[Column("displayName{}".format(lang), String) for lang in eos.config.translation_mapping.values()],
)
mapper(Unit, groups_table,
properties={

View File

@@ -344,7 +344,7 @@ class Item(EqBase):
try:
if (
self.category.categoryName == 'Structure' or
self.category.name == 'Structure' or
# Here until CCP puts their shit together
self.name in ("Thunderchild", "Stormbringer", "Skybreaker")
):
@@ -423,7 +423,7 @@ class Item(EqBase):
def requiresSkill(self, skill, level=None):
for s, l in self.requiredSkills.items():
if isinstance(skill, str):
if s.name == skill and (level is None or l == level):
if s.typeName == skill and (level is None or l == level):
return True
elif isinstance(skill, int) and (level is None or l == level):
@@ -506,8 +506,8 @@ class Item(EqBase):
return False
def __repr__(self):
return "Item(ID={}, name={}) at {}".format(
self.ID, self.name, hex(id(self))
return "Item(ID={}, name={}, display={}) at {}".format(
self.ID, self.typeName, self.name, hex(id(self))
)

View File

@@ -96,7 +96,7 @@ class Character:
if cls.__itemNameMap is None:
map = {}
for skill in cls.getSkillList():
map[skill.name] = skill
map[skill.typeName] = skill
cls.__itemNameMap = map

View File

@@ -25,125 +25,140 @@ from sqlalchemy.orm import reconstructor
import eos.db
def _t(x):
return x
def _c(x):
return '[' + x + ']'
# Order is significant here - UI uses order as-is for built-in patterns
BUILTINS = OrderedDict([
(-1, ('Uniform', 25, 25, 25, 25)),
(-2, ('[Generic]EM', 1, 0, 0, 0)),
(-3, ('[Generic]Thermal', 0, 1, 0, 0)),
(-4, ('[Generic]Kinetic', 0, 0, 1, 0)),
(-5, ('[Generic]Explosive', 0, 0, 0, 1)),
(-6, ('[Frequency Crystals]|[T2] Aurora', 5, 3, 0, 0)),
(-7, ('[Frequency Crystals]|[T2] Scorch', 9, 2, 0, 0)),
(-8, ('[Frequency Crystals]Radio', 5, 0, 0, 0)),
(-9, ('[Frequency Crystals]Microwave', 4, 2, 0, 0)),
(-10, ('[Frequency Crystals]Infrared', 5, 2, 0, 0)),
(-11, ('[Frequency Crystals]Standard', 5, 3, 0, 0)),
(-12, ('[Frequency Crystals]Ultraviolet', 6, 3, 0, 0)),
(-13, ('[Frequency Crystals]Xray', 6, 4, 0, 0)),
(-14, ('[Frequency Crystals]Gamma', 7, 4, 0, 0)),
(-15, ('[Frequency Crystals]Multifrequency', 7, 5, 0, 0)),
(-16, ('[Frequency Crystals]|[T2] Gleam', 7, 7, 0, 0)),
(-17, ('[Frequency Crystals]|[T2] Conflagration', 7.7, 7.7, 0, 0)),
(-1, (_t('Uniform'), 25, 25, 25, 25)),
(-2, (_c(_t('Generic')) + _t('EM'), 1, 0, 0, 0)),
(-3, (_c(_t('Generic')) + _t('Thermal'), 0, 1, 0, 0)),
(-4, (_c(_t('Generic')) + _t('Kinetic'), 0, 0, 1, 0)),
(-5, (_c(_t('Generic')) + _t('Explosive'), 0, 0, 0, 1)),
(-6, (_c(_t('Frequency Crystals')) + '|' + _t('[T2] Aurora'), 5, 3, 0, 0)),
(-7, (_c(_t('Frequency Crystals')) + '|' + _t('[T2] Scorch'), 9, 2, 0, 0)),
(-8, (_c(_t('Frequency Crystals')) + _t('Radio'), 5, 0, 0, 0)),
(-9, (_c(_t('Frequency Crystals')) + _t('Microwave'), 4, 2, 0, 0)),
(-10, (_c(_t('Frequency Crystals')) + _t('Infrared'), 5, 2, 0, 0)),
(-11, (_c(_t('Frequency Crystals')) + _t('Standard'), 5, 3, 0, 0)),
(-12, (_c(_t('Frequency Crystals')) + _t('Ultraviolet'), 6, 3, 0, 0)),
(-13, (_c(_t('Frequency Crystals')) + _t('Xray'), 6, 4, 0, 0)),
(-14, (_c(_t('Frequency Crystals')) + _t('Gamma'), 7, 4, 0, 0)),
(-15, (_c(_t('Frequency Crystals')) + _t('Multifrequency'), 7, 5, 0, 0)),
(-16, (_c(_t('Frequency Crystals')) + '|' + _t('[T2] Gleam'), 7, 7, 0, 0)),
(-17, (_c(_t('Frequency Crystals')) + '|' + _t('[T2] Conflagration'), 7.7, 7.7, 0, 0)),
# Different sizes of plasma do different damage ratios, the values here
# are average of ratios across sizes
(-18, ('[Exotic Plasma]|[T2] Mystic', 0, 66319, 0, 33681)),
(-19, ('[Exotic Plasma]Meson', 0, 60519, 0, 39481)),
(-20, ('[Exotic Plasma]Baryon', 0, 59737, 0, 40263)),
(-21, ('[Exotic Plasma]Tetryon', 0, 69208, 0, 30792)),
(-22, ('[Exotic Plasma]|[T2] Occult', 0, 55863, 0, 44137)),
(-23, ('[Hybrid Charges]|[T2] Spike', 0, 4, 4, 0)),
(-24, ('[Hybrid Charges]|[T2] Null', 0, 6, 5, 0)),
(-25, ('[Hybrid Charges]Iron', 0, 2, 3, 0)),
(-26, ('[Hybrid Charges]Tungsten', 0, 2, 4, 0)),
(-27, ('[Hybrid Charges]Iridium', 0, 3, 4, 0)),
(-28, ('[Hybrid Charges]Lead', 0, 3, 5, 0)),
(-29, ('[Hybrid Charges]Thorium', 0, 4, 5, 0)),
(-30, ('[Hybrid Charges]Uranium', 0, 4, 6, 0)),
(-31, ('[Hybrid Charges]Plutonium', 0, 5, 6, 0)),
(-32, ('[Hybrid Charges]Antimatter', 0, 5, 7, 0)),
(-33, ('[Hybrid Charges]|[T2] Javelin', 0, 8, 6, 0)),
(-34, ('[Hybrid Charges]|[T2] Void', 0, 7.7, 7.7, 0)),
(-35, ('[Projectile Ammo]|[T2] Tremor', 0, 0, 3, 5)),
(-36, ('[Projectile Ammo]|[T2] Barrage', 0, 0, 5, 6)),
(-37, ('[Projectile Ammo]Carbonized Lead', 0, 0, 4, 1)),
(-38, ('[Projectile Ammo]Nuclear', 0, 0, 1, 4)),
(-39, ('[Projectile Ammo]Proton', 3, 0, 2, 0)),
(-40, ('[Projectile Ammo]Depleted Uranium', 0, 3, 2, 3)),
(-41, ('[Projectile Ammo]Titanium Sabot', 0, 0, 6, 2)),
(-42, ('[Projectile Ammo]EMP', 9, 0, 1, 2)),
(-43, ('[Projectile Ammo]Phased Plasma', 0, 10, 2, 0)),
(-44, ('[Projectile Ammo]Fusion', 0, 0, 2, 10)),
(-45, ('[Projectile Ammo]|[T2] Quake', 0, 0, 5, 9)),
(-46, ('[Projectile Ammo]|[T2] Hail', 0, 0, 3.3, 12.1)),
(-47, ('[Missiles]Mjolnir', 1, 0, 0, 0)),
(-48, ('[Missiles]Inferno', 0, 1, 0, 0)),
(-49, ('[Missiles]Scourge', 0, 0, 1, 0)),
(-50, ('[Missiles]Nova', 0, 0, 0, 1)),
(-51, ('[Bombs]Electron Bomb', 6400, 0, 0, 0)),
(-52, ('[Bombs]Scorch Bomb', 0, 6400, 0, 0)),
(-53, ('[Bombs]Concussion Bomb', 0, 0, 6400, 0)),
(-54, ('[Bombs]Shrapnel Bomb', 0, 0, 0, 6400)),
(-18, (_c(_t('Exotic Plasma')) + '|' + _t('[T2] Mystic'), 0, 66319, 0, 33681)),
(-19, (_c(_t('Exotic Plasma')) + _t('Meson'), 0, 60519, 0, 39481)),
(-20, (_c(_t('Exotic Plasma')) + _t('Baryon'), 0, 59737, 0, 40263)),
(-21, (_c(_t('Exotic Plasma')) + _t('Tetryon'), 0, 69208, 0, 30792)),
(-22, (_c(_t('Exotic Plasma')) + '|' + _t('[T2] Occult'), 0, 55863, 0, 44137)),
(-23, (_c(_t('Hybrid Charges')) + '|' + _t('[T2] Spike'), 0, 4, 4, 0)),
(-24, (_c(_t('Hybrid Charges')) + '|' + _t('[T2] Null'), 0, 6, 5, 0)),
(-25, (_c(_t('Hybrid Charges')) + _t('Iron'), 0, 2, 3, 0)),
(-26, (_c(_t('Hybrid Charges')) + _t('Tungsten'), 0, 2, 4, 0)),
(-27, (_c(_t('Hybrid Charges')) + _t('Iridium'), 0, 3, 4, 0)),
(-28, (_c(_t('Hybrid Charges')) + _t('Lead'), 0, 3, 5, 0)),
(-29, (_c(_t('Hybrid Charges')) + _t('Thorium'), 0, 4, 5, 0)),
(-30, (_c(_t('Hybrid Charges')) + _t('Uranium'), 0, 4, 6, 0)),
(-31, (_c(_t('Hybrid Charges')) + _t('Plutonium'), 0, 5, 6, 0)),
(-32, (_c(_t('Hybrid Charges')) + _t('Antimatter'), 0, 5, 7, 0)),
(-33, (_c(_t('Hybrid Charges')) + '|' + _t('[T2] Javelin'), 0, 8, 6, 0)),
(-34, (_c(_t('Hybrid Charges')) + '|' + _t('[T2] Void'), 0, 7.7, 7.7, 0)),
(-35, (_c(_t('Projectile Ammo')) + '|' + _t('[T2] Tremor'), 0, 0, 3, 5)),
(-36, (_c(_t('Projectile Ammo')) + '|' + _t('[T2] Barrage'), 0, 0, 5, 6)),
(-37, (_c(_t('Projectile Ammo')) + _t('Carbonized Lead'), 0, 0, 4, 1)),
(-38, (_c(_t('Projectile Ammo')) + _t('Nuclear'), 0, 0, 1, 4)),
(-39, (_c(_t('Projectile Ammo')) + _t('Proton'), 3, 0, 2, 0)),
(-40, (_c(_t('Projectile Ammo')) + _t('Depleted Uranium'), 0, 3, 2, 3)),
(-41, (_c(_t('Projectile Ammo')) + _t('Titanium Sabot'), 0, 0, 6, 2)),
(-42, (_c(_t('Projectile Ammo')) + _t('EMP'), 9, 0, 1, 2)),
(-43, (_c(_t('Projectile Ammo')) + _t('Phased Plasma'), 0, 10, 2, 0)),
(-44, (_c(_t('Projectile Ammo')) + _t('Fusion'), 0, 0, 2, 10)),
(-45, (_c(_t('Projectile Ammo')) + '|' + _t('[T2] Quake'), 0, 0, 5, 9)),
(-46, (_c(_t('Projectile Ammo')) + '|' + _t('[T2] Hail'), 0, 0, 3.3, 12.1)),
(-47, (_c(_t('Missiles')) + _t('Mjolnir'), 1, 0, 0, 0)),
(-48, (_c(_t('Missiles')) + _t('Inferno'), 0, 1, 0, 0)),
(-49, (_c(_t('Missiles')) + _t('Scourge'), 0, 0, 1, 0)),
(-50, (_c(_t('Missiles')) + _t('Nova'), 0, 0, 0, 1)),
(-51, (_c(_t('Bombs')) + _t('Electron Bomb'), 6400, 0, 0, 0)),
(-52, (_c(_t('Bombs')) + _t('Scorch Bomb'), 0, 6400, 0, 0)),
(-53, (_c(_t('Bombs')) + _t('Concussion Bomb'), 0, 0, 6400, 0)),
(-54, (_c(_t('Bombs')) + _t('Shrapnel Bomb'), 0, 0, 0, 6400)),
# Source: ticket #2067 and #2265
(-55, ('[NPC][Abyssal]All', 126, 427, 218, 230)),
(-109, ('[NPC][Abyssal]Angel', 450, 72, 80, 398)),
(-107, ('[NPC][Abyssal]Concord', 53, 559, 94, 295)),
(-56, ('[NPC][Abyssal]Drifter', 250, 250, 250, 250)),
(-57, ('[NPC][Abyssal]Drones', 250, 250, 250, 250)),
(-58, ('[NPC][Abyssal]Overmind', 0, 410, 590, 0)),
(-108, ('[NPC][Abyssal]Sansha', 569, 431, 0, 0)),
(-59, ('[NPC][Abyssal]Seeker', 402, 402, 98, 98)),
(-60, ('[NPC][Abyssal]Sleeper', 313, 313, 187, 187)),
(-61, ('[NPC][Abyssal]Triglavian', 0, 615, 0, 385)),
(-62, ('[NPC][Asteroid]Angel Cartel', 1838, 562, 2215, 3838)),
(-63, ('[NPC][Asteroid]Blood Raiders', 5067, 4214, 0, 0)),
(-64, ('[NPC][Asteroid]Guristas', 0, 1828, 7413, 0)),
(-65, ('[NPC][Asteroid]Rogue Drone', 394, 666, 1090, 1687)),
(-66, ('[NPC][Asteroid]Sanshas Nation', 5586, 4112, 0, 0)),
(-67, ('[NPC][Asteroid]Serpentis', 0, 5373, 4813, 0)),
(-68, ('[NPC][Burner]Cruor (Blood Raiders)', 90, 90, 0, 0)),
(-69, ('[NPC][Burner]Dramiel (Angel)', 55, 0, 20, 96)),
(-70, ('[NPC][Burner]Daredevil (Serpentis)', 0, 110, 154, 0)),
(-71, ('[NPC][Burner]Succubus (Sanshas Nation)', 135, 30, 0, 0)),
(-72, ('[NPC][Burner]Worm (Guristas)', 0, 0, 228, 0)),
(-73, ('[NPC][Burner]Enyo', 0, 147, 147, 0)),
(-74, ('[NPC][Burner]Hawk', 0, 0, 247, 0)),
(-75, ('[NPC][Burner]Jaguar', 36, 0, 50, 182)),
(-76, ('[NPC][Burner]Vengeance', 232, 0, 0, 0)),
(-77, ('[NPC][Burner]Ashimmu (Blood Raiders)', 260, 100, 0, 0)),
(-78, ('[NPC][Burner]Talos', 0, 413, 413, 0)),
(-79, ('[NPC][Burner]Sentinel', 0, 75, 0, 90)),
(-80, ('[NPC][Deadspace]Angel Cartel', 369, 533, 1395, 3302)),
(-81, ('[NPC][Deadspace]Blood Raiders', 6040, 5052, 10, 15)),
(-82, ('[NPC][Deadspace]Guristas', 0, 1531, 9680, 0)),
(-83, ('[NPC][Deadspace]Rogue Drone', 276, 1071, 1069, 871)),
(-84, ('[NPC][Deadspace]Sanshas Nation', 3009, 2237, 0, 0)),
(-85, ('[NPC][Deadspace]Serpentis', 0, 3110, 1929, 0)),
(-55, (_c(_t('NPC')) + _c(_t('Abyssal')) + _t('All'), 126, 427, 218, 230)),
(-109, (_c(_t('NPC')) + _c(_t('Abyssal')) + _t('Angel'), 450, 72, 80, 398)),
(-107, (_c(_t('NPC')) + _c(_t('Abyssal')) + _t('Concord'), 53, 559, 94, 295)),
(-56, (_c(_t('NPC')) + _c(_t('Abyssal')) + _t('Drifter'), 250, 250, 250, 250)),
(-57, (_c(_t('NPC')) + _c(_t('Abyssal')) + _t('Drones'), 250, 250, 250, 250)),
(-58, (_c(_t('NPC')) + _c(_t('Abyssal')) + _t('Overmind'), 0, 410, 590, 0)),
(-108, (_c(_t('NPC')) + _c(_t('Abyssal')) + _t('Sansha'), 569, 431, 0, 0)),
(-59, (_c(_t('NPC')) + _c(_t('Abyssal')) + _t('Seeker'), 402, 402, 98, 98)),
(-60, (_c(_t('NPC')) + _c(_t('Abyssal')) + _t('Sleeper'), 313, 313, 187, 187)),
(-61, (_c(_t('NPC')) + _c(_t('Abyssal')) + _t('Triglavian'), 0, 615, 0, 385)),
(-62, (_c(_t('NPC')) + _c(_t('Asteroid')) + _t('Angel Cartel'), 1838, 562, 2215, 3838)),
(-63, (_c(_t('NPC')) + _c(_t('Asteroid')) + _t('Blood Raiders'), 5067, 4214, 0, 0)),
(-64, (_c(_t('NPC')) + _c(_t('Asteroid')) + _t('Guristas'), 0, 1828, 7413, 0)),
(-65, (_c(_t('NPC')) + _c(_t('Asteroid')) + _t('Rogue Drone'), 394, 666, 1090, 1687)),
(-66, (_c(_t('NPC')) + _c(_t('Asteroid')) + _t('Sanshas Nation'), 5586, 4112, 0, 0)),
(-67, (_c(_t('NPC')) + _c(_t('Asteroid')) + _t('Serpentis'), 0, 5373, 4813, 0)),
(-68, (_c(_t('NPC')) + _c(_t('Burner')) + _t('Cruor (Blood Raiders)'), 90, 90, 0, 0)),
(-69, (_c(_t('NPC')) + _c(_t('Burner')) + _t('Dramiel (Angel)'), 55, 0, 20, 96)),
(-70, (_c(_t('NPC')) + _c(_t('Burner')) + _t('Daredevil (Serpentis)'), 0, 110, 154, 0)),
(-71, (_c(_t('NPC')) + _c(_t('Burner')) + _t('Succubus (Sanshas Nation)'), 135, 30, 0, 0)),
(-72, (_c(_t('NPC')) + _c(_t('Burner')) + _t('Worm (Guristas)'), 0, 0, 228, 0)),
(-73, (_c(_t('NPC')) + _c(_t('Burner')) + _t('Enyo'), 0, 147, 147, 0)),
(-74, (_c(_t('NPC')) + _c(_t('Burner')) + _t('Hawk'), 0, 0, 247, 0)),
(-75, (_c(_t('NPC')) + _c(_t('Burner')) + _t('Jaguar'), 36, 0, 50, 182)),
(-76, (_c(_t('NPC')) + _c(_t('Burner')) + _t('Vengeance'), 232, 0, 0, 0)),
(-77, (_c(_t('NPC')) + _c(_t('Burner')) + _t('Ashimmu (Blood Raiders)'), 260, 100, 0, 0)),
(-78, (_c(_t('NPC')) + _c(_t('Burner')) + _t('Talos'), 0, 413, 413, 0)),
(-79, (_c(_t('NPC')) + _c(_t('Burner')) + _t('Sentinel'), 0, 75, 0, 90)),
(-80, (_c(_t('NPC')) + _c(_t('Deadspace')) + _t('Angel Cartel'), 369, 533, 1395, 3302)),
(-81, (_c(_t('NPC')) + _c(_t('Deadspace')) + _t('Blood Raiders'), 6040, 5052, 10, 15)),
(-82, (_c(_t('NPC')) + _c(_t('Deadspace')) + _t('Guristas'), 0, 1531, 9680, 0)),
(-83, (_c(_t('NPC')) + _c(_t('Deadspace')) + _t('Rogue Drone'), 276, 1071, 1069, 871)),
(-84, (_c(_t('NPC')) + _c(_t('Deadspace')) + _t('Sanshas Nation'), 3009, 2237, 0, 0)),
(-85, (_c(_t('NPC')) + _c(_t('Deadspace')) + _t('Serpentis'), 0, 3110, 1929, 0)),
# Source: ticket #2067
(-86, ('[NPC][Invasion][Triglavian Entities]Dread', 0, 417, 0, 583)),
(-87, ('[NPC][Invasion][Triglavian Entities]Normal Subcaps', 0, 610, 0, 390)),
(-88, ('[NPC][Invasion][Triglavian Entities]Subcaps w/missiles 0% spool up', 367, 155, 367, 112)),
(-89, ('[NPC][Invasion][Triglavian Entities]Subcaps w/missiles 50% spool up', 291, 243, 291, 175)),
(-90, ('[NPC][Invasion][Triglavian Entities]Subcaps w/missiles 100% spool up', 241, 301, 241, 217)),
(-91, ('[NPC][Invasion][Amarr EDENCOM Entities]Dread/Subcaps', 583, 417, 0, 0)),
(-92, ('[NPC][Invasion][Caldari EDENCOM Entities]Dread', 1000, 0, 0, 0)),
(-93, ('[NPC][Invasion][Caldari EDENCOM Entities]Subcaps', 511, 21, 29, 440)),
(-94, ('[NPC][Invasion][Gallente EDENCOM Entities]Dread/Subcaps', 0, 417, 583, 0)),
(-95, ('[NPC][Invasion][Minmatar EDENCOM Entities]Dread', 0, 0, 583, 417)),
(-96, ('[NPC][Invasion][Minmatar EDENCOM Entities]Subcaps', 302, 136, 328, 234)),
(-97, ('[NPC][Mission]Amarr Empire', 4464, 3546, 97, 0)),
(-98, ('[NPC][Mission]Caldari State', 0, 2139, 4867, 0)),
(-99, ('[NPC][Mission]CONCORD', 336, 134, 212, 412)),
(-100, ('[NPC][Mission]Gallente Federation', 9, 3712, 2758, 0)),
(-101, ('[NPC][Mission]Khanid', 612, 483, 43, 6)),
(-102, ('[NPC][Mission]Minmatar Republic', 1024, 388, 1655, 4285)),
(-103, ('[NPC][Mission]Mordus Legion', 25, 262, 625, 0)),
(-104, ('[NPC][Mission]Thukker', 0, 52, 10, 79)),
(-105, ('[NPC]Sansha Incursion', 1682, 1347, 3678, 3678)),
(-106, ('[NPC]Sleepers', 1472, 1472, 1384, 1384))])
(-86, (_c(_t('NPC')) + _c(_t('Invasion')) + _c(_t('Triglavian Entities')) + _t('Dread'), 0, 417, 0, 583)),
(-87, (_c(_t('NPC')) + _c(_t('Invasion')) + _c(_t('Triglavian Entities')) + _t('Normal Subcaps'), 0, 610, 0, 390)),
# To avoid errors on msgfmt, we have to mark that '0%' is meaning literally 0% with no-python-format.
# See also: https://github.com/vslavik/poedit/issues/645
(-88, (_c(_t('NPC')) + _c(_t('Invasion')) + _c(_t('Triglavian Entities')) +
# xgettext:no-python-format
_t('Subcaps w/missiles 0% spool up'), 367, 155, 367, 112)),
(-89, (_c(_t('NPC')) + _c(_t('Invasion')) + _c(_t('Triglavian Entities')) +
# xgettext:no-python-format
_t('Subcaps w/missiles 50% spool up'), 291, 243, 291, 175)),
(-90, (_c(_t('NPC')) + _c(_t('Invasion')) + _c(_t('Triglavian Entities')) +
# xgettext:no-python-format
_t('Subcaps w/missiles 100% spool up'), 241, 301, 241, 217)),
(-91, (_c(_t('NPC')) + _c(_t('Invasion')) + _c(_t('Amarr EDENCOM Entities')) + _t('Dread/Subcaps'), 583, 417, 0, 0)),
(-92, (_c(_t('NPC')) + _c(_t('Invasion')) + _c(_t('Caldari EDENCOM Entities')) + _t('Dread'), 1000, 0, 0, 0)),
(-93, (_c(_t('NPC')) + _c(_t('Invasion')) + _c(_t('Caldari EDENCOM Entities')) + _t('Subcaps'), 511, 21, 29, 440)),
(-94, (_c(_t('NPC')) + _c(_t('Invasion')) + _c(_t('Gallente EDENCOM Entities')) + _t('Dread/Subcaps'), 0, 417, 583, 0)),
(-95, (_c(_t('NPC')) + _c(_t('Invasion')) + _c(_t('Minmatar EDENCOM Entities')) + _t('Dread'), 0, 0, 583, 417)),
(-96, (_c(_t('NPC')) + _c(_t('Invasion')) + _c(_t('Minmatar EDENCOM Entities')) + _t('Subcaps'), 302, 136, 328, 234)),
(-97, (_c(_t('NPC')) + _c(_t('Mission')) + _t('Amarr Empire'), 4464, 3546, 97, 0)),
(-98, (_c(_t('NPC')) + _c(_t('Mission')) + _t('Caldari State'), 0, 2139, 4867, 0)),
(-99, (_c(_t('NPC')) + _c(_t('Mission')) + _t('CONCORD'), 336, 134, 212, 412)),
(-100, (_c(_t('NPC')) + _c(_t('Mission')) + _t('Gallente Federation'), 9, 3712, 2758, 0)),
(-101, (_c(_t('NPC')) + _c(_t('Mission')) + _t('Khanid'), 612, 483, 43, 6)),
(-102, (_c(_t('NPC')) + _c(_t('Mission')) + _t('Minmatar Republic'), 1024, 388, 1655, 4285)),
(-103, (_c(_t('NPC')) + _c(_t('Mission')) + _t('Mordus Legion'), 25, 262, 625, 0)),
(-104, (_c(_t('NPC')) + _c(_t('Mission')) + _t('Thukker'), 0, 52, 10, 79)),
(-105, (_c(_t('NPC')) + _t('Sansha Incursion'), 1682, 1347, 3678, 3678)),
(-106, (_c(_t('NPC')) + _t('Sleepers'), 1472, 1472, 1384, 1384))])
class DamagePattern:
DAMAGE_TYPES = ('em', 'thermal', 'kinetic', 'explosive')
_builtins = None
@@ -204,7 +219,8 @@ class DamagePattern:
"armorRepair": "armor",
"armorRepairPreSpool": "armor",
"armorRepairFullSpool": "armor",
"hullRepair": "hull"}
"hullRepair": "hull"
}
ereps = {}
for field in tankInfo:
if field in typeMap:
@@ -228,10 +244,10 @@ class DamagePattern:
return amount / (specificDivider or 1)
importMap = {
"em" : "em",
"em": "em",
"therm": "thermal",
"kin" : "kinetic",
"exp" : "explosive"
"kin": "kinetic",
"exp": "explosive"
}
@classmethod

View File

@@ -42,10 +42,13 @@ from eos.saveddata.targetProfile import TargetProfile
from eos.utils.float import floatUnerr
from eos.utils.stats import DmgTypes, RRTypes
pyfalog = Logger(__name__)
def _t(x):
return x
class FitLite:
def __init__(self, id=None, name=None, shipID=None, shipName=None, shipNameShort=None):
@@ -395,16 +398,16 @@ class Fit:
@property
def scanType(self):
maxStr = -1
type = None
for scanType in ("Magnetometric", "Ladar", "Radar", "Gravimetric"):
type_ = None
for scanType in (_t("Magnetometric"), _t("Ladar"), _t("Radar"), _t("Gravimetric")):
currStr = self.ship.getModifiedItemAttr("scan%sStrength" % scanType)
if currStr > maxStr:
maxStr = currStr
type = scanType
type_ = scanType
elif currStr == maxStr:
type = "Multispectral"
type_ = _t("Multispectral")
return type
return type_
@property
def jamChance(self):
@@ -443,9 +446,9 @@ class Fit:
@validates("ID", "ownerID", "shipID")
def validator(self, key, val):
map = {
"ID" : lambda _val: isinstance(_val, int),
"ID": lambda _val: isinstance(_val, int),
"ownerID": lambda _val: isinstance(_val, int) or _val is None,
"shipID" : lambda _val: isinstance(_val, int) or _val is None
"shipID": lambda _val: isinstance(_val, int) or _val is None
}
if not map[key](val):
@@ -578,15 +581,15 @@ class Fit:
if warfareBuffID == 11: # Shield Burst: Active Shielding: Repair Duration/Capacitor
self.modules.filteredItemBoost(
lambda mod: mod.item.requiresSkill("Shield Operation") or
mod.item.requiresSkill("Shield Emission Systems") or
mod.item.requiresSkill("Capital Shield Emission Systems"),
"capacitorNeed", value)
lambda mod: mod.item.requiresSkill("Shield Operation") or
mod.item.requiresSkill("Shield Emission Systems") or
mod.item.requiresSkill("Capital Shield Emission Systems"),
"capacitorNeed", value)
self.modules.filteredItemBoost(
lambda mod: mod.item.requiresSkill("Shield Operation") or
mod.item.requiresSkill("Shield Emission Systems") or
mod.item.requiresSkill("Capital Shield Emission Systems"),
"duration", value)
lambda mod: mod.item.requiresSkill("Shield Operation") or
mod.item.requiresSkill("Shield Emission Systems") or
mod.item.requiresSkill("Capital Shield Emission Systems"),
"duration", value)
if warfareBuffID == 12: # Shield Burst: Shield Extension: Shield HP
self.ship.boostItemAttr("shieldCapacity", value, stackingPenalties=True)
@@ -597,15 +600,15 @@ class Fit:
if warfareBuffID == 14: # Armor Burst: Rapid Repair: Repair Duration/Capacitor
self.modules.filteredItemBoost(
lambda mod: mod.item.requiresSkill("Remote Armor Repair Systems") or
mod.item.requiresSkill("Repair Systems") or
mod.item.requiresSkill("Capital Remote Armor Repair Systems"),
"capacitorNeed", value)
lambda mod: mod.item.requiresSkill("Remote Armor Repair Systems") or
mod.item.requiresSkill("Repair Systems") or
mod.item.requiresSkill("Capital Remote Armor Repair Systems"),
"capacitorNeed", value)
self.modules.filteredItemBoost(
lambda mod: mod.item.requiresSkill("Remote Armor Repair Systems") or
mod.item.requiresSkill("Repair Systems") or
mod.item.requiresSkill("Capital Remote Armor Repair Systems"),
"duration", value)
lambda mod: mod.item.requiresSkill("Remote Armor Repair Systems") or
mod.item.requiresSkill("Repair Systems") or
mod.item.requiresSkill("Capital Remote Armor Repair Systems"),
"duration", value)
if warfareBuffID == 15: # Armor Burst: Armor Reinforcement: Armor HP
self.ship.boostItemAttr("armorHP", value, stackingPenalties=True)
@@ -1006,14 +1009,14 @@ class Fit:
for _ in range(projectionInfo.amount):
targetFit.register(item, origin=self)
item.calculateModifiedAttributes(
targetFit, runTime, forceProjected=True,
forcedProjRange=0)
targetFit, runTime, forceProjected=True,
forcedProjRange=0)
for mod in self.modules:
for _ in range(projectionInfo.amount):
targetFit.register(mod, origin=self)
mod.calculateModifiedAttributes(
targetFit, runTime, forceProjected=True,
forcedProjRange=projectionInfo.projectionRange)
targetFit, runTime, forceProjected=True,
forcedProjRange=projectionInfo.projectionRange)
def fill(self):
"""
@@ -1029,7 +1032,8 @@ class Fit:
# Look for any dummies of that type to remove
posToRemove = {}
for slotType in (FittingSlot.LOW.value, FittingSlot.MED.value, FittingSlot.HIGH.value, FittingSlot.RIG.value, FittingSlot.SUBSYSTEM.value, FittingSlot.SERVICE.value):
for slotType in (
FittingSlot.LOW.value, FittingSlot.MED.value, FittingSlot.HIGH.value, FittingSlot.RIG.value, FittingSlot.SUBSYSTEM.value, FittingSlot.SERVICE.value):
amount = self.getSlotsFree(slotType, True)
if amount > 0:
for _ in range(int(amount)):
@@ -1106,22 +1110,23 @@ class Fit:
for mod in chain(self.modules, self.fighters):
if mod.slot is type and (not getattr(mod, "isEmpty", False) or countDummies):
if type in (FittingSlot.F_HEAVY, FittingSlot.F_SUPPORT, FittingSlot.F_LIGHT, FittingSlot.FS_HEAVY, FittingSlot.FS_LIGHT, FittingSlot.FS_SUPPORT) and not mod.active:
if type in (FittingSlot.F_HEAVY, FittingSlot.F_SUPPORT, FittingSlot.F_LIGHT, FittingSlot.FS_HEAVY, FittingSlot.FS_LIGHT,
FittingSlot.FS_SUPPORT) and not mod.active:
continue
amount += 1
return amount
slots = {
FittingSlot.LOW : "lowSlots",
FittingSlot.MED : "medSlots",
FittingSlot.HIGH : "hiSlots",
FittingSlot.RIG : "rigSlots",
FittingSlot.LOW: "lowSlots",
FittingSlot.MED: "medSlots",
FittingSlot.HIGH: "hiSlots",
FittingSlot.RIG: "rigSlots",
FittingSlot.SUBSYSTEM: "maxSubSystems",
FittingSlot.SERVICE : "serviceSlots",
FittingSlot.F_LIGHT : "fighterLightSlots",
FittingSlot.SERVICE: "serviceSlots",
FittingSlot.F_LIGHT: "fighterLightSlots",
FittingSlot.F_SUPPORT: "fighterSupportSlots",
FittingSlot.F_HEAVY : "fighterHeavySlots",
FittingSlot.F_HEAVY: "fighterHeavySlots",
FittingSlot.FS_LIGHT: "fighterStandupLightSlots",
FittingSlot.FS_SUPPORT: "fighterStandupSupportSlots",
FittingSlot.FS_HEAVY: "fighterStandupHeavySlots",
@@ -1403,8 +1408,8 @@ class Fit:
"""Return how much cap regen do we gain from having this module"""
currentRegen = self.calculateCapRecharge()
nomodRegen = self.calculateCapRecharge(
capacity=self.ship.getModifiedItemAttrExtended("capacitorCapacity", ignoreAfflictors=[mod]),
rechargeRate=self.ship.getModifiedItemAttrExtended("rechargeRate", ignoreAfflictors=[mod]) / 1000.0)
capacity=self.ship.getModifiedItemAttrExtended("capacitorCapacity", ignoreAfflictors=[mod]),
rechargeRate=self.ship.getModifiedItemAttrExtended("rechargeRate", ignoreAfflictors=[mod]) / 1000.0)
return currentRegen - nomodRegen
def getRemoteReps(self, spoolOptions=None):
@@ -1448,7 +1453,8 @@ class Fit:
"armorRepair": self.extraAttributes["armorRepair"],
"armorRepairPreSpool": self.extraAttributes["armorRepairPreSpool"],
"armorRepairFullSpool": self.extraAttributes["armorRepairFullSpool"],
"hullRepair": self.extraAttributes["hullRepair"]}
"hullRepair": self.extraAttributes["hullRepair"]
}
return reps
@property
@@ -1488,7 +1494,8 @@ class Fit:
"armorRepair": self.extraAttributes["armorRepair"],
"armorRepairPreSpool": self.extraAttributes["armorRepairPreSpool"],
"armorRepairFullSpool": self.extraAttributes["armorRepairFullSpool"],
"hullRepair": self.extraAttributes["hullRepair"]}
"hullRepair": self.extraAttributes["hullRepair"]
}
if not self.capStable or self.factorReload:
# Map a local repairer type to the attribute it uses
groupAttrMap = {
@@ -1496,14 +1503,16 @@ class Fit:
"Ancillary Shield Booster": "shieldBonus",
"Armor Repair Unit": "armorDamageAmount",
"Ancillary Armor Repairer": "armorDamageAmount",
"Hull Repair Unit": "structureDamageAmount"}
"Hull Repair Unit": "structureDamageAmount"
}
# Map local repairer type to tank type
groupStoreMap = {
"Shield Booster": "shieldRepair",
"Ancillary Shield Booster": "shieldRepair",
"Armor Repair Unit": "armorRepair",
"Ancillary Armor Repairer": "armorRepair",
"Hull Repair Unit": "hullRepair"}
"Hull Repair Unit": "hullRepair"
}
repairers = []
localAdjustment = {"shieldRepair": 0, "armorRepair": 0, "hullRepair": 0}
capUsed = self.capUsed
@@ -1555,7 +1564,7 @@ class Fit:
# Sort repairers by efficiency. We want to use the most efficient repairers first
repairers.sort(key=lambda _mod: _mod.getModifiedItemAttr(
groupAttrMap[_mod.item.group.name]) * (_mod.getModifiedItemAttr(
groupAttrMap[_mod.item.group.name]) * (_mod.getModifiedItemAttr(
"chargedArmorDamageMultiplier") or 1) / _mod.getModifiedItemAttr("capacitorNeed"), reverse=True)
# Loop through every module until we're above peak recharge
@@ -1680,7 +1689,6 @@ class Fit:
secstatus = FitSystemSecurity.NULLSEC
return secstatus
def activeModulesIter(self):
for mod in self.modules:
if mod.state >= FittingModuleState.ACTIVE:

View File

@@ -26,204 +26,210 @@ from sqlalchemy.orm import reconstructor
import eos.db
pyfalog = Logger(__name__)
def _t(x):
return x
def _c(x):
return '[' + x + ']'
BUILTINS = OrderedDict([
# 0 is taken by ideal target profile, composed manually in one of TargetProfile methods
(-1, ('Uniform (25%)', 0.25, 0.25, 0.25, 0.25)),
(-2, ('Uniform (50%)', 0.50, 0.50, 0.50, 0.50)),
(-3, ('Uniform (75%)', 0.75, 0.75, 0.75, 0.75)),
(-4, ('Uniform (90%)', 0.90, 0.90, 0.90, 0.90)),
(-5, ('[T1 Resist]Shield', 0.0, 0.20, 0.40, 0.50)),
(-6, ('[T1 Resist]Armor', 0.50, 0.45, 0.25, 0.10)),
(-7, ('[T1 Resist]Hull', 0.33, 0.33, 0.33, 0.33)),
(-8, ('[T1 Resist]Shield (+T2 DCU)', 0.125, 0.30, 0.475, 0.562)),
(-9, ('[T1 Resist]Armor (+T2 DCU)', 0.575, 0.532, 0.363, 0.235)),
(-10, ('[T1 Resist]Hull (+T2 DCU)', 0.598, 0.598, 0.598, 0.598)),
(-11, ('[T2 Resist]Amarr (Shield)', 0.0, 0.20, 0.70, 0.875)),
(-12, ('[T2 Resist]Amarr (Armor)', 0.50, 0.35, 0.625, 0.80)),
(-13, ('[T2 Resist]Caldari (Shield)', 0.20, 0.84, 0.76, 0.60)),
(-14, ('[T2 Resist]Caldari (Armor)', 0.50, 0.8625, 0.625, 0.10)),
(-15, ('[T2 Resist]Gallente (Shield)', 0.0, 0.60, 0.85, 0.50)),
(-16, ('[T2 Resist]Gallente (Armor)', 0.50, 0.675, 0.8375, 0.10)),
(-17, ('[T2 Resist]Minmatar (Shield)', 0.75, 0.60, 0.40, 0.50)),
(-18, ('[T2 Resist]Minmatar (Armor)', 0.90, 0.675, 0.25, 0.10)),
(-19, ('[NPC][Asteroid]Angel Cartel', 0.54, 0.42, 0.37, 0.32)),
(-20, ('[NPC][Asteroid]Blood Raiders', 0.34, 0.39, 0.45, 0.52)),
(-21, ('[NPC][Asteroid]Guristas', 0.55, 0.35, 0.3, 0.48)),
(-22, ('[NPC][Asteroid]Rogue Drones', 0.35, 0.38, 0.44, 0.49)),
(-23, ('[NPC][Asteroid]Sanshas Nation', 0.35, 0.4, 0.47, 0.53)),
(-24, ('[NPC][Asteroid]Serpentis', 0.49, 0.38, 0.29, 0.51)),
(-25, ('[NPC][Deadspace]Angel Cartel', 0.59, 0.48, 0.4, 0.32)),
(-26, ('[NPC][Deadspace]Blood Raiders', 0.31, 0.39, 0.47, 0.56)),
(-27, ('[NPC][Deadspace]Guristas', 0.57, 0.39, 0.31, 0.5)),
(-28, ('[NPC][Deadspace]Rogue Drones', 0.42, 0.42, 0.47, 0.49)),
(-29, ('[NPC][Deadspace]Sanshas Nation', 0.31, 0.39, 0.47, 0.56)),
(-30, ('[NPC][Deadspace]Serpentis', 0.49, 0.38, 0.29, 0.56)),
(-31, ('[NPC][Mission]Amarr Empire', 0.34, 0.38, 0.42, 0.46)),
(-32, ('[NPC][Mission]Caldari State', 0.51, 0.38, 0.3, 0.51)),
(-33, ('[NPC][Mission]CONCORD', 0.47, 0.46, 0.47, 0.47)),
(-34, ('[NPC][Mission]Gallente Federation', 0.51, 0.38, 0.31, 0.52)),
(-35, ('[NPC][Mission]Khanid', 0.51, 0.42, 0.36, 0.4)),
(-36, ('[NPC][Mission]Minmatar Republic', 0.51, 0.46, 0.41, 0.35)),
(-37, ('[NPC][Mission]Mordus Legion', 0.32, 0.48, 0.4, 0.62)),
(-38, ('[NPC][Other]Sleeper', 0.61, 0.61, 0.61, 0.61)),
(-39, ('[NPC][Other]Sansha Incursion', 0.65, 0.63, 0.64, 0.65)),
(-40, ('[NPC][Burner]Cruor (Blood Raiders)', 0.8, 0.73, 0.69, 0.67)),
(-41, ('[NPC][Burner]Dramiel (Angel)', 0.35, 0.48, 0.61, 0.68)),
(-42, ('[NPC][Burner]Daredevil (Serpentis)', 0.69, 0.59, 0.59, 0.43)),
(-43, ('[NPC][Burner]Succubus (Sanshas Nation)', 0.35, 0.48, 0.61, 0.68)),
(-44, ('[NPC][Burner]Worm (Guristas)', 0.48, 0.58, 0.69, 0.74)),
(-45, ('[NPC][Burner]Enyo', 0.58, 0.72, 0.86, 0.24)),
(-46, ('[NPC][Burner]Hawk', 0.3, 0.86, 0.79, 0.65)),
(-47, ('[NPC][Burner]Jaguar', 0.78, 0.65, 0.48, 0.56)),
(-48, ('[NPC][Burner]Vengeance', 0.66, 0.56, 0.75, 0.86)),
(-49, ('[NPC][Burner]Ashimmu (Blood Raiders)', 0.8, 0.76, 0.68, 0.7)),
(-50, ('[NPC][Burner]Talos', 0.68, 0.59, 0.59, 0.43)),
(-51, ('[NPC][Burner]Sentinel', 0.58, 0.45, 0.52, 0.66)),
(-1, (_t('Uniform (25%)'), 0.25, 0.25, 0.25, 0.25)),
(-2, (_t('Uniform (50%)'), 0.50, 0.50, 0.50, 0.50)),
(-3, (_t('Uniform (75%)'), 0.75, 0.75, 0.75, 0.75)),
(-4, (_t('Uniform (90%)'), 0.90, 0.90, 0.90, 0.90)),
(-5, (_c(_t('T1 Resist')) + _t('Shield'), 0.0, 0.20, 0.40, 0.50)),
(-6, (_c(_t('T1 Resist')) + _t('Armor'), 0.50, 0.45, 0.25, 0.10)),
(-7, (_c(_t('T1 Resist')) + _t('Hull'), 0.33, 0.33, 0.33, 0.33)),
(-8, (_c(_t('T1 Resist')) + _t('Shield (+T2 DCU)'), 0.125, 0.30, 0.475, 0.562)),
(-9, (_c(_t('T1 Resist')) + _t('Armor (+T2 DCU)'), 0.575, 0.532, 0.363, 0.235)),
(-10, (_c(_t('T1 Resist')) + _t('Hull (+T2 DCU)'), 0.598, 0.598, 0.598, 0.598)),
(-11, (_c(_t('T2 Resist')) + _t('Amarr (Shield)'), 0.0, 0.20, 0.70, 0.875)),
(-12, (_c(_t('T2 Resist')) + _t('Amarr (Armor)'), 0.50, 0.35, 0.625, 0.80)),
(-13, (_c(_t('T2 Resist')) + _t('Caldari (Shield)'), 0.20, 0.84, 0.76, 0.60)),
(-14, (_c(_t('T2 Resist')) + _t('Caldari (Armor)'), 0.50, 0.8625, 0.625, 0.10)),
(-15, (_c(_t('T2 Resist')) + _t('Gallente (Shield)'), 0.0, 0.60, 0.85, 0.50)),
(-16, (_c(_t('T2 Resist')) + _t('Gallente (Armor)'), 0.50, 0.675, 0.8375, 0.10)),
(-17, (_c(_t('T2 Resist')) + _t('Minmatar (Shield)'), 0.75, 0.60, 0.40, 0.50)),
(-18, (_c(_t('T2 Resist')) + _t('Minmatar (Armor)'), 0.90, 0.675, 0.25, 0.10)),
(-19, (_c(_t('NPC')) + _c(_t('Asteroid')) + _t('Angel Cartel'), 0.54, 0.42, 0.37, 0.32)),
(-20, (_c(_t('NPC')) + _c(_t('Asteroid')) + _t('Blood Raiders'), 0.34, 0.39, 0.45, 0.52)),
(-21, (_c(_t('NPC')) + _c(_t('Asteroid')) + _t('Guristas'), 0.55, 0.35, 0.3, 0.48)),
(-22, (_c(_t('NPC')) + _c(_t('Asteroid')) + _t('Rogue Drones'), 0.35, 0.38, 0.44, 0.49)),
(-23, (_c(_t('NPC')) + _c(_t('Asteroid')) + _t('Sanshas Nation'), 0.35, 0.4, 0.47, 0.53)),
(-24, (_c(_t('NPC')) + _c(_t('Asteroid')) + _t('Serpentis'), 0.49, 0.38, 0.29, 0.51)),
(-25, (_c(_t('NPC')) + _c(_t('Deadspace')) + _t('Angel Cartel'), 0.59, 0.48, 0.4, 0.32)),
(-26, (_c(_t('NPC')) + _c(_t('Deadspace')) + _t('Blood Raiders'), 0.31, 0.39, 0.47, 0.56)),
(-27, (_c(_t('NPC')) + _c(_t('Deadspace')) + _t('Guristas'), 0.57, 0.39, 0.31, 0.5)),
(-28, (_c(_t('NPC')) + _c(_t('Deadspace')) + _t('Rogue Drones'), 0.42, 0.42, 0.47, 0.49)),
(-29, (_c(_t('NPC')) + _c(_t('Deadspace')) + _t('Sanshas Nation'), 0.31, 0.39, 0.47, 0.56)),
(-30, (_c(_t('NPC')) + _c(_t('Deadspace')) + _t('Serpentis'), 0.49, 0.38, 0.29, 0.56)),
(-31, (_c(_t('NPC')) + _c(_t('Mission')) + _t('Amarr Empire'), 0.34, 0.38, 0.42, 0.46)),
(-32, (_c(_t('NPC')) + _c(_t('Mission')) + _t('Caldari State'), 0.51, 0.38, 0.3, 0.51)),
(-33, (_c(_t('NPC')) + _c(_t('Mission')) + _t('CONCORD'), 0.47, 0.46, 0.47, 0.47)),
(-34, (_c(_t('NPC')) + _c(_t('Mission')) + _t('Gallente Federation'), 0.51, 0.38, 0.31, 0.52)),
(-35, (_c(_t('NPC')) + _c(_t('Mission')) + _t('Khanid'), 0.51, 0.42, 0.36, 0.4)),
(-36, (_c(_t('NPC')) + _c(_t('Mission')) + _t('Minmatar Republic'), 0.51, 0.46, 0.41, 0.35)),
(-37, (_c(_t('NPC')) + _c(_t('Mission')) + _t('Mordus Legion'), 0.32, 0.48, 0.4, 0.62)),
(-38, (_c(_t('NPC')) + _c(_t('Other')) + _t('Sleeper'), 0.61, 0.61, 0.61, 0.61)),
(-39, (_c(_t('NPC')) + _c(_t('Other')) + _t('Sansha Incursion'), 0.65, 0.63, 0.64, 0.65)),
(-40, (_c(_t('NPC')) + _c(_t('Burner')) + _t('Cruor (Blood Raiders)'), 0.8, 0.73, 0.69, 0.67)),
(-41, (_c(_t('NPC')) + _c(_t('Burner')) + _t('Dramiel (Angel)'), 0.35, 0.48, 0.61, 0.68)),
(-42, (_c(_t('NPC')) + _c(_t('Burner')) + _t('Daredevil (Serpentis)'), 0.69, 0.59, 0.59, 0.43)),
(-43, (_c(_t('NPC')) + _c(_t('Burner')) + _t('Succubus (Sanshas Nation)'), 0.35, 0.48, 0.61, 0.68)),
(-44, (_c(_t('NPC')) + _c(_t('Burner')) + _t('Worm (Guristas)'), 0.48, 0.58, 0.69, 0.74)),
(-45, (_c(_t('NPC')) + _c(_t('Burner')) + _t('Enyo'), 0.58, 0.72, 0.86, 0.24)),
(-46, (_c(_t('NPC')) + _c(_t('Burner')) + _t('Hawk'), 0.3, 0.86, 0.79, 0.65)),
(-47, (_c(_t('NPC')) + _c(_t('Burner')) + _t('Jaguar'), 0.78, 0.65, 0.48, 0.56)),
(-48, (_c(_t('NPC')) + _c(_t('Burner')) + _t('Vengeance'), 0.66, 0.56, 0.75, 0.86)),
(-49, (_c(_t('NPC')) + _c(_t('Burner')) + _t('Ashimmu (Blood Raiders)'), 0.8, 0.76, 0.68, 0.7)),
(-50, (_c(_t('NPC')) + _c(_t('Burner')) + _t('Talos'), 0.68, 0.59, 0.59, 0.43)),
(-51, (_c(_t('NPC')) + _c(_t('Burner')) + _t('Sentinel'), 0.58, 0.45, 0.52, 0.66)),
# Source: ticket #2067
(-52, ('[NPC][Invasion]Triglavian Entities', 0.422, 0.367, 0.453, 0.411)),
(-53, ('[NPC][Invasion]Amarr EDENCOM Entities', 0.360, 0.310, 0.441, 0.602)),
(-54, ('[NPC][Invasion]Caldari EDENCOM Entities', 0.303, 0.610, 0.487, 0.401)),
(-55, ('[NPC][Invasion]Gallente EDENCOM Entities', 0.383, 0.414, 0.578, 0.513)),
(-56, ('[NPC][Invasion]Minmatar EDENCOM Entities', 0.620, 0.422, 0.355, 0.399)),
(-57, ('[NPC][Abyssal][Dark Matter All Tiers]Drones', 0.439, 0.522, 0.529, 0.435)),
(-58, ('[NPC][Abyssal][Dark Matter All Tiers]Overmind', 0.643, 0.593, 0.624, 0.639)),
(-59, ('[NPC][Abyssal][Dark Matter All Tiers]Seeker', 0.082, 0.082, 0.082, 0.082)),
(-60, ('[NPC][Abyssal][Dark Matter All Tiers]Triglavian', 0.494, 0.41, 0.464, 0.376)),
(-61, ('[NPC][Abyssal][Dark Matter All Tiers]Drifter', 0.415, 0.415, 0.415, 0.415)),
(-62, ('[NPC][Abyssal][Dark Matter All Tiers]Sleeper', 0.435, 0.435, 0.435, 0.435)),
(-63, ('[NPC][Abyssal][Dark Matter All Tiers]All', 0.508, 0.474, 0.495, 0.488)),
(-64, ('[NPC][Abyssal][Electrical T0/T1/T2]Drones', 0.323, 0.522, 0.529, 0.435)),
(-65, ('[NPC][Abyssal][Electrical T0/T1/T2]Overmind', 0.542, 0.593, 0.624, 0.639)),
(-66, ('[NPC][Abyssal][Electrical T0/T1/T2]Seeker', 0, 0.082, 0.082, 0.082)),
(-67, ('[NPC][Abyssal][Electrical T0/T1/T2]Triglavian', 0.356, 0.41, 0.464, 0.376)),
(-68, ('[NPC][Abyssal][Electrical T0/T1/T2]Drifter', 0.277, 0.415, 0.415, 0.415)),
(-69, ('[NPC][Abyssal][Electrical T0/T1/T2]Sleeper', 0.329, 0.435, 0.435, 0.435)),
(-70, ('[NPC][Abyssal][Electrical T0/T1/T2]All', 0.381, 0.474, 0.495, 0.488)),
(-71, ('[NPC][Abyssal][Electrical T3 (Some T5 Rooms)]Drones', 0.255, 0.522, 0.529, 0.435)),
(-72, ('[NPC][Abyssal][Electrical T3 (Some T5 Rooms)]Overmind', 0.48, 0.593, 0.624, 0.639)),
(-73, ('[NPC][Abyssal][Electrical T3 (Some T5 Rooms)]Seeker', 0, 0.082, 0.082, 0.082)),
(-74, ('[NPC][Abyssal][Electrical T3 (Some T5 Rooms)]Triglavian', 0.268, 0.41, 0.464, 0.376)),
(-75, ('[NPC][Abyssal][Electrical T3 (Some T5 Rooms)]Drifter', 0.191, 0.415, 0.415, 0.415)),
(-76, ('[NPC][Abyssal][Electrical T3 (Some T5 Rooms)]Sleeper', 0.268, 0.435, 0.435, 0.435)),
(-77, ('[NPC][Abyssal][Electrical T3 (Some T5 Rooms)]All', 0.308, 0.474, 0.495, 0.488)),
(-78, ('[NPC][Abyssal][Electrical T4/T5/T6]Drones', 0.193, 0.522, 0.529, 0.435)),
(-79, ('[NPC][Abyssal][Electrical T4/T5/T6]Overmind', 0.423, 0.593, 0.624, 0.639)),
(-80, ('[NPC][Abyssal][Electrical T4/T5/T6]Seeker', 0, 0.082, 0.082, 0.082)),
(-81, ('[NPC][Abyssal][Electrical T4/T5/T6]Triglavian', 0.206, 0.41, 0.464, 0.376)),
(-82, ('[NPC][Abyssal][Electrical T4/T5/T6]Drifter', 0.111, 0.415, 0.415, 0.415)),
(-83, ('[NPC][Abyssal][Electrical T4/T5/T6]Sleeper', 0.215, 0.435, 0.435, 0.435)),
(-84, ('[NPC][Abyssal][Electrical T4/T5/T6]All', 0.247, 0.474, 0.495, 0.488)),
(-85, ('[NPC][Abyssal][Firestorm T0/T1/T2]Drones', 0.461, 0.425, 0.541, 0.443)),
(-86, ('[NPC][Abyssal][Firestorm T0/T1/T2]Overmind', 0.666, 0.489, 0.634, 0.646)),
(-87, ('[NPC][Abyssal][Firestorm T0/T1/T2]Seeker', 0.084, 0, 0.084, 0.084)),
(-88, ('[NPC][Abyssal][Firestorm T0/T1/T2]Triglavian', 0.537, 0.269, 0.489, 0.371)),
(-89, ('[NPC][Abyssal][Firestorm T0/T1/T2]Drifter', 0.43, 0.289, 0.43, 0.43)),
(-90, ('[NPC][Abyssal][Firestorm T0/T1/T2]Sleeper', 0.512, 0.402, 0.512, 0.512)),
(-91, ('[NPC][Abyssal][Firestorm T0/T1/T2]All', 0.537, 0.352, 0.512, 0.495)),
(-92, ('[NPC][Abyssal][Firestorm T3 (Some T5 Rooms)]Drones', 0.461, 0.36, 0.541, 0.443)),
(-93, ('[NPC][Abyssal][Firestorm T3 (Some T5 Rooms)]Overmind', 0.666, 0.413, 0.634, 0.646)),
(-94, ('[NPC][Abyssal][Firestorm T3 (Some T5 Rooms)]Seeker', 0.084, 0, 0.084, 0.084)),
(-95, ('[NPC][Abyssal][Firestorm T3 (Some T5 Rooms)]Triglavian', 0.537, 0.166, 0.489, 0.371)),
(-96, ('[NPC][Abyssal][Firestorm T3 (Some T5 Rooms)]Drifter', 0.43, 0.201, 0.43, 0.43)),
(-97, ('[NPC][Abyssal][Firestorm T3 (Some T5 Rooms)]Sleeper', 0.512, 0.337, 0.512, 0.512)),
(-98, ('[NPC][Abyssal][Firestorm T3 (Some T5 Rooms)]All', 0.537, 0.269, 0.512, 0.495)),
(-99, ('[NPC][Abyssal][Firestorm T4/T5/T6]Drones', 0.461, 0.305, 0.541, 0.443)),
(-100, ('[NPC][Abyssal][Firestorm T4/T5/T6]Overmind', 0.666, 0.345, 0.634, 0.646)),
(-101, ('[NPC][Abyssal][Firestorm T4/T5/T6]Seeker', 0.084, 0, 0.084, 0.084)),
(-102, ('[NPC][Abyssal][Firestorm T4/T5/T6]Triglavian', 0.537, 0.085, 0.489, 0.371)),
(-103, ('[NPC][Abyssal][Firestorm T4/T5/T6]Drifter', 0.43, 0.117, 0.43, 0.43)),
(-104, ('[NPC][Abyssal][Firestorm T4/T5/T6]Sleeper', 0.512, 0.276, 0.512, 0.512)),
(-105, ('[NPC][Abyssal][Firestorm T4/T5/T6]All', 0.537, 0.201, 0.512, 0.495)),
(-106, ('[NPC][Abyssal][Exotic T0/T1/T2]Drones', 0.439, 0.522, 0.417, 0.435)),
(-107, ('[NPC][Abyssal][Exotic T0/T1/T2]Overmind', 0.643, 0.593, 0.511, 0.639)),
(-108, ('[NPC][Abyssal][Exotic T0/T1/T2]Seeker', 0.082, 0.082, 0, 0.082)),
(-109, ('[NPC][Abyssal][Exotic T0/T1/T2]Triglavian', 0.494, 0.41, 0.304, 0.376)),
(-110, ('[NPC][Abyssal][Exotic T0/T1/T2]Drifter', 0.415, 0.415, 0.277, 0.415)),
(-111, ('[NPC][Abyssal][Exotic T0/T1/T2]Sleeper', 0.435, 0.435, 0.329, 0.435)),
(-112, ('[NPC][Abyssal][Exotic T0/T1/T2]All', 0.508, 0.474, 0.359, 0.488)),
(-113, ('[NPC][Abyssal][Exotic T3 (Some T5 Rooms)]Drones', 0.439, 0.522, 0.351, 0.435)),
(-114, ('[NPC][Abyssal][Exotic T3 (Some T5 Rooms)]Overmind', 0.643, 0.593, 0.435, 0.639)),
(-115, ('[NPC][Abyssal][Exotic T3 (Some T5 Rooms)]Seeker', 0.082, 0.082, 0, 0.082)),
(-116, ('[NPC][Abyssal][Exotic T3 (Some T5 Rooms)]Triglavian', 0.494, 0.41, 0.198, 0.376)),
(-117, ('[NPC][Abyssal][Exotic T3 (Some T5 Rooms)]Drifter', 0.415, 0.415, 0.191, 0.415)),
(-118, ('[NPC][Abyssal][Exotic T3 (Some T5 Rooms)]Sleeper', 0.435, 0.435, 0.268, 0.435)),
(-119, ('[NPC][Abyssal][Exotic T3 (Some T5 Rooms)]All', 0.508, 0.474, 0.276, 0.488)),
(-120, ('[NPC][Abyssal][Exotic T4/T5/T6]Drones', 0.439, 0.522, 0.293, 0.435)),
(-121, ('[NPC][Abyssal][Exotic T4/T5/T6]Overmind', 0.643, 0.593, 0.362, 0.639)),
(-122, ('[NPC][Abyssal][Exotic T4/T5/T6]Seeker', 0.082, 0.082, 0, 0.082)),
(-123, ('[NPC][Abyssal][Exotic T4/T5/T6]Triglavian', 0.494, 0.41, 0.122, 0.376)),
(-124, ('[NPC][Abyssal][Exotic T4/T5/T6]Drifter', 0.415, 0.415, 0.111, 0.415)),
(-125, ('[NPC][Abyssal][Exotic T4/T5/T6]Sleeper', 0.435, 0.435, 0.215, 0.435)),
(-126, ('[NPC][Abyssal][Exotic T4/T5/T6]All', 0.508, 0.474, 0.208, 0.488)),
(-127, ('[NPC][Abyssal][Gamma T0/T1/T2]Drones', 0.449, 0.54, 0.549, 0.336)),
(-128, ('[NPC][Abyssal][Gamma T0/T1/T2]Overmind', 0.619, 0.574, 0.612, 0.522)),
(-129, ('[NPC][Abyssal][Gamma T0/T1/T2]Seeker', 0.085, 0.085, 0.085, 0)),
(-130, ('[NPC][Abyssal][Gamma T0/T1/T2]Triglavian', 0.477, 0.4, 0.461, 0.202)),
(-131, ('[NPC][Abyssal][Gamma T0/T1/T2]Drifter', 0.437, 0.437, 0.437, 0.295)),
(-132, ('[NPC][Abyssal][Gamma T0/T1/T2]Sleeper', 0.435, 0.435, 0.435, 0.329)),
(-133, ('[NPC][Abyssal][Gamma T0/T1/T2]All', 0.493, 0.468, 0.492, 0.35)),
(-134, ('[NPC][Abyssal][Gamma T3 (Some T5 Rooms)]Drones', 0.449, 0.54, 0.549, 0.264)),
(-135, ('[NPC][Abyssal][Gamma T3 (Some T5 Rooms)]Overmind', 0.619, 0.574, 0.612, 0.449)),
(-136, ('[NPC][Abyssal][Gamma T3 (Some T5 Rooms)]Seeker', 0.085, 0.085, 0.085, 0)),
(-137, ('[NPC][Abyssal][Gamma T3 (Some T5 Rooms)]Triglavian', 0.477, 0.4, 0.461, 0.081)),
(-138, ('[NPC][Abyssal][Gamma T3 (Some T5 Rooms)]Drifter', 0.437, 0.437, 0.437, 0.206)),
(-139, ('[NPC][Abyssal][Gamma T3 (Some T5 Rooms)]Sleeper', 0.435, 0.435, 0.435, 0.268)),
(-140, ('[NPC][Abyssal][Gamma T3 (Some T5 Rooms)]All', 0.493, 0.468, 0.492, 0.264)),
(-141, ('[NPC][Abyssal][Gamma T4/T5/T6]Drones', 0.449, 0.54, 0.549, 0.197)),
(-142, ('[NPC][Abyssal][Gamma T4/T5/T6]Overmind', 0.619, 0.574, 0.612, 0.379)),
(-143, ('[NPC][Abyssal][Gamma T4/T5/T6]Seeker', 0.085, 0.085, 0.085, 0)),
(-144, ('[NPC][Abyssal][Gamma T4/T5/T6]Triglavian', 0.477, 0.4, 0.461, 0.034)),
(-145, ('[NPC][Abyssal][Gamma T4/T5/T6]Drifter', 0.437, 0.437, 0.437, 0.121)),
(-146, ('[NPC][Abyssal][Gamma T4/T5/T6]Sleeper', 0.435, 0.435, 0.435, 0.215)),
(-147, ('[NPC][Abyssal][Gamma T4/T5/T6]All', 0.493, 0.468, 0.492, 0.196)),
(-52, (_c(_t('NPC')) + _c(_t('Invasion')) + _t('Triglavian Entities'), 0.422, 0.367, 0.453, 0.411)),
(-53, (_c(_t('NPC')) + _c(_t('Invasion')) + _t('Amarr EDENCOM Entities'), 0.360, 0.310, 0.441, 0.602)),
(-54, (_c(_t('NPC')) + _c(_t('Invasion')) + _t('Caldari EDENCOM Entities'), 0.303, 0.610, 0.487, 0.401)),
(-55, (_c(_t('NPC')) + _c(_t('Invasion')) + _t('Gallente EDENCOM Entities'), 0.383, 0.414, 0.578, 0.513)),
(-56, (_c(_t('NPC')) + _c(_t('Invasion')) + _t('Minmatar EDENCOM Entities'), 0.620, 0.422, 0.355, 0.399)),
(-57, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Dark Matter All Tiers')) + _t('Drones'), 0.439, 0.522, 0.529, 0.435)),
(-58, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Dark Matter All Tiers')) + _t('Overmind'), 0.643, 0.593, 0.624, 0.639)),
(-59, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Dark Matter All Tiers')) + _t('Seeker'), 0.082, 0.082, 0.082, 0.082)),
(-60, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Dark Matter All Tiers')) + _t('Triglavian'), 0.494, 0.41, 0.464, 0.376)),
(-61, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Dark Matter All Tiers')) + _t('Drifter'), 0.415, 0.415, 0.415, 0.415)),
(-62, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Dark Matter All Tiers')) + _t('Sleeper'), 0.435, 0.435, 0.435, 0.435)),
(-63, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Dark Matter All Tiers')) + _t('All'), 0.508, 0.474, 0.495, 0.488)),
(-64, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Electrical T0/T1/T2')) + _t('Drones'), 0.323, 0.522, 0.529, 0.435)),
(-65, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Electrical T0/T1/T2')) + _t('Overmind'), 0.542, 0.593, 0.624, 0.639)),
(-66, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Electrical T0/T1/T2')) + _t('Seeker'), 0, 0.082, 0.082, 0.082)),
(-67, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Electrical T0/T1/T2')) + _t('Triglavian'), 0.356, 0.41, 0.464, 0.376)),
(-68, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Electrical T0/T1/T2')) + _t('Drifter'), 0.277, 0.415, 0.415, 0.415)),
(-69, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Electrical T0/T1/T2')) + _t('Sleeper'), 0.329, 0.435, 0.435, 0.435)),
(-70, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Electrical T0/T1/T2')) + _t('All'), 0.381, 0.474, 0.495, 0.488)),
(-71, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Electrical T3 (Some T5 Rooms)')) + _t('Drones'), 0.255, 0.522, 0.529, 0.435)),
(-72, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Electrical T3 (Some T5 Rooms)')) + _t('Overmind'), 0.48, 0.593, 0.624, 0.639)),
(-73, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Electrical T3 (Some T5 Rooms)')) + _t('Seeker'), 0, 0.082, 0.082, 0.0822)),
(-74, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Electrical T3 (Some T5 Rooms)')) + _t('Triglavian'), 0.268, 0.41, 0.464, 0.376)),
(-75, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Electrical T3 (Some T5 Rooms)')) + _t('Drifter'), 0.191, 0.415, 0.415, 0.415)),
(-76, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Electrical T3 (Some T5 Rooms)')) + _t('Sleeper'), 0.268, 0.435, 0.435, 0.435)),
(-77, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Electrical T3 (Some T5 Rooms)')) + _t('All'), 0.308, 0.474, 0.495, 0.488)),
(-78, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Electrical T4/T5/T6')) + _t('Drones'), 0.193, 0.522, 0.529, 0.435)),
(-79, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Electrical T4/T5/T6')) + _t('Overmind'), 0.423, 0.593, 0.624, 0.639)),
(-80, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Electrical T4/T5/T6')) + _t('Seeker'), 0, 0.082, 0.082, 0.082)),
(-81, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Electrical T4/T5/T6')) + _t('Triglavian'), 0.206, 0.41, 0.464, 0.376)),
(-82, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Electrical T4/T5/T6')) + _t('Drifter'), 0.111, 0.415, 0.415, 0.415)),
(-83, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Electrical T4/T5/T6')) + _t('Sleeper'), 0.215, 0.435, 0.435, 0.435)),
(-84, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Electrical T4/T5/T6')) + _t('All'), 0.247, 0.474, 0.495, 0.488)),
(-85, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Firestorm T0/T1/T2')) + _t('Drones'), 0.461, 0.425, 0.541, 0.443)),
(-86, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Firestorm T0/T1/T2')) + _t('Overmind'), 0.666, 0.489, 0.634, 0.646)),
(-87, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Firestorm T0/T1/T2')) + _t('Seeker'), 0.084, 0, 0.084, 0.084)),
(-88, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Firestorm T0/T1/T2')) + _t('Triglavian'), 0.537, 0.269, 0.489, 0.371)),
(-89, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Firestorm T0/T1/T2')) + _t('Drifter'), 0.43, 0.289, 0.43, 0.43)),
(-90, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Firestorm T0/T1/T2')) + _t('Sleeper'), 0.512, 0.402, 0.512, 0.512)),
(-91, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Firestorm T0/T1/T2')) + _t('All'), 0.537, 0.352, 0.512, 0.495)),
(-92, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Firestorm T3 (Some T5 Rooms)')) + _t('Drones'), 0.461, 0.36, 0.541, 0.443)),
(-93, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Firestorm T3 (Some T5 Rooms)')) + _t('Overmind'), 0.666, 0.413, 0.634, 0.646)),
(-94, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Firestorm T3 (Some T5 Rooms)')) + _t('Seeker'), 0.084, 0, 0.084, 0.084)),
(-95, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Firestorm T3 (Some T5 Rooms)')) + _t('Triglavian'), 0.537, 0.166, 0.489, 0.371)),
(-96, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Firestorm T3 (Some T5 Rooms)')) + _t('Drifter'), 0.43, 0.201, 0.43, 0.43)),
(-97, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Firestorm T3 (Some T5 Rooms)')) + _t('Sleeper'), 0.512, 0.337, 0.512, 0.512)),
(-98, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Firestorm T3 (Some T5 Rooms)')) + _t('All'), 0.537, 0.269, 0.512, 0.495)),
(-99, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Firestorm T4/T5/T6')) + _t('Drones'), 0.461, 0.305, 0.541, 0.443)),
(-100, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Firestorm T4/T5/T6')) + _t('Overmind'), 0.666, 0.345, 0.634, 0.646)),
(-101, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Firestorm T4/T5/T6')) + _t('Seeker'), 0.084, 0, 0.084, 0.084)),
(-102, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Firestorm T4/T5/T6')) + _t('Triglavian'), 0.537, 0.085, 0.489, 0.371)),
(-103, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Firestorm T4/T5/T6')) + _t('Drifter'), 0.43, 0.117, 0.43, 0.43)),
(-104, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Firestorm T4/T5/T6')) + _t('Sleeper'), 0.512, 0.276, 0.512, 0.512)),
(-105, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Firestorm T4/T5/T6')) + _t('All'), 0.537, 0.201, 0.512, 0.495)),
(-106, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Exotic T0/T1/T2')) + _t('Drones'), 0.439, 0.522, 0.417, 0.435)),
(-107, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Exotic T0/T1/T2')) + _t('Overmind'), 0.643, 0.593, 0.511, 0.639)),
(-108, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Exotic T0/T1/T2')) + _t('Seeker'), 0.082, 0.082, 0, 0.082)),
(-109, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Exotic T0/T1/T2')) + _t('Triglavian'), 0.494, 0.41, 0.304, 0.376)),
(-110, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Exotic T0/T1/T2')) + _t('Drifter'), 0.415, 0.415, 0.277, 0.415)),
(-111, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Exotic T0/T1/T2')) + _t('Sleeper'), 0.435, 0.435, 0.329, 0.435)),
(-112, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Exotic T0/T1/T2')) + _t('All'), 0.508, 0.474, 0.359, 0.488)),
(-113, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Exotic T3 (Some T5 Rooms)')) + _t('Drones'), 0.439, 0.522, 0.351, 0.435)),
(-114, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Exotic T3 (Some T5 Rooms)')) + _t('Overmind'), 0.643, 0.593, 0.435, 0.639)),
(-115, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Exotic T3 (Some T5 Rooms)')) + _t('Seeker'), 0.082, 0.082, 0, 0.082)),
(-116, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Exotic T3 (Some T5 Rooms)')) + _t('Triglavian'), 0.494, 0.41, 0.198, 0.376)),
(-117, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Exotic T3 (Some T5 Rooms)')) + _t('Drifter'), 0.415, 0.415, 0.191, 0.415)),
(-118, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Exotic T3 (Some T5 Rooms)')) + _t('Sleeper'), 0.435, 0.435, 0.268, 0.435)),
(-119, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Exotic T3 (Some T5 Rooms)')) + _t('All'), 0.508, 0.474, 0.276, 0.488)),
(-120, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Exotic T4/T5/T6')) + _t('Drones'), 0.439, 0.522, 0.293, 0.435)),
(-121, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Exotic T4/T5/T6')) + _t('Overmind'), 0.643, 0.593, 0.362, 0.639)),
(-122, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Exotic T4/T5/T6')) + _t('Seeker'), 0.082, 0.082, 0, 0.082)),
(-123, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Exotic T4/T5/T6')) + _t('Triglavian'), 0.494, 0.41, 0.122, 0.376)),
(-124, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Exotic T4/T5/T6')) + _t('Drifter'), 0.415, 0.415, 0.111, 0.415)),
(-125, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Exotic T4/T5/T6')) + _t('Sleeper'), 0.435, 0.435, 0.215, 0.435)),
(-126, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Exotic T4/T5/T6')) + _t('All'), 0.508, 0.474, 0.208, 0.488)),
(-127, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Gamma T0/T1/T2')) + _t('Drones'), 0.449, 0.54, 0.549, 0.336)),
(-128, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Gamma T0/T1/T2')) + _t('Overmind'), 0.619, 0.574, 0.612, 0.522)),
(-129, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Gamma T0/T1/T2')) + _t('Seeker'), 0.085, 0.085, 0.085, 0)),
(-130, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Gamma T0/T1/T2')) + _t('Triglavian'), 0.477, 0.4, 0.461, 0.202)),
(-131, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Gamma T0/T1/T2')) + _t('Drifter'), 0.437, 0.437, 0.437, 0.295)),
(-132, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Gamma T0/T1/T2')) + _t('Sleeper'), 0.435, 0.435, 0.435, 0.329)),
(-133, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Gamma T0/T1/T2')) + _t('All'), 0.493, 0.468, 0.492, 0.35)),
(-134, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Gamma T3 (Some T5 Rooms)')) + _t('Drones'), 0.449, 0.54, 0.549, 0.264)),
(-135, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Gamma T3 (Some T5 Rooms)')) + _t('Overmind'), 0.619, 0.574, 0.612, 0.449)),
(-136, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Gamma T3 (Some T5 Rooms)')) + _t('Seeker'), 0.085, 0.085, 0.085, 0)),
(-137, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Gamma T3 (Some T5 Rooms)')) + _t('Triglavian'), 0.477, 0.4, 0.461, 0.081)),
(-138, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Gamma T3 (Some T5 Rooms)')) + _t('Drifter'), 0.437, 0.437, 0.437, 0.206)),
(-139, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Gamma T3 (Some T5 Rooms)')) + _t('Sleeper'), 0.435, 0.435, 0.435, 0.268)),
(-140, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Gamma T3 (Some T5 Rooms)')) + _t('All'), 0.493, 0.468, 0.492, 0.264)),
(-141, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Gamma T4/T5/T6')) + _t('Drones'), 0.449, 0.54, 0.549, 0.197)),
(-142, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Gamma T4/T5/T6')) + _t('Overmind'), 0.619, 0.574, 0.612, 0.379)),
(-143, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Gamma T4/T5/T6')) + _t('Seeker'), 0.085, 0.085, 0.085, 0)),
(-144, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Gamma T4/T5/T6')) + _t('Triglavian'), 0.477, 0.4, 0.461, 0.034)),
(-145, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Gamma T4/T5/T6')) + _t('Drifter'), 0.437, 0.437, 0.437, 0.121)),
(-146, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Gamma T4/T5/T6')) + _t('Sleeper'), 0.435, 0.435, 0.435, 0.215)),
(-147, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Gamma T4/T5/T6')) + _t('All'), 0.493, 0.468, 0.492, 0.196)),
# Source: ticket #2265
(-148, ('[NPC][Abyssal][Dark Matter All Tiers]Concord', 0.324, 0.318, 0.369, 0.372)),
(-149, ('[NPC][Abyssal][Dark Matter All Tiers]Sansha', 0.137, 0.331, 0.332, 0.322)),
(-150, ('[NPC][Abyssal][Dark Matter All Tiers]Angel', 0.582, 0.508, 0.457, 0.416)),
(-151, ('[NPC][Abyssal][Electrical T0/T1/T2]Concord', 0.121, 0.318, 0.369, 0.372)),
(-152, ('[NPC][Abyssal][Electrical T0/T1/T2]Sansha', 0.034, 0.331, 0.332, 0.322)),
(-153, ('[NPC][Abyssal][Electrical T0/T1/T2]Angel', 0.456, 0.508, 0.457, 0.416)),
(-154, ('[NPC][Abyssal][Electrical T3 (Some T5 Rooms)]Concord', 0.025, 0.318, 0.369, 0.372)),
(-155, ('[NPC][Abyssal][Electrical T3 (Some T5 Rooms)]Sansha', 0.018, 0.331, 0.332, 0.322)),
(-156, ('[NPC][Abyssal][Electrical T3 (Some T5 Rooms)]Angel', 0.373, 0.508, 0.457, 0.416)),
(-157, ('[NPC][Abyssal][Electrical T4/T5/T6]Concord', 0.008, 0.318, 0.369, 0.372)),
(-158, ('[NPC][Abyssal][Electrical T4/T5/T6]Sansha', 0.009, 0.331, 0.332, 0.322)),
(-159, ('[NPC][Abyssal][Electrical T4/T5/T6]Angel', 0.3, 0.508, 0.457, 0.416)),
(-160, ('[NPC][Abyssal][Firestorm T0/T1/T2]Concord', 0.324, 0.107, 0.369, 0.372)),
(-161, ('[NPC][Abyssal][Firestorm T0/T1/T2]Sansha', 0.148, 0.181, 0.329, 0.328)),
(-162, ('[NPC][Abyssal][Firestorm T0/T1/T2]Angel', 0.587, 0.342, 0.439, 0.39)),
(-163, ('[NPC][Abyssal][Firestorm T3 (Some T5 Rooms)]Concord', 0.324, 0.016, 0.369, 0.372)),
(-164, ('[NPC][Abyssal][Firestorm T3 (Some T5 Rooms)]Sansha', 0.148, 0.14, 0.329, 0.328)),
(-165, ('[NPC][Abyssal][Firestorm T3 (Some T5 Rooms)]Angel', 0.587, 0.241, 0.439, 0.39)),
(-166, ('[NPC][Abyssal][Firestorm T4/T5/T6]Concord', 0.324, 0.004, 0.369, 0.372)),
(-167, ('[NPC][Abyssal][Firestorm T4/T5/T6]Sansha', 0.148, 0.106, 0.329, 0.328)),
(-168, ('[NPC][Abyssal][Firestorm T4/T5/T6]Angel', 0.587, 0.172, 0.439, 0.39)),
(-169, ('[NPC][Abyssal][Exotic T0/T1/T2]Concord', 0.324, 0.318, 0.18, 0.372)),
(-170, ('[NPC][Abyssal][Exotic T0/T1/T2]Sansha', 0.137, 0.331, 0.166, 0.322)),
(-171, ('[NPC][Abyssal][Exotic T0/T1/T2]Angel', 0.582, 0.508, 0.295, 0.416)),
(-172, ('[NPC][Abyssal][Exotic T3 (Some T5 Rooms)]Concord', 0.324, 0.318, 0.089, 0.372)),
(-173, ('[NPC][Abyssal][Exotic T3 (Some T5 Rooms)]Sansha', 0.137, 0.331, 0.108, 0.322)),
(-174, ('[NPC][Abyssal][Exotic T3 (Some T5 Rooms)]Angel', 0.582, 0.508, 0.203, 0.416)),
(-175, ('[NPC][Abyssal][Exotic T4/T5/T6]Concord', 0.324, 0.318, 0.068, 0.372)),
(-176, ('[NPC][Abyssal][Exotic T4/T5/T6]Sansha', 0.137, 0.331, 0.073, 0.322)),
(-177, ('[NPC][Abyssal][Exotic T4/T5/T6]Angel', 0.582, 0.508, 0.14, 0.416)),
(-178, ('[NPC][Abyssal][Gamma T0/T1/T2]Concord', 0.324, 0.318, 0.369, 0.203)),
(-179, ('[NPC][Abyssal][Gamma T0/T1/T2]Sansha', 0.137, 0.355, 0.352, 0.16)),
(-180, ('[NPC][Abyssal][Gamma T0/T1/T2]Angel', 0.59, 0.528, 0.477, 0.286)),
(-181, ('[NPC][Abyssal][Gamma T3 (Some T5 Rooms)]Concord', 0.324, 0.318, 0.369, 0.112)),
(-182, ('[NPC][Abyssal][Gamma T3 (Some T5 Rooms)]Sansha', 0.137, 0.355, 0.352, 0.05)),
(-183, ('[NPC][Abyssal][Gamma T3 (Some T5 Rooms)]Angel', 0.59, 0.528, 0.477, 0.197)),
(-184, ('[NPC][Abyssal][Gamma T4/T5/T6]Concord', 0.324, 0.318, 0.369, 0.086)),
(-185, ('[NPC][Abyssal][Gamma T4/T5/T6]Sansha', 0.137, 0.355, 0.352, 0)),
(-186, ('[NPC][Abyssal][Gamma T4/T5/T6]Angel', 0.59, 0.528, 0.477, 0.126))])
(-148, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Dark Matter All Tiers')) + _t('Concord'), 0.324, 0.318, 0.369, 0.372)),
(-149, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Dark Matter All Tiers')) + _t('Sansha'), 0.137, 0.331, 0.332, 0.322)),
(-150, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Dark Matter All Tiers')) + _t('Angel'), 0.582, 0.508, 0.457, 0.416)),
(-151, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Electrical T0/T1/T2')) + _t('Concord'), 0.121, 0.318, 0.369, 0.372)),
(-152, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Electrical T0/T1/T2')) + _t('Sansha'), 0.034, 0.331, 0.332, 0.322)),
(-153, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Electrical T0/T1/T2')) + _t('Angel'), 0.456, 0.508, 0.457, 0.416)),
(-154, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Electrical T3 (Some T5 Rooms)')) + _t('Concord'), 0.025, 0.318, 0.369, 0.372)),
(-155, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Electrical T3 (Some T5 Rooms)')) + _t('Sansha'), 0.018, 0.331, 0.332, 0.322)),
(-156, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Electrical T3 (Some T5 Rooms)')) + _t('Angel'), 0.373, 0.508, 0.457, 0.416)),
(-157, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Electrical T4/T5/T6')) + _t('Concord'), 0.008, 0.318, 0.369, 0.372)),
(-158, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Electrical T4/T5/T6')) + _t('Sansha'), 0.009, 0.331, 0.332, 0.322)),
(-159, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Electrical T4/T5/T6')) + _t('Angel'), 0.3, 0.508, 0.457, 0.416)),
(-160, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Firestorm T0/T1/T2')) + _t('Concord'), 0.324, 0.107, 0.369, 0.372)),
(-161, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Firestorm T0/T1/T2')) + _t('Sansha'), 0.148, 0.181, 0.329, 0.328)),
(-162, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Firestorm T0/T1/T2')) + _t('Angel'), 0.587, 0.342, 0.439, 0.39)),
(-163, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Firestorm T3 (Some T5 Rooms)')) + _t('Concord'), 0.324, 0.016, 0.369, 0.372)),
(-164, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Firestorm T3 (Some T5 Rooms)')) + _t('Sansha'), 0.148, 0.14, 0.329, 0.328)),
(-165, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Firestorm T3 (Some T5 Rooms)')) + _t('Angel'), 0.587, 0.241, 0.439, 0.39)),
(-166, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Firestorm T4/T5/T6')) + _t('Concord'), 0.324, 0.004, 0.369, 0.372)),
(-167, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Firestorm T4/T5/T6')) + _t('Sansha'), 0.148, 0.106, 0.329, 0.328)),
(-168, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Firestorm T4/T5/T6')) + _t('Angel'), 0.587, 0.172, 0.439, 0.39)),
(-169, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Exotic T0/T1/T2')) + _t('Concord'), 0.324, 0.318, 0.18, 0.372)),
(-170, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Exotic T0/T1/T2')) + _t('Sansha'), 0.137, 0.331, 0.166, 0.322)),
(-171, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Exotic T0/T1/T2')) + _t('Angel'), 0.582, 0.508, 0.295, 0.416)),
(-172, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Exotic T3 (Some T5 Rooms)')) + _t('Concord'), 0.324, 0.318, 0.089, 0.372)),
(-173, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Exotic T3 (Some T5 Rooms)')) + _t('Sansha'), 0.137, 0.331, 0.108, 0.322)),
(-174, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Exotic T3 (Some T5 Rooms)')) + _t('Angel'), 0.582, 0.508, 0.203, 0.416)),
(-175, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Exotic T4/T5/T6')) + _t('Concord'), 0.324, 0.318, 0.068, 0.372)),
(-176, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Exotic T4/T5/T6')) + _t('Sansha'), 0.137, 0.331, 0.073, 0.322)),
(-177, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Exotic T4/T5/T6')) + _t('Angel'), 0.582, 0.508, 0.14, 0.416)),
(-178, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Gamma T0/T1/T2')) + _t('Concord'), 0.324, 0.318, 0.369, 0.203)),
(-179, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Gamma T0/T1/T2')) + _t('Sansha'), 0.137, 0.355, 0.352, 0.16)),
(-180, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Gamma T0/T1/T2')) + _t('Angel'), 0.59, 0.528, 0.477, 0.286)),
(-181, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Gamma T3 (Some T5 Rooms)')) + _t('Concord'), 0.324, 0.318, 0.369, 0.112)),
(-182, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Gamma T3 (Some T5 Rooms)')) + _t('Sansha'), 0.137, 0.355, 0.352, 0.05)),
(-183, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Gamma T3 (Some T5 Rooms)')) + _t('Angel'), 0.59, 0.528, 0.477, 0.197)),
(-184, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Gamma T4/T5/T6')) + _t('Concord'), 0.324, 0.318, 0.369, 0.086)),
(-185, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Gamma T4/T5/T6')) + _t('Sansha'), 0.137, 0.355, 0.352, 0)),
(-186, (_c(_t('NPC')) + _c(_t('Abyssal')) + _c(_t('Gamma T4/T5/T6')) + _t('Angel'), 0.59, 0.528, 0.477, 0.126))])
class TargetProfile:
# also determined import/export order - VERY IMPORTANT
DAMAGE_TYPES = ('em', 'thermal', 'kinetic', 'explosive')
_idealTarget = None
@@ -274,14 +280,14 @@ class TargetProfile:
def getIdeal(cls):
if cls._idealTarget is None:
cls._idealTarget = cls(
emAmount=0,
thermalAmount=0,
kineticAmount=0,
explosiveAmount=0,
maxVelocity=0,
signatureRadius=None,
radius=0)
cls._idealTarget.rawName = 'Ideal Target'
emAmount=0,
thermalAmount=0,
kineticAmount=0,
explosiveAmount=0,
maxVelocity=0,
signatureRadius=None,
radius=0)
cls._idealTarget.rawName = _t('Ideal Target')
cls._idealTarget.ID = 0
cls._idealTarget.builtin = True
return cls._idealTarget
@@ -439,7 +445,7 @@ class TargetProfile:
def __deepcopy__(self, memo):
p = TargetProfile(
self.emAmount, self.thermalAmount, self.kineticAmount, self.explosiveAmount,
self._maxVelocity, self._signatureRadius, self._radius)
self.emAmount, self.thermalAmount, self.kineticAmount, self.explosiveAmount,
self._maxVelocity, self._signatureRadius, self._radius)
p.rawName = "%s copy" % self.rawName
return p

View File

@@ -22,6 +22,10 @@ from eos.utils.float import floatUnerr
from utils.repr import makeReprStr
def _t(x):
return x
class DmgTypes:
"""Container for damage data stats."""
@@ -116,7 +120,7 @@ class DmgTypes:
@staticmethod
def names(short=None, postProcessor=None):
value = ['em', 'th', 'kin', 'exp'] if short else ['em', 'thermal', 'kinetic', 'explosive']
value = [_t('em'), _t('th'), _t('kin'), _t('exp')] if short else [_t('em'), _t('thermal'), _t('kinetic'), _t('explosive')]
if postProcessor:
value = [postProcessor(x) for x in value]

View File

@@ -18,31 +18,34 @@
# =============================================================================
from graphs.data.base import FitGraph, XDef, YDef, Input, InputCheckbox
import wx
from graphs.data.base import FitGraph, Input, InputCheckbox, XDef, YDef
from .getter import CapAmount2CapAmountGetter, CapAmount2CapRegenGetter, Time2CapAmountGetter, Time2CapRegenGetter
_t = wx.GetTranslation
class FitCapacitorGraph(FitGraph):
# UI stuff
internalName = 'capacitorGraph'
name = 'Capacitor'
name = _t('Capacitor')
xDefs = [
XDef(handle='time', unit='s', label='Time', mainInput=('time', 's')),
XDef(handle='capAmount', unit='GJ', label='Cap amount', mainInput=('capAmount', '%')),
XDef(handle='capAmount', unit='%', label='Cap amount', mainInput=('capAmount', '%'))]
XDef(handle='time', unit='s', label=_t('Time'), mainInput=('time', 's')),
XDef(handle='capAmount', unit='GJ', label=_t('Cap amount'), mainInput=('capAmount', '%')),
XDef(handle='capAmount', unit='%', label=_t('Cap amount'), mainInput=('capAmount', '%'))]
yDefs = [
YDef(handle='capAmount', unit='GJ', label='Cap amount'),
YDef(handle='capRegen', unit='GJ/s', label='Cap regen')]
YDef(handle='capAmount', unit='GJ', label=_t('Cap amount')),
YDef(handle='capRegen', unit='GJ/s', label=_t('Cap regen'))]
inputs = [
Input(handle='time', unit='s', label='Time', iconID=1392, defaultValue=120, defaultRange=(0, 300), conditions=[
Input(handle='time', unit='s', label=_t('Time'), iconID=1392, defaultValue=120, defaultRange=(0, 300), conditions=[
(('time', 's'), None)]),
Input(handle='capAmount', unit='%', label='Cap amount', iconID=1668, defaultValue=25, defaultRange=(0, 100), conditions=[
Input(handle='capAmount', unit='%', label=_t('Cap amount'), iconID=1668, defaultValue=25, defaultRange=(0, 100), conditions=[
(('capAmount', 'GJ'), None),
(('capAmount', '%'), None)]),
Input(handle='capAmountT0', unit='%', label='Starting cap amount', iconID=1668, defaultValue=100, defaultRange=(0, 100), conditions=[
Input(handle='capAmountT0', unit='%', label=_t('Starting cap amount'), iconID=1668, defaultValue=100, defaultRange=(0, 100), conditions=[
(('time', 's'), None)])]
checkboxes = [InputCheckbox(handle='useCapsim', label='Use capacitor simulator', defaultValue=True, conditions=[
checkboxes = [InputCheckbox(handle='useCapsim', label=_t('Use capacitor simulator'), defaultValue=True, conditions=[
(('time', 's'), ('capAmount', 'GJ'))])]
srcExtraCols = ('CapAmount', 'CapTime')

View File

@@ -18,15 +18,17 @@
# =============================================================================
from graphs.data.base import FitGraph, XDef, YDef, Input, VectorDef
import wx
from graphs.data.base import FitGraph, Input, VectorDef, XDef, YDef
from service.const import GraphCacheCleanupReason
from service.settings import GraphSettings
from .cache import ProjectedDataCache, TimeCache
from .getter import (
Distance2DpsGetter, Distance2VolleyGetter, Distance2InflictedDamageGetter,
Time2DpsGetter, Time2VolleyGetter, Time2InflictedDamageGetter,
TgtSpeed2DpsGetter, TgtSpeed2VolleyGetter, TgtSpeed2InflictedDamageGetter,
TgtSigRadius2DpsGetter, TgtSigRadius2VolleyGetter, TgtSigRadius2InflictedDamageGetter)
from .getter import (Distance2DpsGetter, Distance2InflictedDamageGetter, Distance2VolleyGetter, TgtSigRadius2DpsGetter, TgtSigRadius2InflictedDamageGetter,
TgtSigRadius2VolleyGetter, TgtSpeed2DpsGetter, TgtSpeed2InflictedDamageGetter, TgtSpeed2VolleyGetter, Time2DpsGetter,
Time2InflictedDamageGetter, Time2VolleyGetter)
_t = wx.GetTranslation
class FitDamageStatsGraph(FitGraph):
@@ -51,23 +53,26 @@ class FitDamageStatsGraph(FitGraph):
# UI stuff
internalName = 'dmgStatsGraph'
name = 'Damage Stats'
name = _t('Damage Stats')
xDefs = [
XDef(handle='distance', unit='km', label='Distance', mainInput=('distance', 'km')),
XDef(handle='time', unit='s', label='Time', mainInput=('time', 's')),
XDef(handle='tgtSpeed', unit='m/s', label='Target speed', mainInput=('tgtSpeed', '%')),
XDef(handle='tgtSpeed', unit='%', label='Target speed', mainInput=('tgtSpeed', '%')),
XDef(handle='tgtSigRad', unit='m', label='Target signature radius', mainInput=('tgtSigRad', '%')),
XDef(handle='tgtSigRad', unit='%', label='Target signature radius', mainInput=('tgtSigRad', '%'))]
XDef(handle='distance', unit='km', label=_t('Distance'), mainInput=('distance', 'km')),
XDef(handle='time', unit='s', label=_t('Time'), mainInput=('time', 's')),
XDef(handle='tgtSpeed', unit='m/s', label=_t('Target speed'), mainInput=('tgtSpeed', '%')),
XDef(handle='tgtSpeed', unit='%', label=_t('Target speed'), mainInput=('tgtSpeed', '%')),
XDef(handle='tgtSigRad', unit='m', label=_t('Target signature radius'), mainInput=('tgtSigRad', '%')),
XDef(handle='tgtSigRad', unit='%', label=_t('Target signature radius'), mainInput=('tgtSigRad', '%'))]
inputs = [
Input(handle='distance', unit='km', label='Distance', iconID=1391, defaultValue=None, defaultRange=(0, 100), mainTooltip='Distance between the attacker and the target, as seen in overview (surface-to-surface)', secondaryTooltip='Distance between the attacker and the target, as seen in overview (surface-to-surface)\nWhen set, places the target that far away from the attacker\nWhen not set, attacker\'s weapons always hit the target'),
Input(handle='time', unit='s', label='Time', iconID=1392, defaultValue=None, defaultRange=(0, 80), secondaryTooltip='When set, uses attacker\'s exact damage stats at a given time\nWhen not set, uses attacker\'s damage stats as shown in stats panel of main window'),
Input(handle='tgtSpeed', unit='%', label='Target speed', iconID=1389, defaultValue=100, defaultRange=(0, 100)),
Input(handle='tgtSigRad', unit='%', label='Target signature', iconID=1390, defaultValue=100, defaultRange=(100, 200), conditions=[
Input(handle='distance', unit='km', label=_t('Distance'), iconID=1391, defaultValue=None, defaultRange=(0, 100),
mainTooltip=_t('Distance between the attacker and the target, as seen in overview (surface-to-surface)'),
secondaryTooltip=_t('Distance between the attacker and the target, as seen in overview (surface-to-surface)\nWhen set, places the target that far away from the attacker\nWhen not set, attacker\'s weapons always hit the target')),
Input(handle='time', unit='s', label=_t('Time'), iconID=1392, defaultValue=None, defaultRange=(0, 80),
secondaryTooltip=_t('When set, uses attacker\'s exact damage stats at a given time\nWhen not set, uses attacker\'s damage stats as shown in stats panel of main window')),
Input(handle='tgtSpeed', unit='%', label=_t('Target speed'), iconID=1389, defaultValue=100, defaultRange=(0, 100)),
Input(handle='tgtSigRad', unit='%', label=_t('Target signature'), iconID=1390, defaultValue=100, defaultRange=(100, 200), conditions=[
(('tgtSigRad', 'm'), None),
(('tgtSigRad', '%'), None)])]
srcVectorDef = VectorDef(lengthHandle='atkSpeed', lengthUnit='%', angleHandle='atkAngle', angleUnit='degrees', label='Attacker')
tgtVectorDef = VectorDef(lengthHandle='tgtSpeed', lengthUnit='%', angleHandle='tgtAngle', angleUnit='degrees', label='Target')
srcVectorDef = VectorDef(lengthHandle='atkSpeed', lengthUnit='%', angleHandle='atkAngle', angleUnit='degrees', label=_t('Attacker'))
tgtVectorDef = VectorDef(lengthHandle='tgtSpeed', lengthUnit='%', angleHandle='tgtAngle', angleUnit='degrees', label=_t('Target'))
hasTargets = True
srcExtraCols = ('Dps', 'Volley', 'Speed', 'Radius')
@@ -75,9 +80,9 @@ class FitDamageStatsGraph(FitGraph):
def yDefs(self):
ignoreResists = GraphSettings.getInstance().get('ignoreResists')
return [
YDef(handle='dps', unit=None, label='DPS' if ignoreResists else 'Effective DPS'),
YDef(handle='volley', unit=None, label='Volley' if ignoreResists else 'Effective volley'),
YDef(handle='damage', unit=None, label='Damage inflicted' if ignoreResists else 'Effective damage inflicted')]
YDef(handle='dps', unit=None, label=_t('DPS') if ignoreResists else _t('Effective DPS')),
YDef(handle='volley', unit=None, label=_t('Volley') if ignoreResists else _t('Effective volley')),
YDef(handle='damage', unit=None, label=_t('Damage inflicted') if ignoreResists else _t('Effective damage inflicted'))]
@property
def tgtExtraCols(self):

View File

@@ -18,30 +18,31 @@
# =============================================================================
import wx
from graphs.data.base import FitGraph, Input, XDef, YDef
from .getter import (
Distance2NeutingStrGetter, Distance2WebbingStrGetter, Distance2EcmStrMaxGetter,
Distance2DampStrLockRangeGetter, Distance2TdStrOptimalGetter, Distance2GdStrRangeGetter,
Distance2TpStrGetter)
from .getter import (Distance2DampStrLockRangeGetter, Distance2EcmStrMaxGetter, Distance2GdStrRangeGetter, Distance2NeutingStrGetter, Distance2TdStrOptimalGetter,
Distance2TpStrGetter, Distance2WebbingStrGetter)
_t = wx.GetTranslation
class FitEwarStatsGraph(FitGraph):
# UI stuff
internalName = 'ewarStatsGraph'
name = 'Electronic Warfare Stats'
xDefs = [XDef(handle='distance', unit='km', label='Distance', mainInput=('distance', 'km'))]
name = _t('Electronic Warfare Stats')
xDefs = [XDef(handle='distance', unit='km', label=_t('Distance'), mainInput=('distance', 'km'))]
yDefs = [
YDef(handle='neutStr', unit=None, label='Cap neutralized per second', selectorLabel='Neuts: cap per second'),
YDef(handle='webStr', unit='%', label='Speed reduction', selectorLabel='Webs: speed reduction'),
YDef(handle='ecmStrMax', unit=None, label='Combined ECM strength', selectorLabel='ECM: combined strength'),
YDef(handle='dampStrLockRange', unit='%', label='Lock range reduction', selectorLabel='Damps: lock range reduction'),
YDef(handle='tdStrOptimal', unit='%', label='Turret optimal range reduction', selectorLabel='TDs: turret optimal range reduction'),
YDef(handle='gdStrRange', unit='%', label='Missile flight range reduction', selectorLabel='GDs: missile flight range reduction'),
YDef(handle='tpStr', unit='%', label='Signature radius increase', selectorLabel='TPs: signature radius increase')]
YDef(handle='neutStr', unit=None, label=_t('Cap neutralized per second'), selectorLabel=_t('Neuts: cap per second')),
YDef(handle='webStr', unit='%', label=_t('Speed reduction'), selectorLabel=_t('Webs: speed reduction')),
YDef(handle='ecmStrMax', unit=None, label=_t('Combined ECM strength'), selectorLabel=_t('ECM: combined strength')),
YDef(handle='dampStrLockRange', unit='%', label=_t('Lock range reduction'), selectorLabel=_t('Damps: lock range reduction')),
YDef(handle='tdStrOptimal', unit='%', label=_t('Turret optimal range reduction'), selectorLabel=_t('TDs: turret optimal range reduction')),
YDef(handle='gdStrRange', unit='%', label=_t('Missile flight range reduction'), selectorLabel=_t('GDs: missile flight range reduction')),
YDef(handle='tpStr', unit='%', label=_t('Signature radius increase'), selectorLabel=_t('TPs: signature radius increase'))]
inputs = [
Input(handle='distance', unit='km', label='Distance', iconID=1391, defaultValue=None, defaultRange=(0, 100)),
Input(handle='resist', unit='%', label='Target resistance', iconID=1393, defaultValue=0, defaultRange=(0, 100))]
Input(handle='distance', unit='km', label=_t('Distance'), iconID=1391, defaultValue=None, defaultRange=(0, 100)),
Input(handle='resist', unit='%', label=_t('Target resistance'), iconID=1393, defaultValue=0, defaultRange=(0, 100))]
# Calculation stuff
_normalizers = {

View File

@@ -20,18 +20,21 @@
import math
from graphs.data.base import FitGraph, XDef, YDef, Input
import wx
from graphs.data.base import FitGraph, Input, XDef, YDef
from .getter import TgtSigRadius2LockTimeGetter
_t = wx.GetTranslation
class FitLockTimeGraph(FitGraph):
# UI stuff
internalName = 'lockTimeGraph'
name = 'Lock Time'
xDefs = [XDef(handle='tgtSigRad', unit='m', label='Target signature radius', mainInput=('tgtSigRad', 'm'))]
yDefs = [YDef(handle='time', unit='s', label='Lock time')]
inputs = [Input(handle='tgtSigRad', unit='m', label='Target signature', iconID=1390, defaultValue=None, defaultRange=(25, 500))]
name = _t('Lock Time')
xDefs = [XDef(handle='tgtSigRad', unit='m', label=_t('Target signature radius'), mainInput=('tgtSigRad', 'm'))]
yDefs = [YDef(handle='time', unit='s', label=_t('Lock time'))]
inputs = [Input(handle='tgtSigRad', unit='m', label=_t('Target signature'), iconID=1390, defaultValue=None, defaultRange=(25, 500))]
srcExtraCols = ('ScanResolution',)
# Calculation stuff

View File

@@ -18,27 +18,32 @@
# =============================================================================
from graphs.data.base import FitGraph, XDef, YDef, Input
from .getter import Time2SpeedGetter, Time2DistanceGetter, Time2MomentumGetter, Time2BumpSpeedGetter, Time2BumpDistanceGetter
import wx
from graphs.data.base import FitGraph, Input, XDef, YDef
from .getter import Time2BumpDistanceGetter, Time2BumpSpeedGetter, Time2DistanceGetter, Time2MomentumGetter, Time2SpeedGetter
_t = wx.GetTranslation
class FitMobilityGraph(FitGraph):
# UI stuff
internalName = 'mobilityGraph'
name = 'Mobility'
xDefs = [XDef(handle='time', unit='s', label='Time', mainInput=('time', 's'))]
name = _t('Mobility')
xDefs = [XDef(handle='time', unit='s', label=_t('Time'), mainInput=('time', 's'))]
yDefs = [
YDef(handle='speed', unit='m/s', label='Speed'),
YDef(handle='distance', unit='km', label='Distance'),
YDef(handle='momentum', unit='Gkg⋅m/s', label='Momentum'),
YDef(handle='bumpSpeed', unit='m/s', label='Target speed', selectorLabel='Bump speed'),
YDef(handle='bumpDistance', unit='km', label='Target distance traveled', selectorLabel='Bump distance')]
YDef(handle='speed', unit='m/s', label=_t('Speed')),
YDef(handle='distance', unit='km', label=_t('Distance')),
YDef(handle='momentum', unit='Gkg⋅m/s', label=_t('Momentum')),
YDef(handle='bumpSpeed', unit='m/s', label=_t('Target speed'), selectorLabel=_t('Bump speed')),
YDef(handle='bumpDistance', unit='km', label=_t('Target distance traveled'), selectorLabel=_t('Bump distance'))]
inputs = [
Input(handle='time', unit='s', label='Time', iconID=1392, defaultValue=10, defaultRange=(0, 30)),
Input(handle='time', unit='s', label=_t('Time'), iconID=1392, defaultValue=10, defaultRange=(0, 30)),
# Default values in target fields correspond to a random carrier/fax
Input(handle='tgtMass', unit='Mkg', label='Target mass', iconID=76, defaultValue=1300, defaultRange=(100, 2500), conditions=[(None, ('bumpSpeed', 'm/s')), (None, ('bumpDistance', 'km'))], secondaryTooltip='Defined in millions of kilograms'),
Input(handle='tgtInertia', unit=None, label='Target inertia factor', iconID=1401, defaultValue=0.015, defaultRange=(0.03, 0.1), conditions=[(None, ('bumpDistance', 'km'))], secondaryTooltip='Inertia Modifier attribute value of the target ship')]
Input(handle='tgtMass', unit='Mkg', label=_t('Target mass'), iconID=76, defaultValue=1300, defaultRange=(100, 2500),
conditions=[(None, ('bumpSpeed', 'm/s')), (None, ('bumpDistance', 'km'))], secondaryTooltip=_t('Defined in millions of kilograms')),
Input(handle='tgtInertia', unit=None, label=_t('Target inertia factor'), iconID=1401, defaultValue=0.015, defaultRange=(0.03, 0.1),
conditions=[(None, ('bumpDistance', 'km'))], secondaryTooltip=_t('Inertia Modifier attribute value of the target ship'))]
srcExtraCols = ('Speed', 'Agility')
# Calculation stuff

View File

@@ -18,10 +18,14 @@
# =============================================================================
from graphs.data.base import FitGraph, XDef, YDef, Input, InputCheckbox
import wx
from graphs.data.base import FitGraph, Input, InputCheckbox, XDef, YDef
from service.const import GraphCacheCleanupReason
from .cache import TimeCache
from .getter import Distance2RpsGetter, Distance2RepAmountGetter, Time2RpsGetter, Time2RepAmountGetter
from .getter import Distance2RepAmountGetter, Distance2RpsGetter, Time2RepAmountGetter, Time2RpsGetter
_t = wx.GetTranslation
class FitRemoteRepsGraph(FitGraph):
@@ -41,18 +45,21 @@ class FitRemoteRepsGraph(FitGraph):
# UI stuff
internalName = 'remoteRepsGraph'
name = 'Remote Repairs'
name = _t('Remote Repairs')
xDefs = [
XDef(handle='distance', unit='km', label='Distance', mainInput=('distance', 'km')),
XDef(handle='time', unit='s', label='Time', mainInput=('time', 's'))]
XDef(handle='distance', unit='km', label=_t('Distance'), mainInput=('distance', 'km')),
XDef(handle='time', unit='s', label=_t('Time'), mainInput=('time', 's'))]
yDefs = [
YDef(handle='rps', unit='HP/s', label='Repair speed'),
YDef(handle='total', unit='HP', label='Total repaired')]
YDef(handle='rps', unit='HP/s', label=_t('Repair speed')),
YDef(handle='total', unit='HP', label=_t('Total repaired'))]
inputs = [
Input(handle='time', unit='s', label='Time', iconID=1392, defaultValue=None, defaultRange=(0, 80), secondaryTooltip='When set, uses repairing ship\'s exact RR stats at a given time\nWhen not set, uses repairing ship\'s RR stats as shown in stats panel of main window'),
Input(handle='distance', unit='km', label='Distance', iconID=1391, defaultValue=None, defaultRange=(0, 100), mainTooltip='Distance between the repairing ship and the target, as seen in overview (surface-to-surface)', secondaryTooltip='Distance between the repairing ship and the target, as seen in overview (surface-to-surface)')]
Input(handle='time', unit='s', label=_t('Time'), iconID=1392, defaultValue=None, defaultRange=(0, 80),
secondaryTooltip=_t('When set, uses repairing ship\'s exact RR stats at a given time\nWhen not set, uses repairing ship\'s RR stats as shown in stats panel of main window')),
Input(handle='distance', unit='km', label=_t('Distance'), iconID=1391, defaultValue=None, defaultRange=(0, 100),
mainTooltip=_t('Distance between the repairing ship and the target, as seen in overview (surface-to-surface)'),
secondaryTooltip=_t('Distance between the repairing ship and the target, as seen in overview (surface-to-surface)'))]
srcExtraCols = ('ShieldRR', 'ArmorRR', 'HullRR')
checkboxes = [InputCheckbox(handle='ancReload', label='Reload ancillary RRs', defaultValue=True)]
checkboxes = [InputCheckbox(handle='ancReload', label=_t('Reload ancillary RRs'), defaultValue=True)]
# Calculation stuff
_normalizers = {('distance', 'km'): lambda v, src, tgt: None if v is None else v * 1000}

View File

@@ -18,11 +18,13 @@
# =============================================================================
import wx
import gui.mainFrame
from graphs.data.base import FitGraph, XDef, YDef, Input
from .getter import (
Time2ShieldAmountGetter, Time2ShieldRegenGetter,
ShieldAmount2ShieldAmountGetter, ShieldAmount2ShieldRegenGetter)
from graphs.data.base import FitGraph, Input, XDef, YDef
from .getter import (ShieldAmount2ShieldAmountGetter, ShieldAmount2ShieldRegenGetter, Time2ShieldAmountGetter, Time2ShieldRegenGetter)
_t = wx.GetTranslation
class FitShieldRegenGraph(FitGraph):
@@ -33,15 +35,15 @@ class FitShieldRegenGraph(FitGraph):
# UI stuff
internalName = 'shieldRegenGraph'
name = 'Shield Regeneration'
name = _t('Shield Regeneration')
inputs = [
Input(handle='time', unit='s', label='Time', iconID=1392, defaultValue=120, defaultRange=(0, 300), conditions=[
Input(handle='time', unit='s', label=_t('Time'), iconID=1392, defaultValue=120, defaultRange=(0, 300), conditions=[
(('time', 's'), None)]),
Input(handle='shieldAmount', unit='%', label='Shield amount', iconID=1384, defaultValue=25, defaultRange=(0, 100), conditions=[
Input(handle='shieldAmount', unit='%', label=_t('Shield amount'), iconID=1384, defaultValue=25, defaultRange=(0, 100), conditions=[
(('shieldAmount', 'EHP'), None),
(('shieldAmount', 'HP'), None),
(('shieldAmount', '%'), None)]),
Input(handle='shieldAmountT0', unit='%', label='Starting shield amount', iconID=1384, defaultValue=0, defaultRange=(0, 100), conditions=[
Input(handle='shieldAmountT0', unit='%', label=_t('Starting shield amount'), iconID=1384, defaultValue=0, defaultRange=(0, 100), conditions=[
(('time', 's'), None)])]
srcExtraCols = ('ShieldAmount', 'ShieldTime')
usesHpEffectivity = True
@@ -49,15 +51,15 @@ class FitShieldRegenGraph(FitGraph):
@property
def xDefs(self):
return [
XDef(handle='time', unit='s', label='Time', mainInput=('time', 's')),
XDef(handle='shieldAmount', unit='EHP' if self.isEffective else 'HP', label='Shield amount', mainInput=('shieldAmount', '%')),
XDef(handle='shieldAmount', unit='%', label='Shield amount', mainInput=('shieldAmount', '%'))]
XDef(handle='time', unit='s', label=_t('Time'), mainInput=('time', 's')),
XDef(handle='shieldAmount', unit='EHP' if self.isEffective else 'HP', label=_t('Shield amount'), mainInput=('shieldAmount', '%')),
XDef(handle='shieldAmount', unit='%', label=_t('Shield amount'), mainInput=('shieldAmount', '%'))]
@property
def yDefs(self):
return [
YDef(handle='shieldAmount', unit='EHP' if self.isEffective else 'HP', label='Shield amount'),
YDef(handle='shieldRegen', unit='EHP/s' if self.isEffective else 'HP/s', label='Shield regen')]
YDef(handle='shieldAmount', unit='EHP' if self.isEffective else 'HP', label=_t('Shield amount')),
YDef(handle='shieldRegen', unit='EHP/s' if self.isEffective else 'HP/s', label=_t('Shield regen'))]
# Calculation stuff
_normalizers = {

View File

@@ -18,11 +18,15 @@
# =============================================================================
import wx
from graphs.data.base import FitGraph, Input, XDef, YDef
from service.const import GraphCacheCleanupReason
from .cache import SubwarpSpeedCache
from .getter import AU_METERS, Distance2TimeGetter
_t = wx.GetTranslation
class FitWarpTimeGraph(FitGraph):
@@ -38,20 +42,21 @@ class FitWarpTimeGraph(FitGraph):
# UI stuff
internalName = 'warpTimeGraph'
name = 'Warp Time'
name = _t('Warp Time')
xDefs = [
XDef(handle='distance', unit='AU', label='Distance', mainInput=('distance', 'AU')),
XDef(handle='distance', unit='km', label='Distance', mainInput=('distance', 'km'))]
yDefs = [YDef(handle='time', unit='s', label='Warp time')]
XDef(handle='distance', unit='AU', label=_t('Distance'), mainInput=('distance', 'AU')),
XDef(handle='distance', unit='km', label=_t('Distance'), mainInput=('distance', 'km'))]
yDefs = [YDef(handle='time', unit='s', label=_t('Warp time'))]
inputs = [
Input(handle='distance', unit='AU', label='Distance', iconID=1391, defaultValue=20, defaultRange=(0, 50)),
Input(handle='distance', unit='km', label='Distance', iconID=1391, defaultValue=1000, defaultRange=(150, 5000))]
Input(handle='distance', unit='AU', label=_t('Distance'), iconID=1391, defaultValue=20, defaultRange=(0, 50)),
Input(handle='distance', unit='km', label=_t('Distance'), iconID=1391, defaultValue=1000, defaultRange=(150, 5000))]
srcExtraCols = ('WarpSpeed', 'WarpDistance')
# Calculation stuff
_normalizers = {
('distance', 'AU'): lambda v, src, tgt: v * AU_METERS,
('distance', 'km'): lambda v, src, tgt: v * 1000}
('distance', 'km'): lambda v, src, tgt: v * 1000
}
_limiters = {'distance': lambda src, tgt: (0, src.item.maxWarpDistance * AU_METERS)}
_getters = {('distance', 'time'): Distance2TimeGetter}
_denormalizers = {

View File

@@ -31,10 +31,10 @@ from service.fit import Fit
from .lists import SourceWrapperList, TargetWrapperList
from .vector import VectorPicker
InputData = namedtuple('InputData', ('handle', 'unit', 'value'))
InputBox = namedtuple('InputBox', ('handle', 'unit', 'textBox', 'icon', 'label'))
CheckBox = namedtuple('CheckBox', ('handle', 'checkBox'))
_t = wx.GetTranslation
class GraphControlPanel(wx.Panel):
@@ -53,7 +53,7 @@ class GraphControlPanel(wx.Panel):
commonOptsSizer = wx.BoxSizer(wx.VERTICAL)
ySubSelectionSizer = wx.BoxSizer(wx.HORIZONTAL)
yText = wx.StaticText(self, wx.ID_ANY, 'Axis Y:')
yText = wx.StaticText(self, wx.ID_ANY, _t('Axis Y:'))
ySubSelectionSizer.Add(yText, 0, wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, 5)
self.ySubSelection = wx.Choice(self, wx.ID_ANY)
self.ySubSelection.Bind(wx.EVT_CHOICE, self.OnYTypeUpdate)
@@ -61,18 +61,18 @@ class GraphControlPanel(wx.Panel):
commonOptsSizer.Add(ySubSelectionSizer, 0, wx.EXPAND | wx.ALL, 0)
xSubSelectionSizer = wx.BoxSizer(wx.HORIZONTAL)
xText = wx.StaticText(self, wx.ID_ANY, 'Axis X:')
xText = wx.StaticText(self, wx.ID_ANY, _t('Axis X:'))
xSubSelectionSizer.Add(xText, 0, wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, 5)
self.xSubSelection = wx.Choice(self, wx.ID_ANY)
self.xSubSelection.Bind(wx.EVT_CHOICE, self.OnXTypeUpdate)
xSubSelectionSizer.Add(self.xSubSelection, 1, wx.EXPAND | wx.ALL, 0)
commonOptsSizer.Add(xSubSelectionSizer, 0, wx.EXPAND | wx.TOP, 5)
self.showLegendCb = wx.CheckBox(self, wx.ID_ANY, 'Show legend', wx.DefaultPosition, wx.DefaultSize, 0)
self.showLegendCb = wx.CheckBox(self, wx.ID_ANY, _t('Show legend'), wx.DefaultPosition, wx.DefaultSize, 0)
self.showLegendCb.SetValue(True)
self.showLegendCb.Bind(wx.EVT_CHECKBOX, self.OnShowLegendChange)
commonOptsSizer.Add(self.showLegendCb, 0, wx.EXPAND | wx.TOP, 5)
self.showY0Cb = wx.CheckBox(self, wx.ID_ANY, 'Always show Y = 0', wx.DefaultPosition, wx.DefaultSize, 0)
self.showY0Cb = wx.CheckBox(self, wx.ID_ANY, _t('Always show Y = 0'), wx.DefaultPosition, wx.DefaultSize, 0)
self.showY0Cb.SetValue(True)
self.showY0Cb.Bind(wx.EVT_CHECKBOX, self.OnShowY0Change)
commonOptsSizer.Add(self.showY0Cb, 0, wx.EXPAND | wx.TOP, 5)

View File

@@ -34,8 +34,8 @@ from service.settings import GraphSettings
from . import canvasPanel
from .ctrlPanel import GraphControlPanel
pyfalog = Logger(__name__)
_t = wx.GetTranslation
REDRAW_DELAY = 500
@@ -48,7 +48,7 @@ class GraphFrame(AuxiliaryFrame):
pyfalog.warning('Matplotlib is not enabled. Skipping initialization.')
return
super().__init__(parent, title='Graphs', size=(520, 390), resizeable=True)
super().__init__(parent, title=_t('Graphs'), size=(520, 390), resizeable=True)
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
self.includeHidden = includeHidden

View File

@@ -33,6 +33,7 @@ from service.const import GraphCacheCleanupReason
from service.fit import Fit
from .stylePickers import ColorPickerPopup, LightnessPickerPopup, LineStylePickerPopup
_t = wx.GetTranslation
class BaseWrapperList(gui.display.Display):
@@ -302,14 +303,14 @@ class SourceWrapperList(BaseWrapperList):
selection = self.getSelectedWrappers()
mainItem = self.getWrapper(clickedPos)
itemContext = None if mainItem is None else 'Fit'
itemContext = None if mainItem is None else _t('Fit')
menu = ContextMenu.getMenu(self, mainItem, selection, ('graphFitList', itemContext), ('graphFitListMisc', itemContext))
if menu:
self.PopupMenu(menu)
@property
def defaultTTText(self):
return 'Drag a fit into this list to graph it'
return _t('Drag a fit into this list to graph it')
class TargetWrapperList(BaseWrapperList):
@@ -355,7 +356,7 @@ class TargetWrapperList(BaseWrapperList):
selection = self.getSelectedWrappers()
mainItem = self.getWrapper(clickedPos)
itemContext = None if mainItem is None else 'Target'
itemContext = None if mainItem is None else _t('Target')
menu = ContextMenu.getMenu(self, mainItem, selection, ('graphTgtList', itemContext), ('graphTgtListMisc', itemContext))
if menu:
self.PopupMenu(menu)
@@ -366,7 +367,7 @@ class TargetWrapperList(BaseWrapperList):
@property
def defaultTTText(self):
return 'Drag a fit into this list to have your fits graphed against it'
return _t('Drag a fit into this list to have your fits graphed against it')
# Context menu handlers
def addProfile(self, profile):

View File

@@ -25,9 +25,9 @@ import wx
from service.const import GraphColor, GraphLightness, GraphLineStyle
ColorData = namedtuple('ColorData', ('hsl', 'name', 'iconName'))
LightnessData = namedtuple('LightnessData', ('name', 'iconName', 'func'))
_t = wx.GetTranslation
class LineStyleData:
@@ -49,14 +49,14 @@ class LineStyleData:
# In HSL format
BASE_COLORS = OrderedDict([
(GraphColor.red, ColorData((0 / 360.0, 1.0, 0.5), 'Red', 'color_red')),
(GraphColor.green, ColorData((120 / 360.0, 1.0, 0.5), 'Green', 'color_green')),
(GraphColor.blue, ColorData((240 / 360.0, 1.0, 0.5), 'Blue', 'color_blue')),
(GraphColor.orange, ColorData((40 / 360.0, 1.0, 0.5), 'Orange', 'color_orange')),
(GraphColor.magenta, ColorData((300 / 360.0, 1.0, 0.5), 'Magenta', 'color_magenta')),
(GraphColor.cyan, ColorData((180 / 360.0, 1.0, 0.5), 'Cyan', 'color_cyan')),
(GraphColor.purple, ColorData((275 / 360.0, 1.0, 0.5), 'Purple', 'color_purple')),
(GraphColor.yellow, ColorData((56 / 360.0, 1.0, 0.5), 'Yellow', 'color_yellow'))])
(GraphColor.red, ColorData((0 / 360.0, 1.0, 0.5), _t('Red'), 'color_red')),
(GraphColor.green, ColorData((120 / 360.0, 1.0, 0.5), _t('Green'), 'color_green')),
(GraphColor.blue, ColorData((240 / 360.0, 1.0, 0.5), _t('Blue'), 'color_blue')),
(GraphColor.orange, ColorData((40 / 360.0, 1.0, 0.5), _t('Orange'), 'color_orange')),
(GraphColor.magenta, ColorData((300 / 360.0, 1.0, 0.5), _t('Magenta'), 'color_magenta')),
(GraphColor.cyan, ColorData((180 / 360.0, 1.0, 0.5), _t('Cyan'), 'color_cyan')),
(GraphColor.purple, ColorData((275 / 360.0, 1.0, 0.5), _t('Purple'), 'color_purple')),
(GraphColor.yellow, ColorData((56 / 360.0, 1.0, 0.5), _t('Yellow'), 'color_yellow'))])
def hsl_to_hsv(hsl):
@@ -77,13 +77,13 @@ def brighten(hsl):
LIGHTNESSES = OrderedDict([
(GraphLightness.normal, LightnessData('Normal', 'lightness_normal', lambda hsl: hsl)),
(GraphLightness.dark, LightnessData('Dark', 'lightness_dark', darken)),
(GraphLightness.bright, LightnessData('Bright', 'lightness_bright', brighten))])
(GraphLightness.normal, LightnessData(_t('Normal'), 'lightness_normal', lambda hsl: hsl)),
(GraphLightness.dark, LightnessData(_t('Dark'), 'lightness_dark', darken)),
(GraphLightness.bright, LightnessData(_t('Bright'), 'lightness_bright', brighten))])
STYLES = OrderedDict([
(GraphLineStyle.solid, LineStyleData('Solid', 'style_solid', 'solid')),
(GraphLineStyle.dashed, LineStyleData('Dashed', 'style_dashed', (0, (5, 1)))),
(GraphLineStyle.dotted, LineStyleData('Dotted', 'style_dotted', (0, (1, 1)))),
(GraphLineStyle.dashdotted, LineStyleData('Dash-dotted', 'style_dashdot', (0, (3, 1, 1, 1))))])
(GraphLineStyle.solid, LineStyleData(_t('Solid'), 'style_solid', 'solid')),
(GraphLineStyle.dashed, LineStyleData(_t('Dashed'), 'style_dashed', (0, (5, 1)))),
(GraphLineStyle.dotted, LineStyleData(_t('Dotted'), 'style_dotted', (0, (1, 1)))),
(GraphLineStyle.dashdotted, LineStyleData(_t('Dash-dotted'), 'style_dashdot', (0, (3, 1, 1, 1))))])

View File

@@ -18,6 +18,8 @@
# =============================================================================
import config
import wx
_t = wx.GetTranslation
try:
versionString = "{0}".format(config.getVersion())
@@ -26,10 +28,10 @@ except NameError:
versionString = "0.0"
licenses = (
"pyfa is released under GNU GPLv3 - see included LICENSE file",
"All EVE-Online related materials are property of CCP hf.",
"Silk Icons Set by famfamfam.com - Creative Commons Attribution 2.5 License",
"Fat Cow Icons by fatcow.com - Creative Commons Attribution 3.0 License"
_t("pyfa is released under GNU GPLv3 - see included LICENSE file"),
_t("All EVE-Online related materials are property of CCP hf."),
_t("Silk Icons Set by famfamfam.com - Creative Commons Attribution 2.5 License"),
_t("Fat Cow Icons by fatcow.com - Creative Commons Attribution 3.0 License")
)
developers = (
"blitzmann \tSable Blitzmann (maintainer)",
@@ -44,7 +46,7 @@ credits = (
"Corollax (Aamrr) \tVarious EOS / pyfa improvements",
"Dreae (Dreae)\tPyCrest")
description = (
"Pyfa (the Python Fitting Assistant) is an open-source standalone application able to "
_t("Pyfa (the Python Fitting Assistant) is an open-source standalone application able to "
"create and simulate fittings for EVE-Online SciFi MMORPG with a very high degree of "
"accuracy. Pyfa can run on all platforms where Python and wxWidgets are supported."
"accuracy. Pyfa can run on all platforms where Python and wxWidgets are supported.")
)

View File

@@ -33,6 +33,7 @@ from gui.builtinAdditionPanes.projectedView import ProjectedView
from gui.chrome_tabs import ChromeNotebook
from gui.toggle_panel import TogglePanel
_t = wx.GetTranslation
class AdditionsPane(TogglePanel):
@@ -41,7 +42,7 @@ class AdditionsPane(TogglePanel):
TogglePanel.__init__(self, parent, force_layout=1)
self.mainFrame = mainFrame
self.SetLabel("Additions")
self.SetLabel(_t("Additions"))
pane = self.GetContentPanel()
baseSizer = wx.BoxSizer(wx.HORIZONTAL)
@@ -62,28 +63,28 @@ class AdditionsPane(TogglePanel):
notesImg = BitmapLoader.getImage("skill_small", "gui")
self.drone = DroneView(self.notebook)
self.notebook.AddPage(self.drone, "Drones", image=droneImg, closeable=False)
self.notebook.AddPage(self.drone, _t("Drones"), image=droneImg, closeable=False)
self.fighter = FighterView(self.notebook)
self.notebook.AddPage(self.fighter, "Fighters", image=fighterImg, closeable=False)
self.notebook.AddPage(self.fighter, _t("Fighters"), image=fighterImg, closeable=False)
self.cargo = CargoView(self.notebook)
self.notebook.AddPage(self.cargo, "Cargo", image=cargoImg, closeable=False)
self.notebook.AddPage(self.cargo, _t("Cargo"), image=cargoImg, closeable=False)
self.implant = ImplantView(self.notebook)
self.notebook.AddPage(self.implant, "Implants", image=implantImg, closeable=False)
self.notebook.AddPage(self.implant, _t("Implants"), image=implantImg, closeable=False)
self.booster = BoosterView(self.notebook)
self.notebook.AddPage(self.booster, "Boosters", image=boosterImg, closeable=False)
self.notebook.AddPage(self.booster, _t("Boosters"), image=boosterImg, closeable=False)
self.projectedPage = ProjectedView(self.notebook)
self.notebook.AddPage(self.projectedPage, "Projected", image=projectedImg, closeable=False)
self.notebook.AddPage(self.projectedPage, _t("Projected"), image=projectedImg, closeable=False)
self.gangPage = CommandView(self.notebook)
self.notebook.AddPage(self.gangPage, "Command", image=gangImg, closeable=False)
self.notebook.AddPage(self.gangPage, _t("Command"), image=gangImg, closeable=False)
self.notes = NotesView(self.notebook)
self.notebook.AddPage(self.notes, "Notes", image=notesImg, closeable=False)
self.notebook.AddPage(self.notes, _t("Notes"), image=notesImg, closeable=False)
self.mainFrame.Bind(GE.FIT_CHANGED, self.OnFitChanged)
self.mainFrame.Bind(GE.FIT_NOTES_CHANGED, self.OnNotesChanged)

77
gui/app.py Normal file
View File

@@ -0,0 +1,77 @@
import wx
import config
import os
import sys
from logbook import Logger
pyfalog = Logger(__name__)
from service.settings import LocaleSettings
class PyfaApp(wx.App):
def OnInit(self):
"""
Do application initialization work, e.g. define application globals.
"""
# Name for my application.
self.appName = "pyfa"
#------------
# # Simplified init method.
# self.DoConfig()
# self.Init() # InspectionMixin
# # work around for Python stealing "_".
# sys.displayhook = _displayHook
#
# #------------
# Return locale folder.
localeDir = os.path.join(config.pyfaPath, "locale")
# Set language stuff and update to last used language.
self.locale = None
wx.Locale.AddCatalogLookupPathPrefix(localeDir)
# Set language stuff and update to last used language.
self.UpdateLanguage(config.language)
return True
#-----------------------------------------------------------------------
def UpdateLanguage(self, lang=None):
"""
Update the language to the requested one.
Make *sure* any existing locale is deleted before the new
one is created. The old C++ object needs to be deleted
before the new one is created, and if we just assign a new
instance to the old Python variable, the old C++ locale will
not be destroyed soon enough, likely causing a crash.
:param string `lang`: one of the supported language codes.
"""
# Language domain.
langDomain = config.CATALOG
# If an unsupported language is requested default to English.
if self.locale:
assert sys.getrefcount(self.locale) <= 2
del self.locale
# Create a locale object for this language.
langInfo = wx.Locale.FindLanguageInfo(lang)
if langInfo is not None:
pyfalog.debug("Setting language to: " + lang)
self.locale = wx.Locale(langInfo.Language)
if self.locale.IsOk():
success = self.locale.AddCatalog(langDomain)
if not success:
print("Langauage catalog not successfully loaded")
else:
pyfalog.debug("Cannot find langauge: " + lang)
self.locale = wx.Locale(wx.Locale.FindLanguageInfo(LocaleSettings.defaults['locale']).Language)

View File

@@ -29,7 +29,7 @@ from gui.contextMenu import ContextMenu
from gui.utils.staticHelpers import DragDropHelper
from service.fit import Fit
from service.market import Market
_t = wx.GetTranslation
class BoosterViewDrop(wx.DropTarget):
def __init__(self, dropFn, *args, **kwargs):
@@ -212,7 +212,7 @@ class BoosterView(d.Display):
else:
if booster in self.original:
mainBooster = booster
itemContext = None if mainBooster is None else "Booster"
itemContext = None if mainBooster is None else _t("Booster")
menu = ContextMenu.getMenu(self, mainBooster, selection, ("boosterItem", itemContext), ("boosterItemMisc", itemContext))
if menu:
self.PopupMenu(menu)

View File

@@ -227,7 +227,7 @@ class CargoView(d.Display):
else:
if cargo in self.original:
mainCargo = cargo
itemContext = None if mainCargo is None else Market.getInstance().getCategoryByItem(mainCargo.item).name
itemContext = None if mainCargo is None else Market.getInstance().getCategoryByItem(mainCargo.item).displayName
menu = ContextMenu.getMenu(self, mainCargo, selection, ("cargoItem", itemContext), ("cargoItemMisc", itemContext))
if menu:
self.PopupMenu(menu)

View File

@@ -30,6 +30,7 @@ from gui.contextMenu import ContextMenu
from gui.utils.staticHelpers import DragDropHelper
from service.fit import Fit
_t = wx.GetTranslation
class DummyItem:
@@ -159,7 +160,7 @@ class CommandView(d.Display):
self.fits.sort(key=self.fitSort)
stuff.extend(self.fits)
if not stuff:
stuff = [DummyEntry("Drag a fit to this area")]
stuff = [DummyEntry(_t("Drag a fit to this area"))]
self.update(stuff)
def click(self, event):
@@ -197,7 +198,7 @@ class CommandView(d.Display):
pass
contexts = []
if mainCommandFit is not None:
contexts.append(('commandFit', 'Command Fit'))
contexts.append(('commandFit', _t('Command Fit')))
contexts.append(('commandView',))
menu = ContextMenu.getMenu(self, mainCommandFit, selection, *contexts)
if menu:

View File

@@ -195,7 +195,7 @@ class DroneView(Display):
def droneKey(drone):
sMkt = Market.getInstance()
groupName = sMkt.getMarketGroupByItem(drone.item).name
groupName = sMkt.getMarketGroupByItem(drone.item).marketGroupName
return (DRONE_ORDER.index(groupName), drone.item.name)
@@ -324,7 +324,7 @@ class DroneView(Display):
if drone in self.original:
mainDrone = drone
selection = self.getSelectedDrones()
itemContext = None if mainDrone is None else Market.getInstance().getCategoryByItem(mainDrone.item).name
itemContext = None if mainDrone is None else Market.getInstance().getCategoryByItem(mainDrone.item).displayName
menu = ContextMenu.getMenu(self, mainDrone, selection, ("droneItem", itemContext), ("droneItemMisc", itemContext))
if menu:
self.PopupMenu(menu)

View File

@@ -35,6 +35,7 @@ from service.market import Market
FIGHTER_ORDER = ('Light Fighter', 'Heavy Fighter', 'Support Fighter')
_t = wx.GetTranslation
class FighterViewDrop(wx.DropTarget):
@@ -58,7 +59,7 @@ class FighterView(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, style=wx.TAB_TRAVERSAL)
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
self.labels = ["Light", "Heavy", "Support"]
self.labels = [("Light", _t("Light")), ("Heavy", _t("Heavy")), ("Support", _t("Support"))]
mainSizer = wx.BoxSizer(wx.VERTICAL)
@@ -68,18 +69,18 @@ class FighterView(wx.Panel):
textSizer = wx.BoxSizer(wx.HORIZONTAL)
textSizer.AddStretchSpacer()
for x in self.labels:
lbl = wx.StaticText(self, wx.ID_ANY, x.capitalize())
for attr, label in self.labels:
lbl = wx.StaticText(self, wx.ID_ANY, label)
textSizer.Add(lbl, 0, wx.ALIGN_CENTER | wx.LEFT, 5)
lbl = wx.StaticText(self, wx.ID_ANY, "0")
setattr(self, "label%sUsed" % (x.capitalize()), lbl)
setattr(self, "label%sUsed" % attr, lbl)
textSizer.Add(lbl, 0, wx.ALIGN_CENTER | wx.LEFT, 5)
textSizer.Add(wx.StaticText(self, wx.ID_ANY, "/"), 0, wx.ALIGN_CENTER)
lbl = wx.StaticText(self, wx.ID_ANY, "0")
setattr(self, "label%sTotal" % (x.capitalize()), lbl)
setattr(self, "label%sTotal" % attr, lbl)
textSizer.Add(lbl, 0, wx.ALIGN_CENTER)
textSizer.AddStretchSpacer()
@@ -100,7 +101,7 @@ class FighterView(wx.Panel):
fit = sFit.getFit(activeFitID)
if fit:
for x in self.labels:
for x, _ in self.labels:
if fit.isStructure:
slot = getattr(FittingSlot, "FS_{}".format(x.upper()))
else:
@@ -382,7 +383,7 @@ class FighterDisplay(d.Display):
else:
if fighter in self.original:
mainFighter = fighter
itemContext = None if mainFighter is None else Market.getInstance().getCategoryByItem(mainFighter.item).name
itemContext = None if mainFighter is None else Market.getInstance().getCategoryByItem(mainFighter.item).displayName
menu = ContextMenu.getMenu(self, mainFighter, selection, ("fighterItem", itemContext), ("fighterItemMisc", itemContext))
if menu:
self.PopupMenu(menu)

View File

@@ -32,6 +32,8 @@ from gui.utils.staticHelpers import DragDropHelper
from service.fit import Fit
from service.market import Market
_t = wx.GetTranslation
class ImplantViewDrop(wx.DropTarget):
def __init__(self, dropFn, *args, **kwargs):
@@ -62,8 +64,8 @@ class ImplantView(wx.Panel):
radioSizer = wx.BoxSizer(wx.HORIZONTAL)
radioSizer.AddStretchSpacer()
self.rbFit = wx.RadioButton(self, id=wx.ID_ANY, label="Use Fit-specific Implants", style=wx.RB_GROUP)
self.rbChar = wx.RadioButton(self, id=wx.ID_ANY, label="Use Character Implants")
self.rbFit = wx.RadioButton(self, id=wx.ID_ANY, label=_t("Use Fit-specific Implants"), style=wx.RB_GROUP)
self.rbChar = wx.RadioButton(self, id=wx.ID_ANY, label=_t("Use Character Implants"))
radioSizer.Add(self.rbFit, 0, wx.ALL, 5)
radioSizer.Add(self.rbChar, 0, wx.ALL, 5)
radioSizer.AddStretchSpacer()
@@ -298,7 +300,7 @@ class ImplantDisplay(d.Display):
fit = Fit.getInstance().getFit(fitID)
sourceContext1 = "implantItem" if fit.implantSource == ImplantLocation.FIT else "implantItemChar"
sourceContext2 = "implantItemMisc" if fit.implantSource == ImplantLocation.FIT else "implantItemMiscChar"
itemContext = None if mainImplant is None else Market.getInstance().getCategoryByItem(mainImplant.item).name
itemContext = None if mainImplant is None else Market.getInstance().getCategoryByItem(mainImplant.item).displayName
menu = ContextMenu.getMenu(self, mainImplant, selection,
(sourceContext1, itemContext),
(sourceContext2, itemContext)

View File

@@ -41,7 +41,7 @@ from service.market import Market
pyfalog = Logger(__name__)
_t = wx.GetTranslation
class DummyItem:
def __init__(self, txt):
@@ -221,7 +221,7 @@ class ProjectedView(d.Display):
stuff.extend(self.drones)
stuff.extend(self.fighters)
if not stuff:
stuff = [DummyEntry('Drag an item or fit, or use right-click menu for wormhole effects')]
stuff = [DummyEntry(_t('Drag an item or fit, or use right-click menu for wormhole effects'))]
self.update(stuff)
def get(self, row):
@@ -301,27 +301,27 @@ class ProjectedView(d.Display):
if isinstance(mainItem, EosModule):
modSrcContext = 'projectedModule'
modItemContext = 'Projected Item'
modItemContext = _t('Projected Item')
modFullContext = (modSrcContext, modItemContext)
contexts.append(modFullContext)
if mainItem.charge is not None:
chargeSrcContext = 'projectedCharge'
chargeItemContext = sMkt.getCategoryByItem(mainItem.charge).name
chargeItemContext = sMkt.getCategoryByItem(mainItem.charge).displayName
chargeFullContext = (chargeSrcContext, chargeItemContext)
contexts.append(chargeFullContext)
elif isinstance(mainItem, EosDrone):
srcContext = 'projectedDrone'
itemContext = 'Projected Item'
itemContext = _t('Projected Item')
droneFullContext = (srcContext, itemContext)
contexts.append(droneFullContext)
elif isinstance(mainItem, EosFighter):
srcContext = 'projectedFighter'
itemContext = 'Projected Item'
itemContext = _t('Projected Item')
fighterFullContext = (srcContext, itemContext)
contexts.append(fighterFullContext)
else:
fitSrcContext = 'projectedFit'
fitItemContext = 'Projected Item'
fitItemContext = _t('Projected Item')
fitFullContext = (fitSrcContext, fitItemContext)
contexts.append(fitFullContext)
contexts.append(('projected',))

View File

@@ -1,44 +1,46 @@
import wx
import gui.mainFrame
from gui.contextMenu import ContextMenuUnconditional
from gui.utils.clipboard import toClipboard
from service.fit import Fit
from service.port.eft import exportDrones, exportFighters, exportCargo, exportImplants, exportBoosters
from service.port.eft import exportBoosters, exportCargo, exportDrones, exportFighters, exportImplants
viewSpecMap = {
'droneItemMisc': ('Drones', lambda cw: cw.drones, exportDrones),
'fighterItemMisc': ('Fighters', lambda cw: cw.fighters, exportFighters),
'cargoItemMisc': ('Cargo Items', lambda cw: cw.cargo, exportCargo),
'implantItemMisc': ('Implants', lambda cw: cw.implants, exportImplants),
'implantItemMiscChar': ('Implants', lambda cw: cw.implants, exportImplants),
'boosterItemMisc': ('Boosters', lambda cw: cw.boosters, exportBoosters)}
_t = wx.GetTranslation
class AdditionsExportAll(ContextMenuUnconditional):
visibilitySetting = 'additionsCopyPaste'
def __init__(self):
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
self.viewSpecMap = {
'droneItemMisc': (_t('Drones'), lambda cw: cw.drones, exportDrones),
'fighterItemMisc': (_t('Fighters'), lambda cw: cw.fighters, exportFighters),
'cargoItemMisc': (_t('Cargo Items'), lambda cw: cw.cargo, exportCargo),
'implantItemMisc': (_t('Implants'), lambda cw: cw.implants, exportImplants),
'implantItemMiscChar': (_t('Implants'), lambda cw: cw.implants, exportImplants),
'boosterItemMisc': (_t('Boosters'), lambda cw: cw.boosters, exportBoosters)
}
def display(self, callingWindow, srcContext):
if srcContext not in viewSpecMap:
if srcContext not in self.viewSpecMap:
return False
fit = Fit.getInstance().getFit(self.mainFrame.getActiveFit())
if fit is None:
return False
if not viewSpecMap[srcContext][1](callingWindow):
if not self.viewSpecMap[srcContext][1](callingWindow):
return False
self.srcContext = srcContext
return True
def getText(self, callingWindow, itmContext):
return 'Copy All {}'.format(viewSpecMap[self.srcContext][0])
return _t('Copy All {}').format(self.viewSpecMap[self.srcContext][0])
def activate(self, callingWindow, fullContext, i):
items = viewSpecMap[self.srcContext][1](callingWindow)
export = viewSpecMap[self.srcContext][2](items)
items = self.viewSpecMap[self.srcContext][1](callingWindow)
export = self.viewSpecMap[self.srcContext][2](items)
if export:
toClipboard(export)

View File

@@ -1,28 +1,30 @@
import wx
import gui.mainFrame
from gui.contextMenu import ContextMenuSelection
from gui.utils.clipboard import toClipboard
from service.fit import Fit
from service.port.eft import exportDrones, exportFighters, exportCargo, exportImplants, exportBoosters
from service.port.eft import exportBoosters, exportCargo, exportDrones, exportFighters, exportImplants
viewSpecMap = {
'droneItemMisc': ('Drones', exportDrones),
'fighterItemMisc': ('Fighters', exportFighters),
'cargoItemMisc': ('Cargo Items', exportCargo),
'implantItemMisc': ('Implants', exportImplants),
'implantItemMiscChar': ('Implants', exportImplants),
'boosterItemMisc': ('Boosters', exportBoosters)}
_t = wx.GetTranslation
class AdditionsExportAll(ContextMenuSelection):
visibilitySetting = 'additionsCopyPaste'
def __init__(self):
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
self.viewSpecMap = {
'droneItemMisc': (_t('Drones'), exportDrones),
'fighterItemMisc': (_t('Fighters'), exportFighters),
'cargoItemMisc': (_t('Cargo Items'), exportCargo),
'implantItemMisc': (_t('Implants'), exportImplants),
'implantItemMiscChar': (_t('Implants'), exportImplants),
'boosterItemMisc': (_t('Boosters'), exportBoosters)
}
def display(self, callingWindow, srcContext, selection):
if srcContext not in viewSpecMap:
if srcContext not in self.viewSpecMap:
return False
if not selection:
return False
@@ -34,10 +36,10 @@ class AdditionsExportAll(ContextMenuSelection):
return True
def getText(self, callingWindow, itmContext, selection):
return 'Copy Selected {}'.format(viewSpecMap[self.srcContext][0])
return _t('Copy Selected {}').format(self.viewSpecMap[self.srcContext][0])
def activate(self, callingWindow, fullContext, selection, i):
export = viewSpecMap[self.srcContext][1](selection)
export = self.viewSpecMap[self.srcContext][1](selection)
if export:
toClipboard(export)

View File

@@ -1,3 +1,5 @@
import wx
import gui.mainFrame
from gui import fitCommands as cmd
from gui.contextMenu import ContextMenuUnconditional
@@ -5,25 +7,25 @@ from gui.utils.clipboard import fromClipboard
from service.fit import Fit
from service.port.eft import parseAdditions
viewSpecMap = {
'droneItemMisc': ('Drones', lambda i: i.isDrone, cmd.GuiImportLocalDronesCommand),
'fighterItemMisc': ('Fighters', lambda i: i.isFighter, cmd.GuiImportLocalFightersCommand),
'cargoItemMisc': ('Cargo Items', lambda i: not i.isAbyssal, cmd.GuiImportCargosCommand),
'implantItemMisc': ('Implants', lambda i: i.isImplant, cmd.GuiImportImplantsCommand),
'implantItemMiscChar': ('Implants', lambda i: i.isImplant, cmd.GuiImportImplantsCommand),
'boosterItemMisc': ('Boosters', lambda i: i.isBooster, cmd.GuiImportBoostersCommand)}
_t = wx.GetTranslation
class AdditionsImport(ContextMenuUnconditional):
visibilitySetting = 'additionsCopyPaste'
def __init__(self):
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
self.viewSpecMap = {
'droneItemMisc': (_t('Drones'), lambda i: i.isDrone, cmd.GuiImportLocalDronesCommand),
'fighterItemMisc': (_t('Fighters'), lambda i: i.isFighter, cmd.GuiImportLocalFightersCommand),
'cargoItemMisc': (_t('Cargo Items'), lambda i: not i.isAbyssal, cmd.GuiImportCargosCommand),
'implantItemMisc': (_t('Implants'), lambda i: i.isImplant, cmd.GuiImportImplantsCommand),
'implantItemMiscChar': (_t('Implants'), lambda i: i.isImplant, cmd.GuiImportImplantsCommand),
'boosterItemMisc': (_t('Boosters'), lambda i: i.isBooster, cmd.GuiImportBoostersCommand)
}
def display(self, callingWindow, srcContext):
if srcContext not in viewSpecMap:
if srcContext not in self.viewSpecMap:
return False
fit = Fit.getInstance().getFit(self.mainFrame.getActiveFit())
if fit is None:
@@ -35,16 +37,16 @@ class AdditionsImport(ContextMenuUnconditional):
return True
def getText(self, callingWindow, itmContext):
return 'Paste {}'.format(viewSpecMap[self.srcContext][0])
return _t('Paste {}').format(self.viewSpecMap[self.srcContext][0])
def activate(self, callingWindow, fullContext, i):
text = fromClipboard()
items = parseAdditions(text)
filterFunc = viewSpecMap[self.srcContext][1]
filterFunc = self.viewSpecMap[self.srcContext][1]
items = [(i.ID, a) for i, a in items if filterFunc(i)]
if not items:
return
command = viewSpecMap[self.srcContext][2]
command = self.viewSpecMap[self.srcContext][2]
self.mainFrame.command.Submit(command(self.mainFrame.getActiveFit(), items))

View File

@@ -6,9 +6,10 @@ import gui.mainFrame
from gui.contextMenu import ContextMenuSingle
from service.fit import Fit
_t = wx.GetTranslation
class AmmoToDmgPattern(ContextMenuSingle):
visibilitySetting = 'ammoPattern'
def __init__(self):
@@ -28,7 +29,7 @@ class AmmoToDmgPattern(ContextMenuSingle):
return False
def getText(self, callingWindow, itmContext, mainItem):
return "Set {} as Damage Pattern".format(itmContext if itmContext is not None else "Item")
return _t("Set {} as Damage Pattern").format(itmContext if itmContext is not None else _t("Item"))
def activate(self, callingWindow, fullContext, mainItem, i):
fitID = self.mainFrame.getActiveFit()

View File

@@ -1,4 +1,5 @@
# noinspection PyPackageRequirements
import wx
import gui.mainFrame
@@ -6,6 +7,8 @@ from gui import fitCommands as cmd
from gui.contextMenu import ContextMenuSingle
from service.fit import Fit
_t = wx.GetTranslation
class BoosterSideEffects(ContextMenuSingle):
@@ -28,7 +31,7 @@ class BoosterSideEffects(ContextMenuSingle):
return False
def getText(self, callingWindow, itmContext, mainItem):
return "Side Effects"
return _t("Side Effects")
def addEffect(self, menu, ability):
label = ability.name
@@ -67,7 +70,7 @@ class BoosterSideEffects(ContextMenuSingle):
if booster in fit.boosters:
index = fit.boosters.index(booster)
self.mainFrame.command.Submit(cmd.GuiToggleBoosterSideEffectStateCommand(
fitID=fitID, position=index, effectID=effect.effectID))
fitID=fitID, position=index, effectID=effect.effectID))
BoosterSideEffects.register()

View File

@@ -1,8 +1,12 @@
import wx
import gui.fitCommands as cmd
import gui.mainFrame
from gui.contextMenu import ContextMenuSingle
from service.fit import Fit
_t = wx.GetTranslation
class AddToCargo(ContextMenuSingle):
@@ -26,7 +30,7 @@ class AddToCargo(ContextMenuSingle):
return True
def getText(self, callingWindow, itmContext, mainItem):
return "Add {} to Cargo".format(itmContext)
return _t("Add {} to Cargo").format(itmContext)
def activate(self, callingWindow, fullContext, mainItem, i):
fitID = self.mainFrame.getActiveFit()

View File

@@ -1,7 +1,11 @@
import wx
import gui.fitCommands as cmd
import gui.mainFrame
from gui.contextMenu import ContextMenuSingle
_t = wx.GetTranslation
class AddToCargoAmmo(ContextMenuSingle):
@@ -21,7 +25,7 @@ class AddToCargoAmmo(ContextMenuSingle):
return True
def getText(self, callingWindow, itmContext, mainItem):
return "Add {0} to Cargo (x1000)".format(itmContext)
return _t("Add {0} to Cargo (x1000)").format(itmContext)
def activate(self, callingWindow, fullContext, mainItem, i):
fitID = self.mainFrame.getActiveFit()

View File

@@ -7,9 +7,10 @@ from gui.contextMenu import ContextMenuUnconditional
from service.fit import Fit
from service.market import Market
_t = wx.GetTranslation
class AddCommandFit(ContextMenuUnconditional):
# Get list of items that define a command fit
sMkt = Market.getInstance()
grp = sMkt.getGroup(1770) # Command burst group
@@ -47,7 +48,7 @@ class AddCommandFit(ContextMenuUnconditional):
return True
def getText(self, callingWindow, itmContext):
return "Command Fits"
return _t("Command Fits")
def addFit(self, menu, fit, includeShip=False):
label = fit.name if not includeShip else "({}) {}".format(fit.ship.item.name, fit.name)

View File

@@ -11,6 +11,8 @@ from gui.utils.sorter import smartSort
from service.damagePattern import DamagePattern as DmgPatternSvc
from service.fit import Fit
_t = wx.GetTranslation
class ChangeDamagePattern(ContextMenuUnconditional):
@@ -35,16 +37,18 @@ class ChangeDamagePattern(ContextMenuUnconditional):
# Order here is important: patterns with duplicate names from the latter will overwrite
# patterns from the former
self.patterns = sorted(
chain(builtinPatterns, userPatterns),
key=lambda p: p.fullName not in ["Uniform", "Selected Ammo"])
chain(builtinPatterns, userPatterns),
key=lambda p: p.fullName not in ["Uniform", "Selected Ammo"])
self.patternEventMap = {}
self.items = (OrderedDict(), OrderedDict())
for pattern in self.patterns:
container = self.items
for categoryName in pattern.hierarchy:
categoryName = _t(categoryName) if pattern.builtin else categoryName
container = container[1].setdefault(categoryName, (OrderedDict(), OrderedDict()))
container[0][pattern.shortName] = pattern
shortName = _t(pattern.shortName) if pattern.builtin else pattern.shortName
container[0][shortName] = pattern
return list(self.items[0].keys()) + list(self.items[1].keys())

View File

@@ -1,9 +1,13 @@
import wx
import gui.fitCommands as cmd
import gui.mainFrame
from gui.contextMenu import ContextMenuSingle
from gui.fitCommands.helpers import droneStackLimit
from service.fit import Fit
_t = wx.GetTranslation
class DroneAddStack(ContextMenuSingle):
@@ -33,14 +37,14 @@ class DroneAddStack(ContextMenuSingle):
return True
def getText(self, callingWindow, itmContext, mainItem):
return 'Add {} to Drone Bay{}'.format(
itmContext, '' if self.amount == 1 else ' (x{})'.format(self.amount))
return _t('Add {} to Drone Bay{}').format(
itmContext, '' if self.amount == 1 else ' (x{})'.format(self.amount))
def activate(self, callingWindow, fullContext, mainItem, i):
command = cmd.GuiAddLocalDroneCommand(
fitID=self.mainFrame.getActiveFit(),
itemID=int(mainItem.ID),
amount=self.amount)
fitID=self.mainFrame.getActiveFit(),
itemID=int(mainItem.ID),
amount=self.amount)
if self.mainFrame.command.Submit(command):
self.mainFrame.additionsPane.select('Drones', focus=False)

View File

@@ -8,6 +8,8 @@ import gui.mainFrame
from gui.contextMenu import ContextMenuSingle
from service.fit import Fit
_t = wx.GetTranslation
class DroneSplitStack(ContextMenuSingle):
@@ -24,7 +26,7 @@ class DroneSplitStack(ContextMenuSingle):
return mainItem.amount > 1
def getText(self, callingWindow, itmContext, mainItem):
return "Split {} Stack".format(itmContext)
return _t("Split {} Stack").format(itmContext)
def activate(self, callingWindow, fullContext, mainItem, i):
with DroneStackSplit(self.mainFrame, mainItem.amount) as dlg:
@@ -41,7 +43,7 @@ class DroneSplitStack(ContextMenuSingle):
if mainItem in fit.drones:
position = fit.drones.index(mainItem)
self.mainFrame.command.Submit(cmd.GuiSplitLocalDroneStackCommand(
fitID=fitID, position=position, amount=int(cleanInput)))
fitID=fitID, position=position, amount=int(cleanInput)))
DroneSplitStack.register()

View File

@@ -10,6 +10,8 @@ import gui.mainFrame
from gui.contextMenu import ContextMenuUnconditional
from service.market import Market
_t = wx.GetTranslation
class Group:
@@ -32,9 +34,7 @@ class Entry:
self.shortName = shortName
class AddEnvironmentEffect(ContextMenuUnconditional):
# CCP doesn't currently provide a mapping between the general Environment, and the specific environment effect
# (which can be random when going into Abyssal space). This is how we currently define it:
# environment type: specific type name prefix
@@ -53,7 +53,7 @@ class AddEnvironmentEffect(ContextMenuUnconditional):
return srcContext == "projected"
def getText(self, callingWindow, itmContext):
return "Add Environmental Effect"
return _t("Add Environmental Effect")
def _addGroup(self, parentMenu, name):
id = ContextMenuUnconditional.nextID()
@@ -102,16 +102,30 @@ class AddEnvironmentEffect(ContextMenuUnconditional):
def getData(self):
data = Group()
data.groups['Metaliminal Storm'] = self.getEffectBeacons(
'Electrical', 'Exotic', 'Gamma', 'Plasma',
extra_garbage=('Metaliminal', 'Storm', 'Matter', 'Ray', 'Firestorm'))
data.groups['Wormhole'] = self.getEffectBeacons(
'Black Hole', 'Cataclysmic Variable', 'Magnetar',
'Pulsar', 'Red Giant', 'Wolf Rayet')
data.groups['Abyssal Weather'] = self.getAbyssalWeather()
data.groups['Sansha Incursion'] = self.getEffectBeacons('Sansha Incursion')
data.groups['Triglavian Invasion'] = self.getEffectBeacons('Triglavian Invasion')
data.groups['Triglavian Invasion'].groups['Destructible Beacons'] = self.getDestructibleBeacons()
data.groups[_t('Metaliminal Storm')] = self.getEffectBeacons(
_t('ContextMenu|ProjectedEffectManipulation|Electrical'),
_t('ContextMenu|ProjectedEffectManipulation|Exotic'),
_t('ContextMenu|ProjectedEffectManipulation|Gamma'),
_t('ContextMenu|ProjectedEffectManipulation|Plasma'),
extra_garbage=(
_t('ContextMenu|ProjectedEffectManipulation|Metaliminal'),
_t('ContextMenu|ProjectedEffectManipulation|Storm'),
_t('ContextMenu|ProjectedEffectManipulation|Matter'),
_t('ContextMenu|ProjectedEffectManipulation|Ray'),
_t('ContextMenu|ProjectedEffectManipulation|Firestorm')))
data.groups[_t('Wormhole')] = self.getEffectBeacons(
_t('ContextMenu|ProjectedEffectManipulation|Black Hole'),
_t('ContextMenu|ProjectedEffectManipulation|Cataclysmic Variable'),
_t('ContextMenu|ProjectedEffectManipulation|Magnetar'),
_t('ContextMenu|ProjectedEffectManipulation|Pulsar'),
_t('ContextMenu|ProjectedEffectManipulation|Red Giant'),
_t('ContextMenu|ProjectedEffectManipulation|Wolf Rayet'))
data.groups[_t('Abyssal Weather')] = self.getAbyssalWeather()
data.groups[_t('Sansha Incursion')] = self.getEffectBeacons(
_t('ContextMenu|ProjectedEffectManipulation|Sansha Incursion'))
data.groups[_t('Triglavian Invasion')] = self.getEffectBeacons(
_t('ContextMenu|ProjectedEffectManipulation|Triglavian Invasion'))
data.groups[_t('Triglavian Invasion')].groups[_t('Destructible Beacons')] = self.getDestructibleBeacons()
return data
def getEffectBeacons(self, *groups, extra_garbage=()):
@@ -125,7 +139,9 @@ class AddEnvironmentEffect(ContextMenuUnconditional):
data = Group()
# Stuff we don't want to see in names
garbages = ["System Effects", "Effects"]
garbages = [
_t('ContextMenu|ProjectedEffectManipulation|System Effects'),
_t('ContextMenu|ProjectedEffectManipulation|Effects')]
garbages.extend(extra_garbage)
# Get group with all the system-wide beacons
@@ -169,8 +185,8 @@ class AddEnvironmentEffect(ContextMenuUnconditional):
environments = {x.ID: x for x in sMkt.getGroup("Abyssal Environment").items}
items = chain(
sMkt.getGroup("MassiveEnvironments").items,
sMkt.getGroup("Non-Interactable Object").items)
sMkt.getGroup("MassiveEnvironments").items,
sMkt.getGroup("Non-Interactable Object").items)
for beacon in items:
if not beacon.isType('projected'):
continue
@@ -186,21 +202,24 @@ class AddEnvironmentEffect(ContextMenuUnconditional):
# Localized abyssal hazards
items = sMkt.getGroup("Abyssal Hazards").items
if items:
subdata = data.groups.setdefault('Localized', Group())
subdata = data.groups.setdefault(_t('Localized'), Group())
for beacon in sMkt.getGroup("Abyssal Hazards").items:
if not beacon.isType('projected'):
continue
# Localized effects, currently, have a name like "(size) (type) Cloud"
# Until this inevitably changes, do a simple split
name_parts = beacon.name.split(" ")
groups = (_t('Bioluminescence'), _t('Caustic'), _t('Filament'))
for group in groups:
if re.search(group, beacon.name):
key = group
break
else:
continue
key = name_parts[1].strip()
subsubdata = subdata.groups.setdefault(key, Group())
subsubdata.items.append(Entry(beacon.ID, beacon.name, beacon.name))
subdata.sort()
# PVP weather
data.items.append(Entry(49766, 'PvP Weather', 'PvP Weather'))
data.items.append(Entry(49766, _t('PvP Weather'), _t('PvP Weather')))
return data
@@ -214,4 +233,5 @@ class AddEnvironmentEffect(ContextMenuUnconditional):
data.sort()
return data
AddEnvironmentEffect.register()

View File

@@ -1,4 +1,5 @@
# noinspection PyPackageRequirements
import wx
import gui.globalEvents as GE
@@ -6,6 +7,8 @@ import gui.mainFrame
from gui.contextMenu import ContextMenuUnconditional
from service.fit import Fit
_t = wx.GetTranslation
class FactorReload(ContextMenuUnconditional):
@@ -20,7 +23,7 @@ class FactorReload(ContextMenuUnconditional):
return self.mainFrame.getActiveFit() is not None
def getText(self, callingWindow, itmContext):
return "Factor in Reload Time"
return _t("Factor in Reload Time")
def activate(self, callingWindow, fullContext, i):
fitIDs = Fit.getInstance().toggleFactorReload()

View File

@@ -1,12 +1,15 @@
# noinspection PyPackageRequirements
import wx
import gui.mainFrame
from gui import fitCommands as cmd
from gui.fitCommands.helpers import getSimilarFighters
from gui.contextMenu import ContextMenuCombined
from gui.fitCommands.helpers import getSimilarFighters
from service.fit import Fit
_t = wx.GetTranslation
class FighterAbilities(ContextMenuCombined):
@@ -27,7 +30,7 @@ class FighterAbilities(ContextMenuCombined):
return True
def getText(self, callingWindow, itmContext, mainItem, selection):
return "Abilities"
return _t("Abilities")
def addAbility(self, menu, ability):
label = ability.name
@@ -78,10 +81,10 @@ class FighterAbilities(ContextMenuCombined):
if fighter in container:
positions.append(container.index(fighter))
self.mainFrame.command.Submit(command(
fitID=fitID,
mainPosition=mainPosition,
positions=positions,
effectID=ability.effectID))
fitID=fitID,
mainPosition=mainPosition,
positions=positions,
effectID=ability.effectID))
FighterAbilities.register()

View File

@@ -1,9 +1,12 @@
# noinspection PyPackageRequirements
import wx
import gui.mainFrame
from gui.contextMenu import ContextMenuUnconditional
_t = wx.GetTranslation
class AddBrowsedFits(ContextMenuUnconditional):
@@ -16,7 +19,7 @@ class AddBrowsedFits(ContextMenuUnconditional):
return True
def getText(self, callingWindow, itmContext):
return 'Add Fit...'
return _t('Add Fit...')
def activate(self, callingWindow, fullContext, i):
from gui.fitBrowserLite import FitBrowserLiteDialog
@@ -24,7 +27,8 @@ class AddBrowsedFits(ContextMenuUnconditional):
'projected': 'Add Projected Fits',
'commandView': 'Add Command Fits',
'graphFitList': 'Add Fits to Graph',
'graphTgtList': 'Add Targets to Graph'}
'graphTgtList': 'Add Targets to Graph'
}
excludedFitIDs = callingWindow.getExistingFitIDs()
with FitBrowserLiteDialog(self.mainFrame, title=titles[fullContext[0]], excludedFitIDs=excludedFitIDs) as dlg:
if dlg.ShowModal() == wx.ID_OK:

View File

@@ -1,4 +1,5 @@
# noinspection PyPackageRequirements
import wx
import gui.mainFrame
@@ -6,6 +7,8 @@ from gui.builtinViews.emptyView import BlankPage
from gui.contextMenu import ContextMenuUnconditional
from service.fit import Fit
_t = wx.GetTranslation
class AddCurrentlyOpenFit(ContextMenuUnconditional):
@@ -23,7 +26,7 @@ class AddCurrentlyOpenFit(ContextMenuUnconditional):
return True
def getText(self, callingWindow, itmContext):
return 'Add Currently Open Fit'
return _t('Add Currently Open Fit')
def getSubMenu(self, callingWindow, context, rootMenu, i, pitem):
self.fitLookup = {}

View File

@@ -1,4 +1,5 @@
# noinspection PyPackageRequirements
import wx
import gui.mainFrame
@@ -6,6 +7,8 @@ from graphs.wrapper import BaseWrapper
from gui.builtinShipBrowser.events import FitSelected
from gui.contextMenu import ContextMenuSingle
_t = wx.GetTranslation
class OpenFitInNewTab(ContextMenuSingle):
@@ -31,7 +34,7 @@ class OpenFitInNewTab(ContextMenuSingle):
return True
def getText(self, callingWindow, itmContext, mainItem):
return "Open Fit in New Tab"
return _t("Open Fit in New Tab")
def activate(self, callingWindow, fullContext, mainItem, i):
if isinstance(mainItem, BaseWrapper):

View File

@@ -8,18 +8,18 @@ from eos.const import FitSystemSecurity
from gui.contextMenu import ContextMenuUnconditional
from service.fit import Fit
optionMap = OrderedDict((
('High Security', FitSystemSecurity.HISEC),
('Low Security', FitSystemSecurity.LOWSEC),
('Null Security', FitSystemSecurity.NULLSEC),
('W-Space', FitSystemSecurity.WSPACE)))
_t = wx.GetTranslation
class FitSystemSecurityMenu(ContextMenuUnconditional):
def __init__(self):
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
self.optionMap = OrderedDict((
(_t('High Security'), FitSystemSecurity.HISEC),
(_t('Low Security'), FitSystemSecurity.LOWSEC),
(_t('Null Security'), FitSystemSecurity.NULLSEC),
(_t('W-Space'), FitSystemSecurity.WSPACE)))
def display(self, callingWindow, srcContext):
if srcContext != "fittingShip":
@@ -34,7 +34,7 @@ class FitSystemSecurityMenu(ContextMenuUnconditional):
return True
def getText(self, callingWindow, itmContext):
return "Citadel System Security"
return _t("Citadel System Security")
def addOption(self, menu, optionLabel):
id = ContextMenuUnconditional.nextID()
@@ -49,7 +49,7 @@ class FitSystemSecurityMenu(ContextMenuUnconditional):
msw = True if "wxMSW" in wx.PlatformInfo else False
self.optionIds = {}
sub = wx.Menu()
for optionLabel, optionValue in optionMap.items():
for optionLabel, optionValue in self.optionMap.items():
menuItem = self.addOption(rootMenu if msw else sub, optionLabel)
sub.Append(menuItem)
menuItem.Check(fit.getSystemSecurity() == optionValue)
@@ -58,10 +58,10 @@ class FitSystemSecurityMenu(ContextMenuUnconditional):
def handleMode(self, event):
optionLabel = self.optionIds[event.Id]
optionValue = optionMap[optionLabel]
optionValue = self.optionMap[optionLabel]
self.mainFrame.command.Submit(cmd.GuiChangeFitSystemSecurityCommand(
fitID=self.mainFrame.getActiveFit(),
secStatus=optionValue))
fitID=self.mainFrame.getActiveFit(),
secStatus=optionValue))
FitSystemSecurityMenu.register()

View File

@@ -1,4 +1,5 @@
# noinspection PyPackageRequirements
import wx
import gui.globalEvents as GE
@@ -6,6 +7,8 @@ import gui.mainFrame
from gui.contextMenu import ContextMenuUnconditional
from service.settings import GraphSettings
_t = wx.GetTranslation
class GraphDmgApplyProjectedMenu(ContextMenuUnconditional):
@@ -17,7 +20,7 @@ class GraphDmgApplyProjectedMenu(ContextMenuUnconditional):
return srcContext == 'dmgStatsGraph'
def getText(self, callingWindow, itmContext):
return 'Apply Projected Items'
return _t('Apply Projected Items')
def activate(self, callingWindow, fullContext, i):
self.settings.set('applyProjected', not self.settings.get('applyProjected'))

View File

@@ -1,6 +1,5 @@
from collections import OrderedDict
# noinspection PyPackageRequirements
import wx
import gui.globalEvents as GE
@@ -9,6 +8,10 @@ from gui.contextMenu import ContextMenuUnconditional
from service.const import GraphDpsDroneMode
from service.settings import GraphSettings
# noinspection PyPackageRequirements
_t = wx.GetTranslation
class GraphDmgDroneModeMenu(ContextMenuUnconditional):
@@ -20,7 +23,7 @@ class GraphDmgDroneModeMenu(ContextMenuUnconditional):
return srcContext == 'dmgStatsGraph'
def getText(self, callingWindow, itmContext):
return 'Drone Mode'
return _t('Drone Mode')
def handleModeSwitch(self, event):
option = self.idOptionMap[event.Id]
@@ -37,9 +40,9 @@ class GraphDmgDroneModeMenu(ContextMenuUnconditional):
bindmenu = m
self.idOptionMap = {}
optionMap = OrderedDict([
(GraphDpsDroneMode.auto, 'Auto'),
(GraphDpsDroneMode.followTarget, 'Stick to Target'),
(GraphDpsDroneMode.followAttacker, 'Stick to Attacker')])
(GraphDpsDroneMode.auto, _t('Auto')),
(GraphDpsDroneMode.followTarget, _t('Stick to Target')),
(GraphDpsDroneMode.followAttacker, _t('Stick to Attacker'))])
for option, label in optionMap.items():
menuId = ContextMenuUnconditional.nextID()
item = wx.MenuItem(m, menuId, label, kind=wx.ITEM_CHECK)

View File

@@ -1,4 +1,5 @@
# noinspection PyPackageRequirements
import wx
import gui.globalEvents as GE
@@ -6,6 +7,8 @@ import gui.mainFrame
from gui.contextMenu import ContextMenuUnconditional
from service.settings import GraphSettings
_t = wx.GetTranslation
class GraphDmgIgnoreResistsMenu(ContextMenuUnconditional):
@@ -17,7 +20,7 @@ class GraphDmgIgnoreResistsMenu(ContextMenuUnconditional):
return srcContext == 'dmgStatsGraph'
def getText(self, callingWindow, itmContext):
return 'Ignore Target Resists'
return _t('Ignore Target Resists')
def activate(self, callingWindow, fullContext, i):
self.settings.set('ignoreResists', not self.settings.get('ignoreResists'))

View File

@@ -1,4 +1,5 @@
# noinspection PyPackageRequirements
import wx
import gui.globalEvents as GE
@@ -6,6 +7,8 @@ import gui.mainFrame
from gui.contextMenu import ContextMenuUnconditional
from service.settings import GraphSettings
_t = wx.GetTranslation
class GraphIgnoreDcrMenu(ContextMenuUnconditional):
@@ -17,7 +20,7 @@ class GraphIgnoreDcrMenu(ContextMenuUnconditional):
return srcContext in ('dmgStatsGraph', 'remoteRepsGraph', 'ewarStatsGraph')
def getText(self, callingWindow, itmContext):
return 'Ignore Drone Control Range'
return _t('Ignore Drone Control Range')
def activate(self, callingWindow, fullContext, i):
self.settings.set('ignoreDCR', not self.settings.get('ignoreDCR'))

View File

@@ -1,4 +1,5 @@
# noinspection PyPackageRequirements
import wx
import gui.mainFrame
@@ -7,6 +8,8 @@ from gui.contextMenu import ContextMenuSingle
from service.ammo import Ammo
from service.market import Market
_t = wx.GetTranslation
class GraphFitAmmoPicker(ContextMenuSingle):
@@ -23,7 +26,7 @@ class GraphFitAmmoPicker(ContextMenuSingle):
return True
def getText(self, callingWindow, itmContext, mainItem):
return 'Plot with Different Ammo...'
return _t('Plot with Different Ammo...')
def activate(self, callingWindow, fullContext, mainItem, i):
AmmoPickerFrame.openOne(callingWindow, mainItem.item, forceReopen=True)
@@ -73,7 +76,6 @@ class AmmoPickerFrame(AuxiliaryDialog):
class AmmoPickerContents(wx.ScrolledCanvas):
indent = 15
def __init__(self, parent, fit):

View File

@@ -1,4 +1,5 @@
# noinspection PyPackageRequirements
import wx
import gui.globalEvents as GE
@@ -6,6 +7,8 @@ import gui.mainFrame
from gui.contextMenu import ContextMenuUnconditional
from service.settings import GraphSettings
_t = wx.GetTranslation
class GraphIgnoreLockRangeMenu(ContextMenuUnconditional):
@@ -17,7 +20,7 @@ class GraphIgnoreLockRangeMenu(ContextMenuUnconditional):
return srcContext in ('dmgStatsGraph', 'remoteRepsGraph', 'ewarStatsGraph')
def getText(self, callingWindow, itmContext):
return 'Ignore Lock Range'
return _t('Ignore Lock Range')
def activate(self, callingWindow, fullContext, i):
self.settings.set('ignoreLockRange', not self.settings.get('ignoreLockRange'))

View File

@@ -1,11 +1,13 @@
# noinspection PyPackageRequirements
import wx
from gui.contextMenu import ContextMenuUnconditional
from service.market import Market
from service.implantSet import ImplantSets as UserImplantSets
from service.precalcImplantSet import PrecalcedImplantSets
_t = wx.GetTranslation
class ImplantSetApply(ContextMenuUnconditional):
@@ -20,7 +22,7 @@ class ImplantSetApply(ContextMenuUnconditional):
return srcContext in ("implantItemMisc", "implantEditor")
def getText(self, callingWindow, context):
return "Apply Implant Set"
return _t("Apply Implant Set")
def _addSeparator(self, m, text):
id_ = ContextMenuUnconditional.nextID()

View File

@@ -4,6 +4,8 @@ import gui.mainFrame
from gui.contextMenu import ContextMenuUnconditional
from service.fit import Fit
_t = wx.GetTranslation
class ImplantSetSave(ContextMenuUnconditional):
@@ -22,7 +24,7 @@ class ImplantSetSave(ContextMenuUnconditional):
return True
def getText(self, callingWindow, context):
return 'Save as New Implant Set'
return _t('Save as New Implant Set')
def activate(self, callingWindow, fullContext, i):
with NameDialog(self.mainFrame, '') as dlg:
@@ -40,13 +42,13 @@ ImplantSetSave.register()
class NameDialog(wx.Dialog):
def __init__(self, parent, value):
super().__init__(parent, title='New Implant Set', style=wx.DEFAULT_DIALOG_STYLE)
super().__init__(parent, title=_t('New Implant Set'), style=wx.DEFAULT_DIALOG_STYLE)
self.SetMinSize((346, 156))
bSizer1 = wx.BoxSizer(wx.VERTICAL)
bSizer2 = wx.BoxSizer(wx.VERTICAL)
text = wx.StaticText(self, wx.ID_ANY, 'Enter a name for your new Implant Set:')
text = wx.StaticText(self, wx.ID_ANY, _t('Enter a name for your new Implant Set:'))
bSizer2.Add(text, 0)
bSizer1.Add(bSizer2, 0, wx.ALL, 10)

View File

@@ -1,6 +1,5 @@
import re
# noinspection PyPackageRequirements
import wx
import gui.fitCommands as cmd
@@ -12,6 +11,10 @@ from eos.saveddata.fit import Fit as es_Fit
from gui.contextMenu import ContextMenuSingle
from service.fit import Fit
# noinspection PyPackageRequirements
_t = wx.GetTranslation
class ChangeItemAmount(ContextMenuSingle):
@@ -28,7 +31,7 @@ class ChangeItemAmount(ContextMenuSingle):
return True
def getText(self, callingWindow, itmContext, mainItem):
return "Change {0} Quantity".format(itmContext)
return _t("Change {0} Quantity").format(itmContext)
def activate(self, callingWindow, fullContext, mainItem, i):
fitID = self.mainFrame.getActiveFit()
@@ -54,30 +57,30 @@ class ChangeItemAmount(ContextMenuSingle):
if isinstance(mainItem, es_Cargo):
self.mainFrame.command.Submit(cmd.GuiChangeCargoAmountCommand(
fitID=fitID, itemID=mainItem.itemID, amount=cleanInput))
fitID=fitID, itemID=mainItem.itemID, amount=cleanInput))
elif isinstance(mainItem, Drone):
if srcContext == "projectedDrone":
self.mainFrame.command.Submit(cmd.GuiChangeProjectedDroneAmountCommand(
fitID=fitID, itemID=mainItem.itemID, amount=cleanInput))
fitID=fitID, itemID=mainItem.itemID, amount=cleanInput))
else:
if mainItem in fit.drones:
position = fit.drones.index(mainItem)
self.mainFrame.command.Submit(cmd.GuiChangeLocalDroneAmountCommand(
fitID=fitID, position=position, amount=cleanInput))
fitID=fitID, position=position, amount=cleanInput))
elif isinstance(mainItem, es_Fit):
self.mainFrame.command.Submit(cmd.GuiChangeProjectedFitAmountCommand(
fitID=fitID, projectedFitID=mainItem.ID, amount=cleanInput))
fitID=fitID, projectedFitID=mainItem.ID, amount=cleanInput))
elif isinstance(mainItem, es_Fighter):
if srcContext == "projectedFighter":
if mainItem in fit.projectedFighters:
position = fit.projectedFighters.index(mainItem)
self.mainFrame.command.Submit(cmd.GuiChangeProjectedFighterAmountCommand(
fitID=fitID, position=position, amount=cleanInput))
fitID=fitID, position=position, amount=cleanInput))
else:
if mainItem in fit.fighters:
position = fit.fighters.index(mainItem)
self.mainFrame.command.Submit(cmd.GuiChangeLocalFighterAmountCommand(
fitID=fitID, position=position, amount=cleanInput))
fitID=fitID, position=position, amount=cleanInput))
ChangeItemAmount.register()
@@ -86,13 +89,13 @@ ChangeItemAmount.register()
class AmountChanger(wx.Dialog):
def __init__(self, parent, value, limits=None):
super().__init__(parent, title="Change Amount", style=wx.DEFAULT_DIALOG_STYLE)
super().__init__(parent, title=_t("Change Amount"), style=wx.DEFAULT_DIALOG_STYLE)
self.SetMinSize((346, 156))
bSizer1 = wx.BoxSizer(wx.VERTICAL)
bSizer2 = wx.BoxSizer(wx.VERTICAL)
text = wx.StaticText(self, wx.ID_ANY, "New Amount:" if limits is None else "New Amount ({}-{})".format(*limits))
text = wx.StaticText(self, wx.ID_ANY, _t("New Amount:") if limits is None else _t("New Amount ({}-{})").format(*limits))
bSizer2.Add(text, 0)
bSizer1.Add(bSizer2, 0, wx.ALL, 10)

View File

@@ -1,10 +1,13 @@
import wx
import gui.fitCommands as cmd
import gui.mainFrame
from gui.contextMenu import ContextMenuSingle
_t = wx.GetTranslation
class FillWithItem(ContextMenuSingle):
visibilitySetting = 'moduleFill'
def __init__(self):
@@ -26,12 +29,12 @@ class FillWithItem(ContextMenuSingle):
return True
def getText(self, callingWindow, itmContext, mainItem):
return "Fill With Module"
return _t("Fill With Module")
def activate(self, callingWindow, fullContext, mainItem, i):
self.mainFrame.command.Submit(cmd.GuiFillWithNewLocalModulesCommand(
fitID=self.mainFrame.getActiveFit(),
itemID=int(mainItem.ID)))
fitID=self.mainFrame.getActiveFit(),
itemID=int(mainItem.ID)))
FillWithItem.register()

View File

@@ -1,7 +1,11 @@
import wx
import gui.mainFrame
from gui.contextMenu import ContextMenuSingle
from service.market import Market
_t = wx.GetTranslation
class JumpToMarketItem(ContextMenuSingle):
def __init__(self):
@@ -37,7 +41,7 @@ class JumpToMarketItem(ContextMenuSingle):
return doit
def getText(self, callingWindow, itmContext, mainItem):
return "{0} Market Group".format(itmContext if itmContext is not None else "Item")
return _t("{0} Market Group").format(itmContext if itmContext is not None else _t("Item"))
def activate(self, callingWindow, fullContext, mainItem, i):
srcContext = fullContext[0]

View File

@@ -1,11 +1,14 @@
import wx
import gui.fitCommands as cmd
import gui.mainFrame
from gui.contextMenu import ContextMenuSingle
from service.fit import Fit
_t = wx.GetTranslation
class ProjectItem(ContextMenuSingle):
visibilitySetting = 'project'
def __init__(self):
@@ -28,7 +31,7 @@ class ProjectItem(ContextMenuSingle):
return mainItem.isType("projected")
def getText(self, callingWindow, itmContext, mainItem):
return "Project {0} onto Fit".format(itmContext)
return _t("Project {0} onto Fit").format(itmContext)
def activate(self, callingWindow, fullContext, mainItem, i):
fitID = self.mainFrame.getActiveFit()

View File

@@ -1,6 +1,5 @@
import re
# noinspection PyPackageRequirements
import wx
import gui.fitCommands as cmd
@@ -12,6 +11,10 @@ from gui.contextMenu import ContextMenuCombined
from gui.fitCommands.helpers import getSimilarFighters, getSimilarModPositions
from service.fit import Fit
# noinspection PyPackageRequirements
_t = wx.GetTranslation
class ChangeItemProjectionRange(ContextMenuCombined):
@@ -28,7 +31,7 @@ class ChangeItemProjectionRange(ContextMenuCombined):
return True
def getText(self, callingWindow, itmContext, mainItem, selection):
return 'Change {} Range'.format(itmContext)
return _t('Change {} Range').format(itmContext)
def activate(self, callingWindow, fullContext, mainItem, selection, i):
fitID = self.mainFrame.getActiveFit()
@@ -63,7 +66,7 @@ class ChangeItemProjectionRange(ContextMenuCombined):
fit = Fit.getInstance().getFit(fitID)
items = getSimilarFighters(fit.projectedFighters, mainItem)
self.mainFrame.command.Submit(cmd.GuiChangeProjectedItemsProjectionRangeCommand(
fitID=fitID, items=items, projectionRange=newRange))
fitID=fitID, items=items, projectionRange=newRange))
ChangeItemProjectionRange.register()

View File

@@ -12,6 +12,8 @@ from gui.contextMenu import ContextMenuCombined
from gui.fitCommands.helpers import getSimilarFighters, getSimilarModPositions
from service.fit import Fit
_t = wx.GetTranslation
class RemoveItem(ContextMenuCombined):
@@ -20,13 +22,13 @@ class RemoveItem(ContextMenuCombined):
def display(self, callingWindow, srcContext, mainItem, selection):
if srcContext not in (
"fittingModule", "droneItem",
"implantItem", "boosterItem",
"projectedModule", "cargoItem",
"projectedFit", "projectedDrone",
"fighterItem", "projectedFighter",
"commandFit", "graphFitList",
"graphTgtList"
"fittingModule", "droneItem",
"implantItem", "boosterItem",
"projectedModule", "cargoItem",
"projectedFit", "projectedDrone",
"fighterItem", "projectedFighter",
"commandFit", "graphFitList",
"graphTgtList"
):
return False
@@ -37,9 +39,9 @@ class RemoveItem(ContextMenuCombined):
return True
def getText(self, callingWindow, itmContext, mainItem, selection):
return 'Remove {}{}'.format(
itmContext if itmContext is not None else 'Item',
' Stack' if self.srcContext in ('droneItem', 'projectedDrone', 'cargoItem', 'projectedFit') else '')
return _t('Remove {item}{stack}').format(
item=itmContext if itmContext is not None else _t('Item'),
stack=_t(' Stack') if self.srcContext in ('droneItem', 'projectedDrone', 'cargoItem', 'projectedFit') else '')
def activate(self, callingWindow, fullContext, mainItem, selection, i):
handlerMap = {
@@ -55,7 +57,8 @@ class RemoveItem(ContextMenuCombined):
'projectedFighter': self.__handleProjectedItem,
'commandFit': self.__handleCommandFit,
'graphFitList': self.__handleGraphItem,
'graphTgtList': self.__handleGraphItem}
'graphTgtList': self.__handleGraphItem
}
srcContext = fullContext[0]
handler = handlerMap.get(srcContext)
if handler is None:
@@ -73,7 +76,7 @@ class RemoveItem(ContextMenuCombined):
if mod in fit.modules:
positions.append(fit.modules.index(mod))
self.mainFrame.command.Submit(cmd.GuiRemoveLocalModuleCommand(
fitID=fitID, positions=positions))
fitID=fitID, positions=positions))
def __handleDrone(self, callingWindow, mainItem, selection):
fitID = self.mainFrame.getActiveFit()
@@ -83,7 +86,7 @@ class RemoveItem(ContextMenuCombined):
if drone in fit.drones:
positions.append(fit.drones.index(drone))
self.mainFrame.command.Submit(cmd.GuiRemoveLocalDronesCommand(
fitID=fitID, positions=positions, amount=math.inf))
fitID=fitID, positions=positions, amount=math.inf))
def __handleFighter(self, callingWindow, mainItem, selection):
fitID = self.mainFrame.getActiveFit()
@@ -97,7 +100,7 @@ class RemoveItem(ContextMenuCombined):
if fighter in fit.fighters:
positions.append(fit.fighters.index(fighter))
self.mainFrame.command.Submit(cmd.GuiRemoveLocalFightersCommand(
fitID=fitID, positions=positions))
fitID=fitID, positions=positions))
def __handleImplant(self, callingWindow, mainItem, selection):
fitID = self.mainFrame.getActiveFit()
@@ -107,7 +110,7 @@ class RemoveItem(ContextMenuCombined):
if implant in fit.implants:
positions.append(fit.implants.index(implant))
self.mainFrame.command.Submit(cmd.GuiRemoveImplantsCommand(
fitID=fitID, positions=positions))
fitID=fitID, positions=positions))
def __handleBooster(self, callingWindow, mainItem, selection):
fitID = self.mainFrame.getActiveFit()
@@ -117,19 +120,19 @@ class RemoveItem(ContextMenuCombined):
if booster in fit.boosters:
positions.append(fit.boosters.index(booster))
self.mainFrame.command.Submit(cmd.GuiRemoveBoostersCommand(
fitID=fitID, positions=positions))
fitID=fitID, positions=positions))
def __handleCargo(self, callingWindow, mainItem, selection):
fitID = self.mainFrame.getActiveFit()
itemIDs = [c.itemID for c in selection]
self.mainFrame.command.Submit(cmd.GuiRemoveCargosCommand(
fitID=fitID, itemIDs=itemIDs))
fitID=fitID, itemIDs=itemIDs))
def __handleProjectedItem(self, callingWindow, mainItem, selection):
fitID = self.mainFrame.getActiveFit()
if isinstance(mainItem, EosFit):
self.mainFrame.command.Submit(cmd.GuiRemoveProjectedItemsCommand(
fitID=fitID, items=selection, amount=math.inf))
fitID=fitID, items=selection, amount=math.inf))
elif isinstance(mainItem, EosModule):
if wx.GetMouseState().GetModifiers() in (wx.MOD_ALT, wx.MOD_CONTROL):
fit = Fit.getInstance().getFit(fitID)
@@ -138,10 +141,10 @@ class RemoveItem(ContextMenuCombined):
else:
items = selection
self.mainFrame.command.Submit(cmd.GuiRemoveProjectedItemsCommand(
fitID=fitID, items=items, amount=math.inf))
fitID=fitID, items=items, amount=math.inf))
elif isinstance(mainItem, EosDrone):
self.mainFrame.command.Submit(cmd.GuiRemoveProjectedItemsCommand(
fitID=fitID, items=selection, amount=math.inf))
fitID=fitID, items=selection, amount=math.inf))
elif isinstance(mainItem, EosFighter):
if wx.GetMouseState().GetModifiers() in (wx.MOD_ALT, wx.MOD_CONTROL):
fit = Fit.getInstance().getFit(fitID)
@@ -149,16 +152,16 @@ class RemoveItem(ContextMenuCombined):
else:
items = selection
self.mainFrame.command.Submit(cmd.GuiRemoveProjectedItemsCommand(
fitID=fitID, items=items, amount=math.inf))
fitID=fitID, items=items, amount=math.inf))
else:
self.mainFrame.command.Submit(cmd.GuiRemoveProjectedItemsCommand(
fitID=fitID, items=selection, amount=math.inf))
fitID=fitID, items=selection, amount=math.inf))
def __handleCommandFit(self, callingWindow, mainItem, selection):
fitID = self.mainFrame.getActiveFit()
commandFitIDs = [cf.ID for cf in selection]
self.mainFrame.command.Submit(cmd.GuiRemoveCommandFitsCommand(
fitID=fitID, commandFitIDs=commandFitIDs))
fitID=fitID, commandFitIDs=commandFitIDs))
def __handleGraphItem(self, callingWindow, mainItem, selection):
callingWindow.removeWrappers(selection)

View File

@@ -1,4 +1,5 @@
# noinspection PyPackageRequirements
import wx
import gui.mainFrame
@@ -6,6 +7,8 @@ from gui.contextMenu import ContextMenuSingle
from gui.itemStats import ItemStatsFrame
from service.fit import Fit
_t = wx.GetTranslation
class ItemStats(ContextMenuSingle):
def __init__(self):
@@ -13,16 +16,16 @@ class ItemStats(ContextMenuSingle):
def display(self, callingWindow, srcContext, mainItem):
if srcContext not in (
"marketItemGroup", "marketItemMisc",
"fittingModule", "fittingCharge",
"fittingShip", "baseShip",
"cargoItem", "droneItem",
"implantItem", "boosterItem",
"skillItem", "projectedModule",
"projectedDrone", "projectedCharge",
"itemStats", "fighterItem",
"implantItemChar", "projectedFighter",
"fittingMode"
"marketItemGroup", "marketItemMisc",
"fittingModule", "fittingCharge",
"fittingShip", "baseShip",
"cargoItem", "droneItem",
"implantItem", "boosterItem",
"skillItem", "projectedModule",
"projectedDrone", "projectedCharge",
"itemStats", "fighterItem",
"implantItemChar", "projectedFighter",
"fittingMode"
):
return False
@@ -32,7 +35,7 @@ class ItemStats(ContextMenuSingle):
return True
def getText(self, callingWindow, itmContext, mainItem):
return "{} Stats".format(itmContext if itmContext is not None else "Item")
return _t("{} Stats").format(itmContext if itmContext is not None else _t("Item"))
def activate(self, callingWindow, fullContext, mainItem, i):
srcContext = fullContext[0]

View File

@@ -1,16 +1,18 @@
# noinspection PyPackageRequirements
import wx
import gui.fitCommands as cmd
import gui.mainFrame
from gui.contextMenu import ContextMenuCombined
from gui.fitCommands.helpers import getSimilarModPositions, getSimilarFighters
from gui.fitCommands.helpers import getSimilarFighters, getSimilarModPositions
from service.fit import Fit
from service.market import Market
_t = wx.GetTranslation
class ChangeItemToVariation(ContextMenuCombined):
visibilitySetting = 'metaSwap'
def __init__(self):
@@ -18,15 +20,15 @@ class ChangeItemToVariation(ContextMenuCombined):
def display(self, callingWindow, srcContext, mainItem, selection):
if self.mainFrame.getActiveFit() is None or srcContext not in (
'fittingModule',
'droneItem',
'fighterItem',
'boosterItem',
'implantItem',
'cargoItem',
'projectedModule',
'projectedDrone',
'projectedFighter'
'fittingModule',
'droneItem',
'fighterItem',
'boosterItem',
'implantItem',
'cargoItem',
'projectedModule',
'projectedDrone',
'projectedFighter'
):
return False
@@ -44,7 +46,7 @@ class ChangeItemToVariation(ContextMenuCombined):
return True
def getText(self, callingWindow, itmContext, mainItem, selection):
return 'Variations'
return _t('Variations')
def getSubMenu(self, callingWindow, context, mainItem, selection, rootMenu, i, pitem):
self.moduleLookup = {}
@@ -60,7 +62,8 @@ class ChangeItemToVariation(ContextMenuCombined):
# We want deadspace before officer mods
5: 6, 6: 5,
# For structures we want t1-t2-faction
54: 52, 52: 54}
54: 52, 52: 54
}
metaGroup = sMkt.getMetaGroupByItem(x)
return remap.get(metaGroup.ID, metaGroup.ID) if metaGroup is not None else 0
@@ -86,8 +89,8 @@ class ChangeItemToVariation(ContextMenuCombined):
# Do not show abyssal items
items = list(
i for i in self.mainVariations
if sMkt.getMetaGroupByItem(i) is None or sMkt.getMetaGroupByItem(i).ID != 15)
i for i in self.mainVariations
if sMkt.getMetaGroupByItem(i) is None or sMkt.getMetaGroupByItem(i).ID != 15)
# Sort items by metalevel, and group within that metalevel
# Sort all items by name first
items.sort(key=lambda x: x.name)
@@ -143,7 +146,8 @@ class ChangeItemToVariation(ContextMenuCombined):
'boosterItem': self.__handleBooster,
'projectedModule': self.__handleProjectedModule,
'projectedDrone': self.__handleProjectedDrone,
'projectedFighter': self.__handleProjectedFighter}
'projectedFighter': self.__handleProjectedFighter
}
handler = handlerMap.get(context)
if handler is None:
return
@@ -169,7 +173,7 @@ class ChangeItemToVariation(ContextMenuCombined):
if modVariations == self.mainVariations:
positions.append(fit.modules.index(mod))
self.mainFrame.command.Submit(cmd.GuiChangeLocalModuleMetasCommand(
fitID=fitID, positions=positions, newItemID=varItem.ID))
fitID=fitID, positions=positions, newItemID=varItem.ID))
def __handleDrone(self, varItem):
fitID = self.mainFrame.getActiveFit()
@@ -186,7 +190,7 @@ class ChangeItemToVariation(ContextMenuCombined):
if droneVariations == self.mainVariations:
positions.append(fit.drones.index(drone))
self.mainFrame.command.Submit(cmd.GuiChangeLocalDroneMetasCommand(
fitID=fitID, positions=positions, newItemID=varItem.ID))
fitID=fitID, positions=positions, newItemID=varItem.ID))
def __handleFighter(self, varItem):
fitID = self.mainFrame.getActiveFit()
@@ -207,7 +211,7 @@ class ChangeItemToVariation(ContextMenuCombined):
if fighterVariations == self.mainVariations:
positions.append(fit.fighters.index(fighter))
self.mainFrame.command.Submit(cmd.GuiChangeLocalFighterMetasCommand(
fitID=fitID, positions=positions, newItemID=varItem.ID))
fitID=fitID, positions=positions, newItemID=varItem.ID))
def __handleCargo(self, varItem):
fitID = self.mainFrame.getActiveFit()
@@ -221,7 +225,7 @@ class ChangeItemToVariation(ContextMenuCombined):
if cargoVariations == self.mainVariations:
itemIDs.append(cargo.itemID)
self.mainFrame.command.Submit(cmd.GuiChangeCargoMetasCommand(
fitID=fitID, itemIDs=itemIDs, newItemID=varItem.ID))
fitID=fitID, itemIDs=itemIDs, newItemID=varItem.ID))
def __handleImplant(self, varItem):
fitID = self.mainFrame.getActiveFit()
@@ -230,7 +234,7 @@ class ChangeItemToVariation(ContextMenuCombined):
if implant in fit.implants:
position = fit.implants.index(implant)
self.mainFrame.command.Submit(cmd.GuiChangeImplantMetaCommand(
fitID=fitID, position=position, newItemID=varItem.ID))
fitID=fitID, position=position, newItemID=varItem.ID))
def __handleBooster(self, varItem):
fitID = self.mainFrame.getActiveFit()
@@ -239,7 +243,7 @@ class ChangeItemToVariation(ContextMenuCombined):
if booster in fit.boosters:
position = fit.boosters.index(booster)
self.mainFrame.command.Submit(cmd.GuiChangeBoosterMetaCommand(
fitID=fitID, position=position, newItemID=varItem.ID))
fitID=fitID, position=position, newItemID=varItem.ID))
def __handleProjectedModule(self, varItem):
fitID = self.mainFrame.getActiveFit()
@@ -259,7 +263,7 @@ class ChangeItemToVariation(ContextMenuCombined):
if modVariations == self.mainVariations:
positions.append(fit.projectedModules.index(mod))
self.mainFrame.command.Submit(cmd.GuiChangeProjectedModuleMetasCommand(
fitID=fitID, positions=positions, newItemID=varItem.ID))
fitID=fitID, positions=positions, newItemID=varItem.ID))
def __handleProjectedDrone(self, varItem):
fitID = self.mainFrame.getActiveFit()
@@ -276,7 +280,7 @@ class ChangeItemToVariation(ContextMenuCombined):
if droneVariations == self.mainVariations:
itemIDs.append(drone.itemID)
self.mainFrame.command.Submit(cmd.GuiChangeProjectedDroneMetasCommand(
fitID=fitID, itemIDs=itemIDs, newItemID=varItem.ID))
fitID=fitID, itemIDs=itemIDs, newItemID=varItem.ID))
def __handleProjectedFighter(self, varItem):
fitID = self.mainFrame.getActiveFit()
@@ -297,7 +301,7 @@ class ChangeItemToVariation(ContextMenuCombined):
if fighterVariations == self.mainVariations:
positions.append(fit.projectedFighters.index(fighter))
self.mainFrame.command.Submit(cmd.GuiChangeProjectedFighterMetasCommand(
fitID=fitID, positions=positions, newItemID=varItem.ID))
fitID=fitID, positions=positions, newItemID=varItem.ID))
ChangeItemToVariation.register()

View File

@@ -1,4 +1,5 @@
# noinspection PyPackageRequirements
import wx
import gui.fitCommands as cmd
@@ -9,6 +10,8 @@ from gui.fitCommands.helpers import getSimilarModPositions
from service.ammo import Ammo
from service.fit import Fit
_t = wx.GetTranslation
class ChangeModuleAmmo(ContextMenuCombined):
@@ -16,6 +19,14 @@ class ChangeModuleAmmo(ContextMenuCombined):
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
# Format: {type ID: set(loadable, charges)}
self.loadableChargesCache = {}
# Translations for the missile categories, as the text here is auto-generated via damage attributes
self.ddMissileChargeCatTrans = {
'em': _t('EM'),
'thermal': _t('Thermal'),
'explosive': _t('Explosive'),
'kinetic': _t('Kinetic'),
'mixed': _t('Mixed')
}
def display(self, callingWindow, srcContext, mainItem, selection):
if srcContext not in ('fittingModule', 'projectedModule'):
@@ -34,7 +45,7 @@ class ChangeModuleAmmo(ContextMenuCombined):
return True
def getText(self, callingWindow, itmContext, mainItem, selection):
return 'Charge'
return _t('Charge')
def _getAmmo(self, mod):
if mod.itemID is None:
@@ -45,7 +56,7 @@ class ChangeModuleAmmo(ContextMenuCombined):
def _addCharge(self, menu, charge):
id_ = ContextMenuCombined.nextID()
name = charge.name if charge is not None else 'Empty'
name = charge.name if charge is not None else _t('Empty')
self.chargeEventMap[id_] = charge
item = wx.MenuItem(menu, id_, name)
menu.Bind(wx.EVT_MENU, self.handleAmmoSwitch, item)
@@ -68,7 +79,7 @@ class ChangeModuleAmmo(ContextMenuCombined):
self.chargeEventMap = {}
modType, chargeDict = Ammo.getInstance().getModuleStructuredAmmo(self.module, ammo=self.mainCharges)
if modType == 'ddTurret':
self._addSeparator(menu, 'Long Range')
self._addSeparator(menu, _t('Long Range'))
menuItems = []
for charges in chargeDict.values():
if len(charges) == 1:
@@ -80,25 +91,28 @@ class ChangeModuleAmmo(ContextMenuCombined):
subMenu = wx.Menu()
subMenu.Bind(wx.EVT_MENU, self.handleAmmoSwitch)
menuItem.SetSubMenu(subMenu)
self._addSeparator(subMenu, 'Less Damage')
self._addSeparator(subMenu, _t('Less Damage'))
for charge in charges:
subMenu.Append(self._addCharge(rootMenu if msw else subMenu, charge))
self._addSeparator(subMenu, 'More Damage')
self._addSeparator(subMenu, _t('More Damage'))
for menuItem in menuItems:
menu.Append(menuItem)
self._addSeparator(menu, 'Short Range')
self._addSeparator(menu, _t('Short Range'))
elif modType == 'ddMissile':
menuItems = []
for chargeCatName, charges in chargeDict.items():
menuItem = wx.MenuItem(menu, wx.ID_ANY, chargeCatName.capitalize())
menuItem = wx.MenuItem(menu, wx.ID_ANY, self.ddMissileChargeCatTrans.get(chargeCatName, chargeCatName))
bitmap = BitmapLoader.getBitmap("%s_small" % chargeCatName, "gui")
if bitmap is not None:
menuItem.SetBitmap(bitmap)
menuItems.append(menuItem)
subMenu = wx.Menu()
subMenu.Bind(wx.EVT_MENU, self.handleAmmoSwitch)
menuItem.SetSubMenu(subMenu)
self._addSeparator(subMenu, 'Less Damage')
self._addSeparator(subMenu, _t('Less Damage'))
for charge in charges:
subMenu.Append(self._addCharge(rootMenu if msw else subMenu, charge))
self._addSeparator(subMenu, 'More Damage')
self._addSeparator(subMenu, _t('More Damage'))
for menuItem in menuItems:
menu.Append(menuItem)
elif modType == 'general':
@@ -129,9 +143,9 @@ class ChangeModuleAmmo(ContextMenuCombined):
return
positions = getSimilarModPositions(modContainer, self.module)
self.mainFrame.command.Submit(command(
fitID=fitID,
positions=positions,
chargeItemID=charge.ID if charge is not None else None))
fitID=fitID,
positions=positions,
chargeItemID=charge.ID if charge is not None else None))
else:
if self.srcContext == 'fittingModule':
command = cmd.GuiChangeLocalModuleChargesCommand
@@ -148,9 +162,9 @@ class ChangeModuleAmmo(ContextMenuCombined):
if modCharges.issubset(self.mainCharges):
positions.append(position)
self.mainFrame.command.Submit(command(
fitID=fitID,
positions=positions,
chargeItemID=charge.ID if charge is not None else None))
fitID=fitID,
positions=positions,
chargeItemID=charge.ID if charge is not None else None))
ChangeModuleAmmo.register()

View File

@@ -1,11 +1,14 @@
import wx
import gui.fitCommands as cmd
import gui.mainFrame
from gui.contextMenu import ContextMenuSingle
from service.fit import Fit
_t = wx.GetTranslation
class FillWithModule(ContextMenuSingle):
visibilitySetting = 'moduleFill'
def __init__(self):
@@ -18,7 +21,7 @@ class FillWithModule(ContextMenuSingle):
return srcContext == "fittingModule"
def getText(self, callingWindow, itmContext, mainItem):
return "Fill With {0}".format(itmContext if itmContext is not None else "Module")
return _t("Fill With {0}").format(itmContext if itmContext is not None else _t("Module"))
def activate(self, callingWindow, fullContext, mainItem, i):
@@ -30,7 +33,7 @@ class FillWithModule(ContextMenuSingle):
if mainItem in fit.modules:
position = fit.modules.index(mainItem)
self.mainFrame.command.Submit(cmd.GuiFillWithClonedLocalModulesCommand(
fitID=fitID, position=position))
fitID=fitID, position=position))
FillWithModule.register()

View File

@@ -1,8 +1,12 @@
import wx
import gui.mainFrame
from gui.contextMenu import ContextMenuSingle
from gui.utils.clipboard import toClipboard
from service.port.muta import renderMutant
_t = wx.GetTranslation
class ExportMutatedModule(ContextMenuSingle):
@@ -21,7 +25,7 @@ class ExportMutatedModule(ContextMenuSingle):
return True
def getText(self, callingWindow, itmContext, mainItem):
return 'Copy Module to Clipboard'
return _t('Copy Module to Clipboard')
def activate(self, callingWindow, fullContext, mainItem, i):
export = renderMutant(mainItem, prefix=' ')

View File

@@ -1,4 +1,5 @@
# noinspection PyPackageRequirements
import wx
import gui.mainFrame
@@ -6,6 +7,8 @@ from gui.contextMenu import ContextMenuSingle
from gui.fitCommands import GuiConvertMutatedLocalModuleCommand, GuiRevertMutatedLocalModuleCommand
from service.fit import Fit
_t = wx.GetTranslation
class ChangeModuleMutation(ContextMenuSingle):
@@ -27,7 +30,7 @@ class ChangeModuleMutation(ContextMenuSingle):
return True
def getText(self, callingWindow, itmContext, mainItem):
return "Apply Mutaplasmid" if not mainItem.isMutated else "Revert to {}".format(mainItem.baseItem.name)
return _t("Apply Mutaplasmid") if not mainItem.isMutated else _t("Revert to {}").format(mainItem.baseItem.name)
def getSubMenu(self, callingWindow, context, mainItem, rootMenu, i, pitem):
if mainItem.isMutated:
@@ -56,7 +59,7 @@ class ChangeModuleMutation(ContextMenuSingle):
if mod in fit.modules:
position = fit.modules.index(mod)
self.mainFrame.command.Submit(GuiConvertMutatedLocalModuleCommand(
fitID=fitID, position=position, mutaplasmid=mutaplasmid))
fitID=fitID, position=position, mutaplasmid=mutaplasmid))
def activate(self, callingWindow, fullContext, mainItem, i):
fitID = self.mainFrame.getActiveFit()
@@ -64,7 +67,7 @@ class ChangeModuleMutation(ContextMenuSingle):
if mainItem in fit.modules:
position = fit.modules.index(mainItem)
self.mainFrame.command.Submit(GuiRevertMutatedLocalModuleCommand(
fitID=fitID, position=position))
fitID=fitID, position=position))
def getBitmap(self, callingWindow, context, mainItem):
return None

View File

@@ -1,18 +1,20 @@
import math
# noinspection PyPackageRequirements
import wx
import eos.config
import gui.fitCommands as cmd
import gui.mainFrame
from eos.utils.spoolSupport import SpoolType, SpoolOptions
from eos.utils.spoolSupport import SpoolOptions, SpoolType
from gui.contextMenu import ContextMenuSingle
from service.fit import Fit
# noinspection PyPackageRequirements
_t = wx.GetTranslation
class ChangeModuleSpool(ContextMenuSingle):
visibilitySetting = 'spoolup'
def __init__(self):
@@ -32,7 +34,7 @@ class ChangeModuleSpool(ContextMenuSingle):
return self.mod.item.group.name in ("Precursor Weapon", "Mutadaptive Remote Armor Repairer")
def getText(self, callingWindow, itmContext, mainItem):
return "Spoolup Cycles"
return _t("Spoolup Cycles")
def getSubMenu(self, callingWindow, context, mainItem, rootMenu, i, pitem):
m = wx.Menu()
@@ -78,7 +80,7 @@ class ChangeModuleSpool(ContextMenuSingle):
# Show default only for current value and when not overriden
if not isNotDefault and cycle == cycleDefault:
text = "{} (default)".format(cycle)
text = _t("{} (default)").format(cycle)
# Always show current selection and stuff which we decided to show via the cycles function
elif cycle == cycleCurrent or cycle in cyclesToShow:
text = "{}".format(cycle)
@@ -93,7 +95,7 @@ class ChangeModuleSpool(ContextMenuSingle):
self.cycleMap[menuId] = cycle
self.resetId = ContextMenuSingle.nextID()
item = wx.MenuItem(m, self.resetId, "Reset")
item = wx.MenuItem(m, self.resetId, _t("Reset"))
bindmenu.Bind(wx.EVT_MENU, self.handleSpoolChange, item)
m.Append(item)
@@ -114,12 +116,12 @@ class ChangeModuleSpool(ContextMenuSingle):
if self.mod in fit.modules:
position = fit.modules.index(self.mod)
self.mainFrame.command.Submit(cmd.GuiChangeLocalModuleSpoolCommand(
fitID=fitID, position=position, spoolType=spoolType, spoolAmount=spoolAmount))
fitID=fitID, position=position, spoolType=spoolType, spoolAmount=spoolAmount))
elif self.context == 'projectedModule':
if self.mod in fit.projectedModules:
position = fit.projectedModules.index(self.mod)
self.mainFrame.command.Submit(cmd.GuiChangeProjectedModuleSpoolCommand(
fitID=fitID, position=position, spoolType=spoolType, spoolAmount=spoolAmount))
fitID=fitID, position=position, spoolType=spoolType, spoolAmount=spoolAmount))
ChangeModuleSpool.register()

View File

@@ -7,6 +7,8 @@ import gui.mainFrame
from gui.contextMenu import ContextMenuUnconditional
from service.settings import MarketPriceSettings
_t = wx.GetTranslation
class ItemGroupPrice(ContextMenuUnconditional, metaclass=ABCMeta):
@@ -14,11 +16,6 @@ class ItemGroupPrice(ContextMenuUnconditional, metaclass=ABCMeta):
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
self.settings = MarketPriceSettings.getInstance()
@property
@abstractmethod
def label(self):
raise NotImplementedError()
@property
@abstractmethod
def optionName(self):
@@ -27,9 +24,6 @@ class ItemGroupPrice(ContextMenuUnconditional, metaclass=ABCMeta):
def display(self, callingWindow, srcContext):
return srcContext in ("priceViewFull", "priceViewMinimal")
def getText(self, callingWindow, itmContext):
return self.label
def activate(self, callingWindow, fullContext, i):
self.settings.set(self.optionName, not self.settings.get(self.optionName))
fitID = self.mainFrame.getActiveFit()
@@ -40,22 +34,25 @@ class ItemGroupPrice(ContextMenuUnconditional, metaclass=ABCMeta):
class DronesPrice(ItemGroupPrice):
label = 'Drones'
optionName = 'drones'
def getText(self, callingWindow, itmContext):
return _t('Drones')
class CargoPrice(ItemGroupPrice):
label = 'Cargo'
optionName = 'cargo'
def getText(self, callingWindow, itmContext):
return _t('Cargo')
class ImplantBoosterPrice(ItemGroupPrice):
label = 'Implants && Boosters'
optionName = 'character'
def getText(self, callingWindow, itmContext):
return _t('Implants && Boosters')
DronesPrice.register()
CargoPrice.register()

View File

@@ -1,6 +1,5 @@
from collections import OrderedDict
# noinspection PyPackageRequirements
import wx
import gui.mainFrame
@@ -10,6 +9,9 @@ from gui.contextMenu import ContextMenuCombined
from service.const import TargetResistMode
from service.settings import GraphSettings
# noinspection PyPackageRequirements
_t = wx.GetTranslation
optionMap = OrderedDict((
('Auto', TargetResistMode.auto),
@@ -36,7 +38,7 @@ class TargetWrapperResists(ContextMenuCombined):
return True
def getText(self, callingWindow, itmContext, mainItem, selection):
return 'Resist Mode'
return _t('Resist Mode')
def addOption(self, menu, optionLabel):
id = ContextMenuCombined.nextID()

View File

@@ -1,4 +1,5 @@
# noinspection PyPackageRequirements
import wx
import gui.mainFrame
@@ -6,6 +7,8 @@ from gui.builtinShipBrowser.events import Stage3Selected
from gui.contextMenu import ContextMenuUnconditional
from service.fit import Fit
_t = wx.GetTranslation
class JumpToShip(ContextMenuUnconditional):
@@ -29,7 +32,7 @@ class JumpToShip(ContextMenuUnconditional):
return False
def getText(self, callingWindow, itmContext):
return "Open in Fitting Browser"
return _t("Open in Fitting Browser")
def activate(self, callingWindow, fullContext, i):
fitID = self.mainFrame.getActiveFit()

View File

@@ -1,4 +1,5 @@
# noinspection PyPackageRequirements
import wx
import gui.fitCommands as cmd
@@ -6,11 +7,18 @@ import gui.mainFrame
from gui.contextMenu import ContextMenuUnconditional
from service.fit import Fit
_t = wx.GetTranslation
class ChangeShipTacticalMode(ContextMenuUnconditional):
def __init__(self):
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
self.modeMap = {
'Defense': _t('Defense'),
'Propulsion': _t('Propulsion'),
'Sharpshooter': _t('Sharpshooter')
}
def display(self, callingWindow, srcContext):
if self.mainFrame.getActiveFit() is None or srcContext != "fittingShip":
@@ -26,10 +34,12 @@ class ChangeShipTacticalMode(ContextMenuUnconditional):
return srcContext == "fittingShip" and self.modes is not None
def getText(self, callingWindow, itmContext):
return "Tactical Mode"
return _t("Tactical Mode")
def addMode(self, menu, mode):
label = mode.item.name.rsplit()[-2]
key = mode.item.typeName.rsplit()[-2]
label = self.modeMap[key]
id = ContextMenuUnconditional.nextID()
self.modeIds[id] = mode
menuItem = wx.MenuItem(menu, id, label, kind=wx.ITEM_RADIO)

View File

@@ -1,4 +1,5 @@
# noinspection PyPackageRequirements
import wx
import gui.globalEvents as GE
@@ -9,9 +10,10 @@ from gui.contextMenu import ContextMenuSingle
from service.character import Character
from service.fit import Fit
_t = wx.GetTranslation
class ChangeAffectingSkills(ContextMenuSingle):
visibilitySetting = 'changeAffectingSkills'
def __init__(self):
@@ -19,9 +21,9 @@ class ChangeAffectingSkills(ContextMenuSingle):
def display(self, callingWindow, srcContext, mainItem):
if srcContext not in (
"fittingModule", "fittingCharge",
"fittingShip", "droneItem",
"fighterItem"
"fittingModule", "fittingCharge",
"fittingShip", "droneItem",
"fighterItem"
):
return False
@@ -68,13 +70,13 @@ class ChangeAffectingSkills(ContextMenuSingle):
return len(self.skills) > 0
def getText(self, callingWindow, itmContext, mainItem):
return "Change %s Skills" % itmContext
return _t("Change %s Skills") % itmContext
def addSkill(self, rootMenu, skill, i):
if i < 0:
label = "Not Learned"
label = _t("Not Learned")
else:
label = "Level %s" % i
label = _t("Level %s") % i
id = ContextMenuSingle.nextID()
self.skillIds[id] = (skill, i)

View File

@@ -1,7 +1,6 @@
from collections import OrderedDict
from itertools import chain
# noinspection PyPackageRequirements
import wx
import gui.mainFrame
@@ -10,6 +9,10 @@ from gui.contextMenu import ContextMenuUnconditional
from gui.utils.sorter import smartSort
from service.targetProfile import TargetProfile as svc_TargetProfile
# noinspection PyPackageRequirements
_t = wx.GetTranslation
class TargetProfileAdder(ContextMenuUnconditional):
@@ -23,7 +26,7 @@ class TargetProfileAdder(ContextMenuUnconditional):
return True
def getText(self, callingWindow, itmContext):
return 'Add Target Profile'
return _t('Add Target Profile')
def handleProfileAdd(self, event):
profile = self.eventProfileMap.get(event.Id, False)
@@ -56,8 +59,10 @@ class TargetProfileAdder(ContextMenuUnconditional):
for profile in profiles:
container = items
for categoryName in profile.hierarchy:
categoryName = _t(categoryName) if profile.builtin else categoryName
container = container[1].setdefault(categoryName, (OrderedDict(), OrderedDict()))
container[0][profile.shortName] = profile
shortName = _t(profile.shortName) if profile.builtin else profile.shortName
container[0][shortName] = profile
# Category as menu item - expands further
msw = "wxMSW" in wx.PlatformInfo

View File

@@ -1,8 +1,12 @@
import wx
import gui.mainFrame
from graphs.wrapper import TargetWrapper
from gui.contextMenu import ContextMenuSingle
from gui.targetProfileEditor import TargetProfileEditor
_t = wx.GetTranslation
class TargetProfileEditorMenu(ContextMenuSingle):

View File

@@ -1,7 +1,6 @@
from collections import OrderedDict
from itertools import chain
# noinspection PyPackageRequirements
import wx
import gui.globalEvents as GE
@@ -11,6 +10,10 @@ from gui.utils.sorter import smartSort
from service.fit import Fit
from service.targetProfile import TargetProfile as svc_TargetProfile
# noinspection PyPackageRequirements
_t = wx.GetTranslation
class TargetProfileSwitcher(ContextMenuUnconditional):
@@ -27,7 +30,7 @@ class TargetProfileSwitcher(ContextMenuUnconditional):
def getText(self, callingWindow, itmContext):
# We take into consideration just target resists, so call menu item accordingly
return 'Target Resists'
return _t('Target Resists')
def handleResistSwitch(self, event):
profile = self.profileEventMap.get(event.Id, False)
@@ -68,8 +71,10 @@ class TargetProfileSwitcher(ContextMenuUnconditional):
for profile in profiles:
container = items
for categoryName in profile.hierarchy:
categoryName = _t(categoryName) if profile.builtin else categoryName
container = container[1].setdefault(categoryName, (OrderedDict(), OrderedDict()))
container[0][profile.shortName] = profile
shortName = _t(profile.shortName) if profile.builtin else profile.shortName
container[0][shortName] = profile
# Category as menu item - expands further
msw = "wxMSW" in wx.PlatformInfo
@@ -77,7 +82,7 @@ class TargetProfileSwitcher(ContextMenuUnconditional):
def makeMenu(container, parentMenu, first=False):
menu = wx.Menu()
if first:
mitem, checked = self._addProfile(rootMenu if msw else parentMenu, None, 'No Profile')
mitem, checked = self._addProfile(rootMenu if msw else parentMenu, None, _t('No Profile'))
menu.Append(mitem)
mitem.Check(checked)
if len(container[0]) > 0 or len(container[1]) > 0:

View File

@@ -17,6 +17,8 @@ import gui.mainFrame
from gui.contextMenu import ContextMenu
from gui.bitmap_loader import BitmapLoader
_t = wx.GetTranslation
def formatOperator(operator, stackingGroup, preResAmount, postResAmount):
opMap = {
@@ -24,7 +26,8 @@ def formatOperator(operator, stackingGroup, preResAmount, postResAmount):
Operator.PREINCREASE: '+',
Operator.MULTIPLY: '*',
Operator.POSTINCREASE: '+',
Operator.FORCE: '\u2263'}
Operator.FORCE: '\u2263'
}
prefix = ''
if stackingGroup is not None:
prefix += 's'
@@ -61,17 +64,17 @@ class ItemAffectedBy(wx.Panel):
mainSizer.Add(self.m_staticline, 0, wx.EXPAND)
bSizer = wx.BoxSizer(wx.HORIZONTAL)
self.toggleExpandBtn = wx.ToggleButton(self, wx.ID_ANY, "Expand All", wx.DefaultPosition, wx.DefaultSize, 0)
self.toggleExpandBtn = wx.ToggleButton(self, wx.ID_ANY, _t("Expand All"), wx.DefaultPosition, wx.DefaultSize, 0)
bSizer.Add(self.toggleExpandBtn, 0, wx.ALIGN_CENTER_VERTICAL)
self.toggleNameBtn = wx.ToggleButton(self, wx.ID_ANY, "Toggle Names", wx.DefaultPosition, wx.DefaultSize, 0)
self.toggleNameBtn = wx.ToggleButton(self, wx.ID_ANY, _t("Toggle Names"), wx.DefaultPosition, wx.DefaultSize, 0)
bSizer.Add(self.toggleNameBtn, 0, wx.ALIGN_CENTER_VERTICAL)
self.toggleViewBtn = wx.ToggleButton(self, wx.ID_ANY, "Toggle View", wx.DefaultPosition, wx.DefaultSize, 0)
self.toggleViewBtn = wx.ToggleButton(self, wx.ID_ANY, _t("Toggle View"), wx.DefaultPosition, wx.DefaultSize, 0)
bSizer.Add(self.toggleViewBtn, 0, wx.ALIGN_CENTER_VERTICAL)
if stuff is not None:
self.refreshBtn = wx.Button(self, wx.ID_ANY, "Refresh", wx.DefaultPosition, wx.DefaultSize, wx.BU_EXACTFIT)
self.refreshBtn = wx.Button(self, wx.ID_ANY, _t("Refresh"), wx.DefaultPosition, wx.DefaultSize, wx.BU_EXACTFIT)
bSizer.Add(self.refreshBtn, 0, wx.ALIGN_CENTER_VERTICAL)
self.refreshBtn.Bind(wx.EVT_BUTTON, self.RefreshTree)

View File

@@ -11,6 +11,8 @@ from enum import IntEnum
from gui.builtinItemStatsViews.attributeGrouping import *
from service.const import GuiAttrGroup
_t = wx.GetTranslation
class AttributeView(IntEnum):
NORMAL = 1
@@ -25,7 +27,8 @@ class ItemParams(wx.Panel):
mainSizer = wx.BoxSizer(wx.VERTICAL)
self.paramList = wx.lib.agw.hypertreelist.HyperTreeList(self, wx.ID_ANY, agwStyle=wx.TR_HIDE_ROOT | wx.TR_NO_LINES | wx.TR_FULL_ROW_HIGHLIGHT | wx.TR_HAS_BUTTONS)
self.paramList = wx.lib.agw.hypertreelist.HyperTreeList(self, wx.ID_ANY,
agwStyle=wx.TR_HIDE_ROOT | wx.TR_NO_LINES | wx.TR_FULL_ROW_HIGHLIGHT | wx.TR_HAS_BUTTONS)
self.paramList.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW))
mainSizer.Add(self.paramList, 1, wx.ALL | wx.EXPAND, 0)
@@ -38,25 +41,25 @@ class ItemParams(wx.Panel):
self.attrValues = {}
self._fetchValues()
self.paramList.AddColumn("Attribute")
self.paramList.AddColumn("Current Value")
self.paramList.AddColumn(_t("Attribute"))
self.paramList.AddColumn(_t("Current Value"))
if self.stuff is not None:
self.paramList.AddColumn("Base Value")
self.paramList.AddColumn(_t("Base Value"))
self.m_staticline = wx.StaticLine(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL)
mainSizer.Add(self.m_staticline, 0, wx.EXPAND)
bSizer = wx.BoxSizer(wx.HORIZONTAL)
self.toggleViewBtn = wx.ToggleButton(self, wx.ID_ANY, "View Raw Data", wx.DefaultPosition, wx.DefaultSize,
self.toggleViewBtn = wx.ToggleButton(self, wx.ID_ANY, _t("View Raw Data"), wx.DefaultPosition, wx.DefaultSize,
0)
bSizer.Add(self.toggleViewBtn, 0, wx.ALIGN_CENTER_VERTICAL)
self.exportStatsBtn = wx.ToggleButton(self, wx.ID_ANY, "Export Item Stats", wx.DefaultPosition, wx.DefaultSize,
self.exportStatsBtn = wx.ToggleButton(self, wx.ID_ANY, _t("Export Item Stats"), wx.DefaultPosition, wx.DefaultSize,
0)
bSizer.Add(self.exportStatsBtn, 0, wx.ALIGN_CENTER_VERTICAL)
if stuff is not None:
self.refreshBtn = wx.Button(self, wx.ID_ANY, "Refresh", wx.DefaultPosition, wx.DefaultSize, wx.BU_EXACTFIT)
self.refreshBtn = wx.Button(self, wx.ID_ANY, _t("Refresh"), wx.DefaultPosition, wx.DefaultSize, wx.BU_EXACTFIT)
bSizer.Add(self.refreshBtn, 0, wx.ALIGN_CENTER_VERTICAL)
self.refreshBtn.Bind(wx.EVT_BUTTON, self.RefreshValues)
@@ -111,8 +114,8 @@ class ItemParams(wx.Panel):
exportFileName = self.item.name + " (" + str(self.item.ID) + ").csv"
with wx.FileDialog(
self, "Save CSV file", "", exportFileName,
"CSV files (*.csv)|*.csv", wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT
self, _t("Save CSV file"), "", exportFileName,
_t("CSV files") + " (*.csv)|*.csv", wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT
) as dlg:
if dlg.ShowModal() == wx.ID_CANCEL:
@@ -213,7 +216,7 @@ class ItemParams(wx.Panel):
misc_parent = root
# We must first deet4ermine if it's categorey already has defined groupings set for it. Otherwise, we default to just using the fitting group
order = CategoryGroups.get(self.item.category.categoryName, [GuiAttrGroup.FITTING, GuiAttrGroup.SHIP_GROUP])
order = CategoryGroups.get(self.item.category.name, [GuiAttrGroup.FITTING, GuiAttrGroup.SHIP_GROUP])
# start building out the tree
for data in [AttrGroupDict[o] for o in order]:
heading = data.get("label")
@@ -266,7 +269,7 @@ class ItemParams(wx.Panel):
for i in range(self.paramList.GetMainWindow().GetColumnCount()):
self.paramList.SetColumnWidth(i, wx.LIST_AUTOSIZE)
def GetData(self, attr, displayOveride = None):
def GetData(self, attr, displayOveride=None):
info = self.attrInfo.get(attr)
att = self.attrValues[attr]
@@ -285,7 +288,8 @@ class ItemParams(wx.Panel):
val = getattr(att, "value", None)
value = val if val is not None else att
if self.toggleView == AttributeView.NORMAL and ((attr not in GroupedAttributes and not (value or valueDefault)) or info is None or not info.published or attr in RequiredSkillAttrs):
if self.toggleView == AttributeView.NORMAL and (
(attr not in GroupedAttributes and not (value or valueDefault)) or info is None or not info.published or attr in RequiredSkillAttrs):
return None
if info and info.displayName and self.toggleView == AttributeView.NORMAL:

View File

@@ -7,6 +7,8 @@ from service.market import Market
from service.attribute import Attribute
from gui.utils.numberFormatter import formatAmount
_t = wx.GetTranslation
def defaultSort(item):
return (item.metaLevel or 0, item.name)
@@ -70,11 +72,11 @@ class ItemCompare(wx.Panel):
self.totalAttrsLabel = wx.StaticText(self, wx.ID_ANY, " ", wx.DefaultPosition, wx.DefaultSize, 0)
bSizer.Add(self.totalAttrsLabel, 0, wx.ALIGN_CENTER_VERTICAL | wx.RIGHT)
self.toggleViewBtn = wx.ToggleButton(self, wx.ID_ANY, "Toggle view mode", wx.DefaultPosition,
self.toggleViewBtn = wx.ToggleButton(self, wx.ID_ANY, _t("Toggle view mode"), wx.DefaultPosition,
wx.DefaultSize, 0)
bSizer.Add(self.toggleViewBtn, 0, wx.ALIGN_CENTER_VERTICAL)
self.refreshBtn = wx.Button(self, wx.ID_ANY, "Refresh", wx.DefaultPosition, wx.DefaultSize,
self.refreshBtn = wx.Button(self, wx.ID_ANY, _t("Refresh"), wx.DefaultPosition, wx.DefaultSize,
wx.BU_EXACTFIT)
bSizer.Add(self.refreshBtn, 0, wx.ALIGN_CENTER_VERTICAL)
self.refreshBtn.Bind(wx.EVT_BUTTON, self.RefreshValues)
@@ -142,7 +144,7 @@ class ItemCompare(wx.Panel):
self.items = sorted(self.items, key=func, reverse=self.sortReverse)
self.paramList.InsertColumn(0, "Item")
self.paramList.InsertColumn(0, _t("Item"))
self.paramList.SetColumnWidth(0, 200)
for i, attr in enumerate(self.attrs.keys()):
@@ -150,7 +152,7 @@ class ItemCompare(wx.Panel):
self.paramList.InsertColumn(i + 1, name)
self.paramList.SetColumnWidth(i + 1, 120)
self.paramList.InsertColumn(len(self.attrs) + 1, "Price")
self.paramList.InsertColumn(len(self.attrs) + 1, _t("Price"))
self.paramList.SetColumnWidth(len(self.attrs) + 1, 60)
for item in self.items:
@@ -189,16 +191,16 @@ class ItemCompare(wx.Panel):
return "%s (%d)" % (attribute.name.capitalize(), value)
trans = {
"Inverse Absolute Percent" : (lambda: (1 - value) * 100, unitName),
"Inverse Absolute Percent": (lambda: (1 - value) * 100, unitName),
"Inversed Modifier Percent": (lambda: (1 - value) * 100, unitName),
"Modifier Percent" : (lambda: ("%+.2f" if ((value - 1) * 100) % 1 else "%+d") % ((value - 1) * 100), unitName),
"Volume" : (lambda: value, "m\u00B3"),
"Sizeclass" : (lambda: value, ""),
"Absolute Percent" : (lambda: (value * 100), unitName),
"Milliseconds" : (lambda: value / 1000.0, unitName),
"typeID" : (itemIDCallback, ""),
"groupID" : (groupIDCallback, ""),
"attributeID" : (attributeIDCallback, "")
"Modifier Percent": (lambda: ("%+.2f" if ((value - 1) * 100) % 1 else "%+d") % ((value - 1) * 100), unitName),
"Volume": (lambda: value, "m\u00B3"),
"Sizeclass": (lambda: value, ""),
"Absolute Percent": (lambda: (value * 100), unitName),
"Milliseconds": (lambda: value / 1000.0, unitName),
"typeID": (itemIDCallback, ""),
"groupID": (groupIDCallback, ""),
"attributeID": (attributeIDCallback, "")
}
override = trans.get(unitDisplayName)

View File

@@ -3,6 +3,8 @@ import wx
from gui.bitmap_loader import BitmapLoader
_t = wx.GetTranslation
class ItemDependents(wx.Panel):
def __init__(self, parent, stuff, item):
@@ -41,7 +43,7 @@ class ItemDependents(wx.Panel):
items = levelToItems[x]
items.sort(key=lambda x: x.name)
child = self.reqTree.AppendItem(parent, "Level {}".format(self.romanNb[int(x)]), sbIconId)
child = self.reqTree.AppendItem(parent, _t("Level {}").format(self.romanNb[int(x)]), sbIconId)
for item in items:
if item.iconID:

View File

@@ -4,6 +4,8 @@ import wx
import wx.html
import re
_t = wx.GetTranslation
class ItemDescription(wx.Panel):
def __init__(self, parent, stuff, item):
@@ -24,9 +26,9 @@ class ItemDescription(wx.Panel):
# Strip URLs
desc = re.sub("<( *)a(.*?)>(?P<inside>.*?)<( *)/( *)a( *)>", "\g<inside>", desc)
desc = "<body style='background-color: {}; color: {}'>{}</body>".format(
bgcolor.GetAsString(wx.C2S_CSS_SYNTAX),
fgcolor.GetAsString(wx.C2S_CSS_SYNTAX),
desc
bgcolor.GetAsString(wx.C2S_CSS_SYNTAX),
fgcolor.GetAsString(wx.C2S_CSS_SYNTAX),
desc
)
self.description.SetPage(desc)
@@ -38,7 +40,7 @@ class ItemDescription(wx.Panel):
self.description.Bind(wx.EVT_KEY_UP, self.onKeyUp)
self.popupMenu = wx.Menu()
copyItem = wx.MenuItem(self.popupMenu, 1, 'Copy')
copyItem = wx.MenuItem(self.popupMenu, 1, _t('Copy'))
self.popupMenu.Append(copyItem)
self.popupMenu.Bind(wx.EVT_MENU, self.menuClickHandler, copyItem)

Some files were not shown because too many files have changed in this diff Show More