Merge branch 'development' into More_Variations
Conflicts: gui/builtinContextMenus/metaSwap.py
This commit is contained in:
26
.codecov.yml
Normal file
26
.codecov.yml
Normal file
@@ -0,0 +1,26 @@
|
||||
codecov:
|
||||
notify:
|
||||
require_ci_to_pass: yes
|
||||
|
||||
coverage:
|
||||
precision: 2
|
||||
round: down
|
||||
range: "70...100"
|
||||
|
||||
status:
|
||||
project: yes
|
||||
patch: yes
|
||||
changes: no
|
||||
|
||||
parsers:
|
||||
gcov:
|
||||
branch_detection:
|
||||
conditional: yes
|
||||
loop: yes
|
||||
method: no
|
||||
macro: no
|
||||
|
||||
comment:
|
||||
layout: "header, diff"
|
||||
behavior: default
|
||||
require_changes: no
|
||||
40
.gitattributes
vendored
Normal file
40
.gitattributes
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
# 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
|
||||
# ============
|
||||
*.pxd text eol=crlf
|
||||
*.py text eol=crlf
|
||||
*.py3 text eol=crlf
|
||||
*.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
|
||||
# ============
|
||||
*.db binary
|
||||
*.p binary
|
||||
*.pkl binary
|
||||
*.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
|
||||
# ============
|
||||
*.png binary
|
||||
*.jpg binary
|
||||
*.icns binary
|
||||
*.ico binary
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -49,7 +49,6 @@ Pyfa.egg-info/
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
|
||||
25
.travis.yml
Normal file
25
.travis.yml
Normal file
@@ -0,0 +1,25 @@
|
||||
language: python
|
||||
python:
|
||||
- '2.7'
|
||||
env:
|
||||
- TOXENV=pep8
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
# for wxPython:
|
||||
- python-wxgtk2.8
|
||||
- python-wxtools
|
||||
- wx2.8-doc
|
||||
- wx2.8-examples
|
||||
- wx2.8-headers
|
||||
- wx2.8-i18n
|
||||
before_install:
|
||||
- pip install -U tox
|
||||
install:
|
||||
- pip install -r requirements.txt
|
||||
- pip install -r requirements_test.txt
|
||||
script:
|
||||
- tox
|
||||
- py.test --cov=./
|
||||
after_success:
|
||||
- bash <(curl -s https://codecov.io/bash)
|
||||
32
ISSUE_TEMPLATE.md
Normal file
32
ISSUE_TEMPLATE.md
Normal file
@@ -0,0 +1,32 @@
|
||||
# Submit a bug report bug report or feature request
|
||||
|
||||
Here you can inform pyfa developers of potential bugs or suggest features / improvements to the project. Please check
|
||||
to make sure that the bug hasn't been reported or feature requested before submitting. If you have general questions
|
||||
about the project and want to reach out to the developers personally, please check out out our [Slack]
|
||||
(https://pyfainvite.azurewebsites.net/).
|
||||
|
||||
---
|
||||
|
||||
## Bug Report
|
||||
|
||||
|
||||
### Expected behavior:
|
||||
|
||||
|
||||
### Actual behavior:
|
||||
|
||||
|
||||
### Detailed steps to reproduce:
|
||||
|
||||
|
||||
### Fits involved in EFT format (Edit > To Clipboard > EFT):
|
||||
|
||||
|
||||
### Release or development git branch? Please note the release version or commit hash:
|
||||
|
||||
|
||||
### Operating system and version (eg: Windows 10, OS X 10.9, OS X 10.11, Ubuntu 16.10):
|
||||
|
||||
|
||||
### Other relevant information:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# pyfa
|
||||
|
||||
[](https://pyfainvite.azurewebsites.net/)
|
||||
[](https://pyfainvite.azurewebsites.net/) [](https://travis-ci.org/pyfa-org/Pyfa)
|
||||
|
||||

|
||||
|
||||
@@ -38,7 +38,7 @@ If you wish to help with development or simply need to run pyfa through a Python
|
||||
|
||||
* Python 2.7
|
||||
* `wxPython` 2.8/3.0
|
||||
* `sqlalchemy` >= 0.6
|
||||
* `sqlalchemy` >= 1.0.5
|
||||
* `dateutil`
|
||||
* `matplotlib` (for some Linux distributions you may need to install separate wxPython bindings such as `python-matplotlib-wx`)
|
||||
* `requests`
|
||||
@@ -51,8 +51,7 @@ pyfa is licensed under the GNU GPL v3.0, see LICENSE
|
||||
|
||||
## Resources
|
||||
* Development repository: [https://github.com/pyfa-org/Pyfa](https://github.com/pyfa-org/Pyfa)
|
||||
* XMPP conference: [pyfa@conference.jabber.org](pyfa@conference.jabber.org)
|
||||
* [EVE forum thread](http://forums.eveonline.com/default.aspx?g=posts&t=247609)
|
||||
* [EVE forum thread](https://forums.eveonline.com/default.aspx?g=posts&t=466425)
|
||||
* [EVE University guide using pyfa](http://wiki.eveuniversity.org/Guide_to_using_PYFA)
|
||||
* [EVE Online website](http://www.eveonline.com/)
|
||||
|
||||
|
||||
13
_development/Pyfa_CodeStyle.xml
Normal file
13
_development/Pyfa_CodeStyle.xml
Normal file
@@ -0,0 +1,13 @@
|
||||
<code_scheme name="Pyfa">
|
||||
<option name="LINE_SEPARATOR" value="
" />
|
||||
<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" />
|
||||
<option name="OPTIMIZE_IMPORTS_SORT_NAMES_IN_FROM_IMPORTS" value="true" />
|
||||
<option name="OPTIMIZE_IMPORTS_JOIN_FROM_IMPORTS_WITH_SAME_SOURCE" value="true" />
|
||||
</Python>
|
||||
</code_scheme>
|
||||
54
_development/Pyfa_Inspections.xml
Normal file
54
_development/Pyfa_Inspections.xml
Normal file
@@ -0,0 +1,54 @@
|
||||
<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>
|
||||
</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>
|
||||
79
config.py
79
config.py
@@ -1,27 +1,28 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
# TODO: move all logging back to pyfa.py main loop
|
||||
# We moved it here just to avoid rebuilding windows skeleton for now (any change to pyfa.py needs it)
|
||||
import logging
|
||||
import logging.handlers
|
||||
from logbook import Logger
|
||||
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
# Load variable overrides specific to distribution type
|
||||
try:
|
||||
import configforced
|
||||
except ImportError:
|
||||
pyfalog.warning("Failed to import: configforced")
|
||||
configforced = None
|
||||
|
||||
|
||||
# Turns on debug mode
|
||||
debug = False
|
||||
# Defines if our saveddata will be in pyfa root or not
|
||||
saveInRoot = False
|
||||
|
||||
# Version data
|
||||
version = "1.26.1"
|
||||
version = "1.27.3"
|
||||
tag = "git"
|
||||
expansionName = "YC118.10"
|
||||
expansionVersion = "1.2"
|
||||
expansionName = "YC119.2"
|
||||
expansionVersion = "1.4"
|
||||
evemonMinVersion = "4081"
|
||||
|
||||
pyfaPath = None
|
||||
@@ -30,35 +31,28 @@ saveDB = None
|
||||
gameDB = None
|
||||
|
||||
|
||||
class StreamToLogger(object):
|
||||
"""
|
||||
Fake file-like stream object that redirects writes to a logger instance.
|
||||
From: http://www.electricmonk.nl/log/2011/08/14/redirect-stdout-and-stderr-to-a-logger-in-python/
|
||||
"""
|
||||
def __init__(self, logger, log_level=logging.INFO):
|
||||
self.logger = logger
|
||||
self.log_level = log_level
|
||||
self.linebuf = ''
|
||||
|
||||
def write(self, buf):
|
||||
for line in buf.rstrip().splitlines():
|
||||
self.logger.log(self.log_level, line.rstrip())
|
||||
|
||||
def isFrozen():
|
||||
if hasattr(sys, 'frozen'):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def __createDirs(path):
|
||||
if not os.path.exists(path):
|
||||
os.makedirs(path)
|
||||
|
||||
|
||||
def getPyfaRoot():
|
||||
base = getattr(sys.modules['__main__'], "__file__", sys.executable) if isFrozen() else sys.argv[0]
|
||||
root = os.path.dirname(os.path.realpath(os.path.abspath(base)))
|
||||
root = unicode(root, sys.getfilesystemencoding())
|
||||
return root
|
||||
|
||||
def __createDirs(path):
|
||||
if not os.path.exists(path):
|
||||
os.makedirs(path)
|
||||
|
||||
def getDefaultSave():
|
||||
return unicode(os.path.expanduser(os.path.join("~", ".pyfa")), sys.getfilesystemencoding())
|
||||
|
||||
|
||||
def defPaths(customSavePath):
|
||||
global debug
|
||||
@@ -68,10 +62,7 @@ def defPaths(customSavePath):
|
||||
global gameDB
|
||||
global saveInRoot
|
||||
|
||||
if debug:
|
||||
logLevel = logging.DEBUG
|
||||
else:
|
||||
logLevel = logging.WARN
|
||||
pyfalog.debug("Configuring Pyfa")
|
||||
|
||||
# The main pyfa directory which contains run.py
|
||||
# Python 2.X uses ANSI by default, so we need to convert the character encoding
|
||||
@@ -87,36 +78,16 @@ def defPaths(customSavePath):
|
||||
else:
|
||||
savePath = getattr(configforced, "savePath", None)
|
||||
if savePath is None:
|
||||
if customSavePath is None: # customSavePath is not overriden
|
||||
savePath = unicode(os.path.expanduser(os.path.join("~", ".pyfa")),
|
||||
sys.getfilesystemencoding())
|
||||
if customSavePath is None: # customSavePath is not overriden
|
||||
savePath = getDefaultSave()
|
||||
else:
|
||||
savePath = customSavePath
|
||||
|
||||
__createDirs(savePath)
|
||||
|
||||
if isFrozen():
|
||||
os.environ["REQUESTS_CA_BUNDLE"] = os.path.join(pyfaPath, "cacert.pem")
|
||||
os.environ["SSL_CERT_FILE"] = os.path.join(pyfaPath, "cacert.pem")
|
||||
|
||||
format = '%(asctime)s %(name)-24s %(levelname)-8s %(message)s'
|
||||
logging.basicConfig(format=format, level=logLevel)
|
||||
handler = logging.handlers.RotatingFileHandler(os.path.join(savePath, "log.txt"), maxBytes=1000000, backupCount=3)
|
||||
formatter = logging.Formatter(format)
|
||||
handler.setFormatter(formatter)
|
||||
logging.getLogger('').addHandler(handler)
|
||||
|
||||
logging.info("Starting pyfa")
|
||||
|
||||
if hasattr(sys, 'frozen'):
|
||||
stdout_logger = logging.getLogger('STDOUT')
|
||||
sl = StreamToLogger(stdout_logger, logging.INFO)
|
||||
sys.stdout = sl
|
||||
|
||||
# This interferes with cx_Freeze's own handling of exceptions. Find a way to fix this.
|
||||
#stderr_logger = logging.getLogger('STDERR')
|
||||
#sl = StreamToLogger(stderr_logger, logging.ERROR)
|
||||
#sys.stderr = sl
|
||||
os.environ["REQUESTS_CA_BUNDLE"] = os.path.join(pyfaPath, "cacert.pem").encode('utf8')
|
||||
os.environ["SSL_CERT_FILE"] = os.path.join(pyfaPath, "cacert.pem").encode('utf8')
|
||||
|
||||
# The database where we store all the fits etc
|
||||
saveDB = os.path.join(savePath, "saveddata.db")
|
||||
@@ -126,10 +97,10 @@ def defPaths(customSavePath):
|
||||
# maintenance script
|
||||
gameDB = os.path.join(pyfaPath, "eve.db")
|
||||
|
||||
## DON'T MODIFY ANYTHING BELOW ##
|
||||
# DON'T MODIFY ANYTHING BELOW
|
||||
import eos.config
|
||||
|
||||
#Caching modifiers, disable all gamedata caching, its unneeded.
|
||||
# Caching modifiers, disable all gamedata caching, its unneeded.
|
||||
eos.config.gamedataCache = False
|
||||
# saveddata db location modifier, shouldn't ever need to touch this
|
||||
eos.config.saveddata_connectionstring = "sqlite:///" + saveDB + "?check_same_thread=False"
|
||||
|
||||
5666
dist_assets/cacert.pem
Normal file
5666
dist_assets/cacert.pem
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,8 +1,2 @@
|
||||
version = "0.2.3"
|
||||
tag = "git"
|
||||
|
||||
|
||||
def test():
|
||||
import tests.runTests
|
||||
import unittest
|
||||
unittest.main(defaultTest="discover", testLoader=tests.runTests.loader)
|
||||
version = "0.2.3"
|
||||
tag = "git"
|
||||
|
||||
@@ -4,10 +4,12 @@ from os.path import realpath, join, dirname, abspath
|
||||
debug = False
|
||||
gamedataCache = True
|
||||
saveddataCache = True
|
||||
gamedata_version = ""
|
||||
gamedata_connectionstring = 'sqlite:///' + unicode(realpath(join(dirname(abspath(__file__)), "..", "eve.db")),
|
||||
sys.getfilesystemencoding())
|
||||
saveddata_connectionstring = 'sqlite:///' + unicode(
|
||||
realpath(join(dirname(abspath(__file__)), "..", "saveddata", "saveddata.db")), sys.getfilesystemencoding())
|
||||
|
||||
|
||||
# Autodetect path, only change if the autodetection bugs out.
|
||||
path = dirname(unicode(__file__, sys.getfilesystemencoding()))
|
||||
|
||||
@@ -20,13 +20,13 @@
|
||||
import threading
|
||||
|
||||
from sqlalchemy import MetaData, create_engine
|
||||
from sqlalchemy.orm import sessionmaker, scoped_session
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
from sqlalchemy import pool
|
||||
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
|
||||
import migration
|
||||
from eos import config
|
||||
from logbook import Logger
|
||||
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
class ReadOnlyException(Exception):
|
||||
@@ -49,7 +49,9 @@ try:
|
||||
config.gamedata_version = gamedata_session.execute(
|
||||
"SELECT `field_value` FROM `metadata` WHERE `field_name` LIKE 'client_build'"
|
||||
).fetchone()[0]
|
||||
except:
|
||||
except Exception as e:
|
||||
pyfalog.warning("Missing gamedata version.")
|
||||
pyfalog.critical(e)
|
||||
config.gamedata_version = None
|
||||
|
||||
saveddata_connectionstring = config.saveddata_connectionstring
|
||||
@@ -62,16 +64,22 @@ if saveddata_connectionstring is not None:
|
||||
saveddata_meta = MetaData()
|
||||
saveddata_meta.bind = saveddata_engine
|
||||
saveddata_session = sessionmaker(bind=saveddata_engine, autoflush=False, expire_on_commit=False)()
|
||||
else:
|
||||
saveddata_meta = None
|
||||
|
||||
# Lock controlling any changes introduced to session
|
||||
sd_lock = threading.Lock()
|
||||
|
||||
# Import all the definitions for all our database stuff
|
||||
from eos.db.gamedata import *
|
||||
from eos.db.saveddata import *
|
||||
# noinspection PyPep8
|
||||
from eos.db.gamedata import alphaClones, attribute, category, effect, group, icon, item, marketGroup, metaData, metaGroup, queries, traits, unit
|
||||
# noinspection PyPep8
|
||||
from eos.db.saveddata import booster, cargo, character, crest, damagePattern, databaseRepair, drone, fighter, fit, implant, implantSet, loadDefaultDatabaseValues, miscData, module, override, price, queries, skill, targetResists, user
|
||||
|
||||
# Import queries
|
||||
# noinspection PyPep8
|
||||
from eos.db.gamedata.queries import *
|
||||
# noinspection PyPep8
|
||||
from eos.db.saveddata.queries import *
|
||||
|
||||
# If using in memory saveddata, you'll want to reflect it so the data structure is good.
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
__all__ = ["attribute", "category", "effect", "group", "metaData",
|
||||
"icon", "item", "marketGroup", "metaGroup", "unit"]
|
||||
"icon", "item", "marketGroup", "metaGroup", "unit", "alphaClones"]
|
||||
|
||||
50
eos/db/gamedata/alphaClones.py
Normal file
50
eos/db/gamedata/alphaClones.py
Normal file
@@ -0,0 +1,50 @@
|
||||
# ===============================================================================
|
||||
# Copyright (C) 2010 Diego Duclos
|
||||
#
|
||||
# This file is part of eos.
|
||||
#
|
||||
# eos is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# eos is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with eos. If not, see <http://www.gnu.org/licenses/>.
|
||||
# ===============================================================================
|
||||
|
||||
from sqlalchemy import Column, String, Integer, Table, ForeignKey
|
||||
from sqlalchemy.orm import relation, mapper, synonym
|
||||
|
||||
from eos.db import gamedata_meta
|
||||
from eos.gamedata import AlphaClone, AlphaCloneSkill
|
||||
|
||||
alphaclones_table = Table(
|
||||
"alphaClones",
|
||||
gamedata_meta,
|
||||
Column("alphaCloneID", Integer, primary_key=True),
|
||||
Column("alphaCloneName", String),
|
||||
)
|
||||
|
||||
alphacloneskskills_table = Table(
|
||||
"alphaCloneSkills",
|
||||
gamedata_meta,
|
||||
Column("alphaCloneID", Integer, ForeignKey("alphaClones.alphaCloneID"), primary_key=True),
|
||||
Column("typeID", Integer, primary_key=True),
|
||||
Column("level", Integer),
|
||||
)
|
||||
|
||||
mapper(AlphaClone, alphaclones_table,
|
||||
properties={
|
||||
"ID": synonym("alphaCloneID"),
|
||||
"skills": relation(
|
||||
AlphaCloneSkill,
|
||||
cascade="all,delete-orphan",
|
||||
backref="clone")
|
||||
})
|
||||
|
||||
mapper(AlphaCloneSkill, alphacloneskskills_table)
|
||||
@@ -22,7 +22,7 @@ from sqlalchemy.ext.associationproxy import association_proxy
|
||||
from sqlalchemy.orm import relation, mapper, synonym, deferred
|
||||
|
||||
from eos.db import gamedata_meta
|
||||
from eos.types import Attribute, Icon, AttributeInfo, Unit
|
||||
from eos.gamedata import Attribute, AttributeInfo, Unit, Icon
|
||||
|
||||
typeattributes_table = Table("dgmtypeattribs", gamedata_meta,
|
||||
Column("value", Float),
|
||||
|
||||
@@ -21,7 +21,7 @@ from sqlalchemy import Column, String, Integer, ForeignKey, Boolean, Table
|
||||
from sqlalchemy.orm import relation, mapper, synonym, deferred
|
||||
|
||||
from eos.db import gamedata_meta
|
||||
from eos.types import Category, Icon
|
||||
from eos.gamedata import Category, Icon
|
||||
|
||||
categories_table = Table("invcategories", gamedata_meta,
|
||||
Column("categoryID", Integer, primary_key=True),
|
||||
|
||||
@@ -22,7 +22,7 @@ from sqlalchemy.ext.associationproxy import association_proxy
|
||||
from sqlalchemy.orm import mapper, synonym, relation, deferred
|
||||
|
||||
from eos.db import gamedata_meta
|
||||
from eos.types import Effect, EffectInfo
|
||||
from eos.gamedata import Effect, EffectInfo
|
||||
|
||||
typeeffects_table = Table("dgmtypeeffects", gamedata_meta,
|
||||
Column("typeID", Integer, ForeignKey("invtypes.typeID"), primary_key=True, index=True),
|
||||
|
||||
@@ -21,7 +21,7 @@ from sqlalchemy import Column, String, Integer, Boolean, ForeignKey, Table
|
||||
from sqlalchemy.orm import relation, mapper, synonym, deferred
|
||||
|
||||
from eos.db import gamedata_meta
|
||||
from eos.types import Group, Icon, Category
|
||||
from eos.gamedata import Category, Group, Icon
|
||||
|
||||
groups_table = Table("invgroups", gamedata_meta,
|
||||
Column("groupID", Integer, primary_key=True),
|
||||
|
||||
@@ -21,7 +21,7 @@ from sqlalchemy import Column, String, Integer, Table
|
||||
from sqlalchemy.orm import mapper, synonym, deferred
|
||||
|
||||
from eos.db import gamedata_meta
|
||||
from eos.types import Icon
|
||||
from eos.gamedata import Icon
|
||||
|
||||
icons_table = Table("icons", gamedata_meta,
|
||||
Column("iconID", Integer, primary_key=True),
|
||||
|
||||
@@ -23,7 +23,7 @@ from sqlalchemy.orm import relation, mapper, synonym, deferred
|
||||
from sqlalchemy.orm.collections import attribute_mapped_collection
|
||||
|
||||
from eos.db import gamedata_meta
|
||||
from eos.types import Icon, Attribute, Item, Effect, MetaType, Group, Traits
|
||||
from eos.gamedata import Attribute, Effect, Group, Icon, Item, MetaType, Traits
|
||||
|
||||
items_table = Table("invtypes", gamedata_meta,
|
||||
Column("typeID", Integer, primary_key=True),
|
||||
@@ -39,8 +39,8 @@ items_table = Table("invtypes", gamedata_meta,
|
||||
Column("iconID", Integer, ForeignKey("icons.iconID")),
|
||||
Column("groupID", Integer, ForeignKey("invgroups.groupID"), index=True))
|
||||
|
||||
from .metaGroup import metatypes_table
|
||||
from .traits import traits_table
|
||||
from .metaGroup import metatypes_table # noqa
|
||||
from .traits import traits_table # noqa
|
||||
|
||||
mapper(Item, items_table,
|
||||
properties={"group": relation(Group, backref="items"),
|
||||
|
||||
@@ -21,7 +21,7 @@ from sqlalchemy import Column, String, Integer, Boolean, ForeignKey, Table
|
||||
from sqlalchemy.orm import relation, mapper, synonym, deferred
|
||||
|
||||
from eos.db import gamedata_meta
|
||||
from eos.types import Item, MarketGroup, Icon
|
||||
from eos.gamedata import Icon, Item, MarketGroup
|
||||
|
||||
marketgroups_table = Table("invmarketgroups", gamedata_meta,
|
||||
Column("marketGroupID", Integer, primary_key=True),
|
||||
|
||||
@@ -1,30 +1,30 @@
|
||||
# ===============================================================================
|
||||
# Copyright (C) 2010 Diego Duclos
|
||||
#
|
||||
# This file is part of eos.
|
||||
#
|
||||
# eos is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# eos is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with eos. If not, see <http://www.gnu.org/licenses/>.
|
||||
# ===============================================================================
|
||||
|
||||
from sqlalchemy import Column, Table, String
|
||||
from sqlalchemy.orm import mapper
|
||||
|
||||
from eos.db import gamedata_meta
|
||||
from eos.types import MetaData
|
||||
|
||||
metadata_table = Table("metadata", gamedata_meta,
|
||||
Column("field_name", String, primary_key=True),
|
||||
Column("field_value", String))
|
||||
|
||||
mapper(MetaData, metadata_table)
|
||||
# ===============================================================================
|
||||
# Copyright (C) 2010 Diego Duclos
|
||||
#
|
||||
# This file is part of eos.
|
||||
#
|
||||
# eos is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# eos is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with eos. If not, see <http://www.gnu.org/licenses/>.
|
||||
# ===============================================================================
|
||||
|
||||
from sqlalchemy import Column, Table, String
|
||||
from sqlalchemy.orm import mapper
|
||||
|
||||
from eos.db import gamedata_meta
|
||||
from eos.gamedata import MetaData
|
||||
|
||||
metadata_table = Table("metadata", gamedata_meta,
|
||||
Column("field_name", String, primary_key=True),
|
||||
Column("field_value", String))
|
||||
|
||||
mapper(MetaData, metadata_table)
|
||||
|
||||
@@ -23,7 +23,7 @@ from sqlalchemy.orm import relation, mapper, synonym
|
||||
|
||||
from eos.db import gamedata_meta
|
||||
from eos.db.gamedata.item import items_table
|
||||
from eos.types import MetaGroup, Item, MetaType
|
||||
from eos.gamedata import Item, MetaGroup, MetaType
|
||||
|
||||
metagroups_table = Table("invmetagroups", gamedata_meta,
|
||||
Column("metaGroupID", Integer, primary_key=True),
|
||||
|
||||
@@ -25,7 +25,7 @@ from eos.db import gamedata_session
|
||||
from eos.db.gamedata.metaGroup import metatypes_table, items_table
|
||||
from eos.db.gamedata.group import groups_table
|
||||
from eos.db.util import processEager, processWhere
|
||||
from eos.types import Item, Category, Group, MarketGroup, AttributeInfo, MetaData, MetaGroup
|
||||
from eos.gamedata import AlphaClone, Attribute, Category, Group, Item, MarketGroup, MetaGroup, AttributeInfo, MetaData
|
||||
|
||||
configVal = getattr(eos.config, "gamedataCache", None)
|
||||
if configVal is True:
|
||||
@@ -98,6 +98,24 @@ def getItem(lookfor, eager=None):
|
||||
return item
|
||||
|
||||
|
||||
@cachedQuery(1, "lookfor")
|
||||
def getAlphaClone(lookfor, eager=None):
|
||||
if isinstance(lookfor, int):
|
||||
if eager is None:
|
||||
item = gamedata_session.query(AlphaClone).get(lookfor)
|
||||
else:
|
||||
item = gamedata_session.query(AlphaClone).options(*processEager(eager)).filter(AlphaClone.ID == lookfor).first()
|
||||
else:
|
||||
raise TypeError("Need integer as argument")
|
||||
return item
|
||||
|
||||
|
||||
def getAlphaCloneList(eager=None):
|
||||
eager = processEager(eager)
|
||||
clones = gamedata_session.query(AlphaClone).options(*eager).all()
|
||||
return clones
|
||||
|
||||
|
||||
groupNameMap = {}
|
||||
|
||||
|
||||
@@ -292,9 +310,9 @@ def directAttributeRequest(itemIDs, attrIDs):
|
||||
if not isinstance(itemID, int):
|
||||
raise TypeError("All itemIDs must be integer")
|
||||
|
||||
q = select((eos.types.Item.typeID, eos.types.Attribute.attributeID, eos.types.Attribute.value),
|
||||
and_(eos.types.Attribute.attributeID.in_(attrIDs), eos.types.Item.typeID.in_(itemIDs)),
|
||||
from_obj=[join(eos.types.Attribute, eos.types.Item)])
|
||||
q = select((Item.typeID, Attribute.attributeID, Attribute.value),
|
||||
and_(Attribute.attributeID.in_(attrIDs), Item.typeID.in_(itemIDs)),
|
||||
from_obj=[join(Attribute, Item)])
|
||||
|
||||
result = gamedata_session.execute(q).fetchall()
|
||||
return result
|
||||
|
||||
@@ -2,7 +2,7 @@ from sqlalchemy import Column, Table, Integer, String, ForeignKey
|
||||
from sqlalchemy.orm import mapper
|
||||
|
||||
from eos.db import gamedata_meta
|
||||
from eos.types import Traits
|
||||
from eos.gamedata import Traits
|
||||
|
||||
traits_table = Table("invtraits", gamedata_meta,
|
||||
Column("typeID", Integer, ForeignKey("invtypes.typeID"), primary_key=True),
|
||||
|
||||
@@ -21,7 +21,7 @@ from sqlalchemy import Column, Table, Integer, String
|
||||
from sqlalchemy.orm import mapper, synonym
|
||||
|
||||
from eos.db import gamedata_meta
|
||||
from eos.types import Unit
|
||||
from eos.gamedata import Unit
|
||||
|
||||
groups_table = Table("dgmunits", gamedata_meta,
|
||||
Column("unitID", Integer, primary_key=True),
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import logging
|
||||
from logbook import Logger
|
||||
import shutil
|
||||
import time
|
||||
|
||||
import config
|
||||
import migrations
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
def getVersion(db):
|
||||
@@ -37,7 +37,7 @@ def update(saveddata_engine):
|
||||
for version in xrange(dbVersion, appVersion):
|
||||
func = migrations.updates[version + 1]
|
||||
if func:
|
||||
logger.info("Applying database update: %d", version + 1)
|
||||
pyfalog.info("Applying database update: {0}", version + 1)
|
||||
func(saveddata_engine)
|
||||
|
||||
# when all is said and done, set version to current
|
||||
|
||||
@@ -45,7 +45,7 @@ CONVERSIONS = {
|
||||
8746, # Quantum Co-Processor
|
||||
8745, # Photonic CPU Enhancer
|
||||
15425, # Naiyon's Modified Co-Processor (never existed but convert
|
||||
# anyway as some fits may include it)
|
||||
# anyway as some fits may include it)
|
||||
],
|
||||
8748: [ # Upgraded Co-Processor
|
||||
8747, # Nanomechanical CPU Enhancer I
|
||||
@@ -70,7 +70,7 @@ CONVERSIONS = {
|
||||
16543, # Micro 'Vigor' Core Augmentation
|
||||
],
|
||||
8089: [ # Compact Light Missile Launcher
|
||||
8093, # Prototype 'Arbalest' Light Missile Launcher
|
||||
8093, # Prototype 'Arbalest' Light Missile Launcher
|
||||
],
|
||||
8091: [ # Ample Light Missile Launcher
|
||||
7993, # Experimental TE-2100 Light Missile Launcher
|
||||
@@ -82,6 +82,7 @@ CONVERSIONS = {
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
def upgrade(saveddata_engine):
|
||||
# Update fits schema to include target resists attribute
|
||||
try:
|
||||
@@ -92,6 +93,7 @@ def upgrade(saveddata_engine):
|
||||
# Convert modules
|
||||
for replacement_item, list in CONVERSIONS.iteritems():
|
||||
for retired_item in list:
|
||||
saveddata_engine.execute('UPDATE "modules" SET "itemID" = ? WHERE "itemID" = ?', (replacement_item, retired_item))
|
||||
saveddata_engine.execute('UPDATE "cargo" SET "itemID" = ? WHERE "itemID" = ?', (replacement_item, retired_item))
|
||||
|
||||
saveddata_engine.execute('UPDATE "modules" SET "itemID" = ? WHERE "itemID" = ?',
|
||||
(replacement_item, retired_item))
|
||||
saveddata_engine.execute('UPDATE "cargo" SET "itemID" = ? WHERE "itemID" = ?',
|
||||
(replacement_item, retired_item))
|
||||
|
||||
@@ -6,6 +6,7 @@ Migration 10
|
||||
|
||||
import sqlalchemy
|
||||
|
||||
|
||||
def upgrade(saveddata_engine):
|
||||
# Update projectedFits schema to include active attribute
|
||||
try:
|
||||
|
||||
@@ -7,7 +7,6 @@ Migration 11
|
||||
modules with their new replacements
|
||||
"""
|
||||
|
||||
|
||||
CONVERSIONS = {
|
||||
16467: ( # Medium Gremlin Compact Energy Neutralizer
|
||||
16471, # Medium Unstable Power Fluctuator I
|
||||
@@ -106,11 +105,12 @@ CONVERSIONS = {
|
||||
),
|
||||
}
|
||||
|
||||
def upgrade(saveddata_engine):
|
||||
|
||||
def upgrade(saveddata_engine):
|
||||
# Convert modules
|
||||
for replacement_item, list in CONVERSIONS.iteritems():
|
||||
for retired_item in list:
|
||||
saveddata_engine.execute('UPDATE "modules" SET "itemID" = ? WHERE "itemID" = ?', (replacement_item, retired_item))
|
||||
saveddata_engine.execute('UPDATE "cargo" SET "itemID" = ? WHERE "itemID" = ?', (replacement_item, retired_item))
|
||||
|
||||
saveddata_engine.execute('UPDATE "modules" SET "itemID" = ? WHERE "itemID" = ?',
|
||||
(replacement_item, retired_item))
|
||||
saveddata_engine.execute('UPDATE "cargo" SET "itemID" = ? WHERE "itemID" = ?',
|
||||
(replacement_item, retired_item))
|
||||
|
||||
@@ -7,7 +7,6 @@ Migration 12
|
||||
modules with their new replacements
|
||||
"""
|
||||
|
||||
|
||||
CONVERSIONS = {
|
||||
16457: ( # Crosslink Compact Ballistic Control System
|
||||
16459, # Muon Coil Bolt Array I
|
||||
@@ -330,11 +329,12 @@ CONVERSIONS = {
|
||||
),
|
||||
}
|
||||
|
||||
def upgrade(saveddata_engine):
|
||||
|
||||
def upgrade(saveddata_engine):
|
||||
# Convert modules
|
||||
for replacement_item, list in CONVERSIONS.iteritems():
|
||||
for retired_item in list:
|
||||
saveddata_engine.execute('UPDATE "modules" SET "itemID" = ? WHERE "itemID" = ?', (replacement_item, retired_item))
|
||||
saveddata_engine.execute('UPDATE "cargo" SET "itemID" = ? WHERE "itemID" = ?', (replacement_item, retired_item))
|
||||
|
||||
saveddata_engine.execute('UPDATE "modules" SET "itemID" = ? WHERE "itemID" = ?',
|
||||
(replacement_item, retired_item))
|
||||
saveddata_engine.execute('UPDATE "cargo" SET "itemID" = ? WHERE "itemID" = ?',
|
||||
(replacement_item, retired_item))
|
||||
|
||||
@@ -6,10 +6,11 @@ Migration 13
|
||||
|
||||
import sqlalchemy
|
||||
|
||||
|
||||
def upgrade(saveddata_engine):
|
||||
# Update fits schema to include implant location attribute
|
||||
try:
|
||||
saveddata_engine.execute("SELECT implantLocation FROM fits LIMIT 1")
|
||||
except sqlalchemy.exc.DatabaseError:
|
||||
saveddata_engine.execute("ALTER TABLE fits ADD COLUMN implantLocation INTEGER;")
|
||||
saveddata_engine.execute("UPDATE fits SET implantLocation = 0")
|
||||
saveddata_engine.execute("UPDATE fits SET implantLocation = 0")
|
||||
|
||||
@@ -6,8 +6,10 @@ Migration 14
|
||||
|
||||
import sqlalchemy
|
||||
|
||||
|
||||
def upgrade(saveddata_engine):
|
||||
if saveddata_engine.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='fighters'").scalar() == 'fighters':
|
||||
if saveddata_engine.execute(
|
||||
"SELECT name FROM sqlite_master WHERE type='table' AND name='fighters'").scalar() == 'fighters':
|
||||
# Fighters table exists
|
||||
try:
|
||||
saveddata_engine.execute("SELECT active FROM fighters LIMIT 1")
|
||||
@@ -16,4 +18,4 @@ def upgrade(saveddata_engine):
|
||||
# (they will be recreated)
|
||||
|
||||
saveddata_engine.execute("DROP TABLE fighters")
|
||||
saveddata_engine.execute("DROP TABLE fightersAbilities")
|
||||
saveddata_engine.execute("DROP TABLE fightersAbilities")
|
||||
|
||||
@@ -4,10 +4,8 @@ Migration 15
|
||||
- Delete projected modules on citadels
|
||||
"""
|
||||
|
||||
import sqlalchemy
|
||||
|
||||
def upgrade(saveddata_engine):
|
||||
|
||||
sql = """
|
||||
DELETE FROM modules WHERE ID IN
|
||||
(
|
||||
|
||||
@@ -6,6 +6,7 @@ Migration 16
|
||||
|
||||
import sqlalchemy
|
||||
|
||||
|
||||
def upgrade(saveddata_engine):
|
||||
# Update fits schema to include notes attribute
|
||||
try:
|
||||
|
||||
@@ -4,8 +4,6 @@ Migration 17
|
||||
- Moves all fleet boosters to the new schema
|
||||
"""
|
||||
|
||||
import sqlalchemy
|
||||
|
||||
|
||||
def upgrade(saveddata_engine):
|
||||
from eos.db import saveddata_session
|
||||
@@ -33,7 +31,8 @@ def upgrade(saveddata_engine):
|
||||
|
||||
inserts.append({"boosterID": value, "boostedID": boosted, "active": 1})
|
||||
try:
|
||||
saveddata_session.execute(commandFits_table.insert(), {"boosterID": value, "boostedID": boosted, "active": 1})
|
||||
except Exception, e:
|
||||
saveddata_session.execute(commandFits_table.insert(),
|
||||
{"boosterID": value, "boostedID": boosted, "active": 1})
|
||||
except Exception:
|
||||
pass
|
||||
saveddata_session.commit()
|
||||
|
||||
@@ -4,27 +4,26 @@ Migration 8
|
||||
- Converts modules from old Warfare Links to Command Modules
|
||||
"""
|
||||
|
||||
|
||||
CONVERSIONS = {
|
||||
42526: ( # Armor Command Burst I
|
||||
20069, # Armored Warfare Link - Damage Control I
|
||||
20409, # Armored Warfare Link - Passive Defense I
|
||||
22227, # Armored Warfare Link - Rapid Repair I
|
||||
20069, # Armored Warfare Link - Damage Control I
|
||||
20409, # Armored Warfare Link - Passive Defense I
|
||||
22227, # Armored Warfare Link - Rapid Repair I
|
||||
),
|
||||
43552: ( # Armor Command Burst II
|
||||
4264, # Armored Warfare Link - Damage Control II
|
||||
4266, # Armored Warfare Link - Passive Defense II
|
||||
4266, # Armored Warfare Link - Rapid Repair II
|
||||
4264, # Armored Warfare Link - Damage Control II
|
||||
4266, # Armored Warfare Link - Passive Defense II
|
||||
4266, # Armored Warfare Link - Rapid Repair II
|
||||
),
|
||||
42527: ( # Information Command Burst I
|
||||
11052, # Information Warfare Link - Sensor Integrity I
|
||||
20405, # Information Warfare Link - Recon Operation I
|
||||
20406, # Information Warfare Link - Electronic Superiority I
|
||||
11052, # Information Warfare Link - Sensor Integrity I
|
||||
20405, # Information Warfare Link - Recon Operation I
|
||||
20406, # Information Warfare Link - Electronic Superiority I
|
||||
),
|
||||
43554: ( # Information Command Burst II
|
||||
4268, # Information Warfare Link - Electronic Superiority II
|
||||
4270, # Information Warfare Link - Recon Operation II
|
||||
4272, # Information Warfare Link - Sensor Integrity II
|
||||
4268, # Information Warfare Link - Electronic Superiority II
|
||||
4270, # Information Warfare Link - Recon Operation II
|
||||
4272, # Information Warfare Link - Sensor Integrity II
|
||||
),
|
||||
42529: ( # Shield Command Burst I
|
||||
20124, # Siege Warfare Link - Active Shielding I
|
||||
@@ -34,17 +33,17 @@ CONVERSIONS = {
|
||||
43555: ( # Shield Command Burst II
|
||||
4280, # Siege Warfare Link - Active Shielding II
|
||||
4282, # Siege Warfare Link - Shield Efficiency II
|
||||
4284 # Siege Warfare Link - Shield Harmonizing II
|
||||
4284 # Siege Warfare Link - Shield Harmonizing II
|
||||
),
|
||||
42530: ( # Skirmish Command Burst I
|
||||
11017, # Skirmish Warfare Link - Interdiction Maneuvers I
|
||||
20070, # Skirmish Warfare Link - Evasive Maneuvers I
|
||||
20408, # Skirmish Warfare Link - Rapid Deployment I
|
||||
11017, # Skirmish Warfare Link - Interdiction Maneuvers I
|
||||
20070, # Skirmish Warfare Link - Evasive Maneuvers I
|
||||
20408, # Skirmish Warfare Link - Rapid Deployment I
|
||||
),
|
||||
43556: ( # Skirmish Command Burst II
|
||||
4286, # Skirmish Warfare Link - Evasive Maneuvers II
|
||||
4288, # Skirmish Warfare Link - Interdiction Maneuvers II
|
||||
4290 # Skirmish Warfare Link - Rapid Deployment II
|
||||
4290 # Skirmish Warfare Link - Rapid Deployment II
|
||||
),
|
||||
42528: ( # Mining Foreman Burst I
|
||||
22553, # Mining Foreman Link - Harvester Capacitor Efficiency I
|
||||
@@ -54,15 +53,16 @@ CONVERSIONS = {
|
||||
43551: ( # Mining Foreman Burst II
|
||||
4274, # Mining Foreman Link - Harvester Capacitor Efficiency II
|
||||
4276, # Mining Foreman Link - Laser Optimization II
|
||||
4278 # Mining Foreman Link - Mining Laser Field Enhancement II
|
||||
4278 # Mining Foreman Link - Mining Laser Field Enhancement II
|
||||
),
|
||||
}
|
||||
|
||||
def upgrade(saveddata_engine):
|
||||
|
||||
def upgrade(saveddata_engine):
|
||||
# Convert modules
|
||||
for replacement_item, list in CONVERSIONS.iteritems():
|
||||
for retired_item in list:
|
||||
saveddata_engine.execute('UPDATE "modules" SET "itemID" = ? WHERE "itemID" = ?', (replacement_item, retired_item))
|
||||
saveddata_engine.execute('UPDATE "cargo" SET "itemID" = ? WHERE "itemID" = ?', (replacement_item, retired_item))
|
||||
|
||||
saveddata_engine.execute('UPDATE "modules" SET "itemID" = ? WHERE "itemID" = ?',
|
||||
(replacement_item, retired_item))
|
||||
saveddata_engine.execute('UPDATE "cargo" SET "itemID" = ? WHERE "itemID" = ?',
|
||||
(replacement_item, retired_item))
|
||||
|
||||
@@ -4,17 +4,15 @@ Migration 19
|
||||
- Deletes broken references to fits from the commandFits table (see GH issue #844)
|
||||
"""
|
||||
|
||||
import sqlalchemy
|
||||
|
||||
|
||||
def upgrade(saveddata_engine):
|
||||
from eos.db import saveddata_session
|
||||
|
||||
sql = """
|
||||
DELETE FROM commandFits
|
||||
WHERE boosterID NOT IN (select ID from fits)
|
||||
OR boostedID NOT IN (select ID from fits)
|
||||
"""
|
||||
DELETE FROM commandFits
|
||||
WHERE boosterID NOT IN (select ID from fits)
|
||||
OR boostedID NOT IN (select ID from fits)
|
||||
"""
|
||||
|
||||
saveddata_session.execute(sql)
|
||||
saveddata_session.commit()
|
||||
|
||||
@@ -6,6 +6,7 @@ Migration 2
|
||||
|
||||
import sqlalchemy
|
||||
|
||||
|
||||
def upgrade(saveddata_engine):
|
||||
# Update characters schema to include default chars
|
||||
try:
|
||||
|
||||
15
eos/db/migrations/upgrade20.py
Normal file
15
eos/db/migrations/upgrade20.py
Normal file
@@ -0,0 +1,15 @@
|
||||
"""
|
||||
Migration 20
|
||||
|
||||
- Adds support for alpha clones to the characters table
|
||||
"""
|
||||
|
||||
import sqlalchemy
|
||||
|
||||
|
||||
def upgrade(saveddata_engine):
|
||||
# Update characters schema to include alphaCloneID
|
||||
try:
|
||||
saveddata_engine.execute("SELECT alphaCloneID FROM characters LIMIT 1")
|
||||
except sqlalchemy.exc.DatabaseError:
|
||||
saveddata_engine.execute("ALTER TABLE characters ADD COLUMN alphaCloneID INTEGER;")
|
||||
10
eos/db/migrations/upgrade21.py
Normal file
10
eos/db/migrations/upgrade21.py
Normal file
@@ -0,0 +1,10 @@
|
||||
"""
|
||||
Migration 21
|
||||
|
||||
- Fixes discrepancy in drone table where we may have an amount active that is not equal to the amount in the stack
|
||||
(we don't support activating only 2/5 drones). See GH issue #728
|
||||
"""
|
||||
|
||||
|
||||
def upgrade(saveddata_engine):
|
||||
saveddata_engine.execute("UPDATE drones SET amountActive = amount where amountActive > 0 AND amountActive <> amount;")
|
||||
@@ -6,6 +6,7 @@ Migration 3
|
||||
|
||||
import sqlalchemy
|
||||
|
||||
|
||||
def upgrade(saveddata_engine):
|
||||
try:
|
||||
saveddata_engine.execute("SELECT modeID FROM fits LIMIT 1")
|
||||
|
||||
@@ -10,7 +10,6 @@ Migration 4
|
||||
and output of itemDiff.py
|
||||
"""
|
||||
|
||||
|
||||
CONVERSIONS = {
|
||||
506: ( # 'Basic' Capacitor Power Relay
|
||||
8205, # Alpha Reactor Control: Capacitor Power Relay
|
||||
@@ -131,11 +130,12 @@ CONVERSIONS = {
|
||||
),
|
||||
}
|
||||
|
||||
def upgrade(saveddata_engine):
|
||||
|
||||
def upgrade(saveddata_engine):
|
||||
# Convert modules
|
||||
for replacement_item, list in CONVERSIONS.iteritems():
|
||||
for retired_item in list:
|
||||
saveddata_engine.execute('UPDATE "modules" SET "itemID" = ? WHERE "itemID" = ?', (replacement_item, retired_item))
|
||||
saveddata_engine.execute('UPDATE "cargo" SET "itemID" = ? WHERE "itemID" = ?', (replacement_item, retired_item))
|
||||
|
||||
saveddata_engine.execute('UPDATE "modules" SET "itemID" = ? WHERE "itemID" = ?',
|
||||
(replacement_item, retired_item))
|
||||
saveddata_engine.execute('UPDATE "cargo" SET "itemID" = ? WHERE "itemID" = ?',
|
||||
(replacement_item, retired_item))
|
||||
|
||||
@@ -4,5 +4,6 @@ Migration 5
|
||||
Simply deletes damage profiles with a blank name. See GH issue #256
|
||||
"""
|
||||
|
||||
|
||||
def upgrade(saveddata_engine):
|
||||
saveddata_engine.execute('DELETE FROM damagePatterns WHERE name LIKE ?', ("",))
|
||||
|
||||
@@ -4,6 +4,8 @@ Migration 6
|
||||
Overwrites damage profile 0 to reset bad uniform values (bad values set with bug)
|
||||
"""
|
||||
|
||||
|
||||
def upgrade(saveddata_engine):
|
||||
saveddata_engine.execute('DELETE FROM damagePatterns WHERE name LIKE ? OR ID LIKE ?', ("Uniform", "1"))
|
||||
saveddata_engine.execute('INSERT INTO damagePatterns VALUES (?, ?, ?, ?, ?, ?, ?)', (1, "Uniform", 25, 25, 25, 25, None))
|
||||
saveddata_engine.execute('INSERT INTO damagePatterns VALUES (?, ?, ?, ?, ?, ?, ?)',
|
||||
(1, "Uniform", 25, 25, 25, 25, None))
|
||||
|
||||
@@ -8,17 +8,16 @@ Migration 7
|
||||
Pyfa.
|
||||
"""
|
||||
|
||||
|
||||
CONVERSIONS = {
|
||||
640: ( # Scorpion
|
||||
4005, # Scorpion Ishukone Watch
|
||||
)
|
||||
}
|
||||
|
||||
def upgrade(saveddata_engine):
|
||||
|
||||
def upgrade(saveddata_engine):
|
||||
# Convert ships
|
||||
for replacement_item, list in CONVERSIONS.iteritems():
|
||||
for retired_item in list:
|
||||
saveddata_engine.execute('UPDATE "fits" SET "shipID" = ? WHERE "shipID" = ?', (replacement_item, retired_item))
|
||||
|
||||
saveddata_engine.execute('UPDATE "fits" SET "shipID" = ? WHERE "shipID" = ?',
|
||||
(replacement_item, retired_item))
|
||||
|
||||
@@ -7,7 +7,6 @@ Migration 8
|
||||
modules with their new replacements
|
||||
"""
|
||||
|
||||
|
||||
CONVERSIONS = {
|
||||
8529: ( # Large F-S9 Regolith Compact Shield Extender
|
||||
8409, # Large Subordinate Screen Stabilizer I
|
||||
@@ -71,15 +70,16 @@ CONVERSIONS = {
|
||||
11321, # 800mm Reinforced Nanofiber Plates I
|
||||
),
|
||||
11317: ( # 800mm Rolled Tungsten Compact Plates
|
||||
11315, # 800mm Reinforced Titanium Plates I
|
||||
11315, # 800mm Reinforced Titanium Plates I
|
||||
),
|
||||
}
|
||||
|
||||
def upgrade(saveddata_engine):
|
||||
|
||||
def upgrade(saveddata_engine):
|
||||
# Convert modules
|
||||
for replacement_item, list in CONVERSIONS.iteritems():
|
||||
for retired_item in list:
|
||||
saveddata_engine.execute('UPDATE "modules" SET "itemID" = ? WHERE "itemID" = ?', (replacement_item, retired_item))
|
||||
saveddata_engine.execute('UPDATE "cargo" SET "itemID" = ? WHERE "itemID" = ?', (replacement_item, retired_item))
|
||||
|
||||
saveddata_engine.execute('UPDATE "modules" SET "itemID" = ? WHERE "itemID" = ?',
|
||||
(replacement_item, retired_item))
|
||||
saveddata_engine.execute('UPDATE "cargo" SET "itemID" = ? WHERE "itemID" = ?',
|
||||
(replacement_item, retired_item))
|
||||
|
||||
@@ -16,8 +16,10 @@ CREATE TABLE boostersTemp (
|
||||
)
|
||||
"""
|
||||
|
||||
|
||||
def upgrade(saveddata_engine):
|
||||
saveddata_engine.execute(tmpTable)
|
||||
saveddata_engine.execute("INSERT INTO boostersTemp (ID, itemID, fitID, active) SELECT ID, itemID, fitID, active FROM boosters")
|
||||
saveddata_engine.execute(
|
||||
"INSERT INTO boostersTemp (ID, itemID, fitID, active) SELECT ID, itemID, fitID, active FROM boosters")
|
||||
saveddata_engine.execute("DROP TABLE boosters")
|
||||
saveddata_engine.execute("ALTER TABLE boostersTemp RENAME TO boosters")
|
||||
|
||||
@@ -22,7 +22,7 @@ from sqlalchemy.ext.associationproxy import association_proxy
|
||||
from sqlalchemy.orm import mapper, relation
|
||||
|
||||
from eos.db import saveddata_meta
|
||||
from eos.types import Booster
|
||||
from eos.saveddata.booster import Booster
|
||||
|
||||
boosters_table = Table("boosters", saveddata_meta,
|
||||
Column("ID", Integer, primary_key=True),
|
||||
|
||||
@@ -21,7 +21,7 @@ from sqlalchemy import Table, Column, Integer, ForeignKey
|
||||
from sqlalchemy.orm import mapper
|
||||
|
||||
from eos.db import saveddata_meta
|
||||
from eos.types import Cargo
|
||||
from eos.saveddata.cargo import Cargo
|
||||
|
||||
cargo_table = Table("cargo", saveddata_meta,
|
||||
Column("ID", Integer, primary_key=True),
|
||||
|
||||
@@ -23,7 +23,9 @@ from sqlalchemy.orm import relation, mapper
|
||||
from eos.db import saveddata_meta
|
||||
from eos.db.saveddata.implant import charImplants_table
|
||||
from eos.effectHandlerHelpers import HandledImplantBoosterList
|
||||
from eos.types import Character, User, Skill, Implant
|
||||
from eos.saveddata.implant import Implant
|
||||
from eos.saveddata.user import User
|
||||
from eos.saveddata.character import Character, Skill
|
||||
|
||||
characters_table = Table("characters", saveddata_meta,
|
||||
Column("ID", Integer, primary_key=True),
|
||||
@@ -33,10 +35,12 @@ characters_table = Table("characters", saveddata_meta,
|
||||
Column("defaultChar", Integer),
|
||||
Column("chars", String, nullable=True),
|
||||
Column("defaultLevel", Integer, nullable=True),
|
||||
Column("alphaCloneID", Integer, nullable=True),
|
||||
Column("ownerID", ForeignKey("users.ID"), nullable=True))
|
||||
|
||||
mapper(Character, characters_table,
|
||||
properties={
|
||||
"_Character__alphaCloneID": characters_table.c.alphaCloneID,
|
||||
"savedName": characters_table.c.name,
|
||||
"_Character__owner": relation(
|
||||
User,
|
||||
|
||||
@@ -21,7 +21,7 @@ from sqlalchemy import Table, Column, Integer, String
|
||||
from sqlalchemy.orm import mapper
|
||||
|
||||
from eos.db import saveddata_meta
|
||||
from eos.types import CrestChar
|
||||
from eos.saveddata.crestchar import CrestChar
|
||||
|
||||
crest_table = Table("crest", saveddata_meta,
|
||||
Column("ID", Integer, primary_key=True),
|
||||
|
||||
@@ -21,7 +21,7 @@ from sqlalchemy import Table, Column, Integer, ForeignKey, String
|
||||
from sqlalchemy.orm import mapper
|
||||
|
||||
from eos.db import saveddata_meta
|
||||
from eos.types import DamagePattern
|
||||
from eos.saveddata.damagePattern import DamagePattern
|
||||
|
||||
damagePatterns_table = Table("damagePatterns", saveddata_meta,
|
||||
Column("ID", Integer, primary_key=True),
|
||||
|
||||
@@ -17,88 +17,223 @@
|
||||
# along with pyfa. If not, see <http://www.gnu.org/licenses/>.
|
||||
# ===============================================================================
|
||||
|
||||
import sqlalchemy
|
||||
import logging
|
||||
from sqlalchemy.exc import DatabaseError
|
||||
from logbook import Logger
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
class DatabaseCleanup:
|
||||
class DatabaseCleanup(object):
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def OrphanedCharacterSkills(saveddata_engine):
|
||||
# Finds and fixes database corruption issues.
|
||||
logger.debug("Start databsae validation and cleanup.")
|
||||
def ExecuteSQLQuery(saveddata_engine, query):
|
||||
try:
|
||||
results = saveddata_engine.execute(query)
|
||||
return results
|
||||
except DatabaseError:
|
||||
pyfalog.error("Failed to connect to database or error executing query:\n{0}", query)
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def OrphanedCharacterSkills(saveddata_engine):
|
||||
# Find orphaned character skills.
|
||||
# This solves an issue where the character doesn't exist, but skills for that character do.
|
||||
# See issue #917
|
||||
try:
|
||||
logger.debug("Running database cleanup for character skills.")
|
||||
results = saveddata_engine.execute("SELECT COUNT(*) AS num FROM characterSkills "
|
||||
"WHERE characterID NOT IN (SELECT ID from characters)")
|
||||
row = results.first()
|
||||
pyfalog.debug("Running database cleanup for character skills.")
|
||||
query = "SELECT COUNT(*) AS num FROM characterSkills WHERE characterID NOT IN (SELECT ID from characters)"
|
||||
results = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, query)
|
||||
|
||||
if row and row['num']:
|
||||
delete = saveddata_engine.execute("DELETE FROM characterSkills WHERE characterID NOT IN (SELECT ID from characters)")
|
||||
logger.error("Database corruption found. Cleaning up %d records.", delete.rowcount)
|
||||
if results is None:
|
||||
return
|
||||
|
||||
except sqlalchemy.exc.DatabaseError:
|
||||
logger.error("Failed to connect to database.")
|
||||
row = results.first()
|
||||
|
||||
if row and row['num']:
|
||||
query = "DELETE FROM characterSkills WHERE characterID NOT IN (SELECT ID from characters)"
|
||||
delete = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, query)
|
||||
pyfalog.error("Database corruption found. Cleaning up {0} records.", delete.rowcount)
|
||||
|
||||
@staticmethod
|
||||
def OrphanedFitDamagePatterns(saveddata_engine):
|
||||
# Find orphaned damage patterns.
|
||||
# This solves an issue where the damage pattern doesn't exist, but fits reference the pattern.
|
||||
# See issue #777
|
||||
try:
|
||||
logger.debug("Running database cleanup for orphaned damage patterns attached to fits.")
|
||||
pyfalog.debug("Running database cleanup for orphaned damage patterns attached to fits.")
|
||||
query = "SELECT COUNT(*) AS num FROM fits WHERE damagePatternID NOT IN (SELECT ID FROM damagePatterns) OR damagePatternID IS NULL"
|
||||
results = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, query)
|
||||
|
||||
results = saveddata_engine.execute("SELECT COUNT(*) AS num FROM fits WHERE damagePatternID NOT IN (SELECT ID FROM damagePatterns) OR damagePatternID IS NULL")
|
||||
row = results.first()
|
||||
if results is None:
|
||||
return
|
||||
|
||||
if row and row['num']:
|
||||
# Get Uniform damage pattern ID
|
||||
query = saveddata_engine.execute("SELECT ID FROM damagePatterns WHERE name = 'Uniform'")
|
||||
rows = query.fetchall()
|
||||
row = results.first()
|
||||
|
||||
if len(rows) == 0:
|
||||
logger.error("Missing uniform damage pattern.")
|
||||
elif len(rows) > 1:
|
||||
logger.error("More than one uniform damage pattern found.")
|
||||
else:
|
||||
uniform_damage_pattern_id = rows[0]['ID']
|
||||
update = saveddata_engine.execute("UPDATE 'fits' SET 'damagePatternID' = ? "
|
||||
"WHERE damagePatternID NOT IN (SELECT ID FROM damagePatterns) OR damagePatternID IS NULL",
|
||||
uniform_damage_pattern_id)
|
||||
logger.error("Database corruption found. Cleaning up %d records.", update.rowcount)
|
||||
except sqlalchemy.exc.DatabaseError:
|
||||
logger.error("Failed to connect to database.")
|
||||
if row and row['num']:
|
||||
# Get Uniform damage pattern ID
|
||||
uniform_query = "SELECT ID FROM damagePatterns WHERE name = 'Uniform'"
|
||||
uniform_results = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, uniform_query)
|
||||
|
||||
if uniform_results is None:
|
||||
return
|
||||
|
||||
rows = uniform_results.fetchall()
|
||||
|
||||
if len(rows) == 0:
|
||||
pyfalog.error("Missing uniform damage pattern.")
|
||||
elif len(rows) > 1:
|
||||
pyfalog.error("More than one uniform damage pattern found.")
|
||||
else:
|
||||
uniform_damage_pattern_id = rows[0]['ID']
|
||||
update_query = "UPDATE 'fits' SET 'damagePatternID' = {} " \
|
||||
"WHERE damagePatternID NOT IN (SELECT ID FROM damagePatterns) OR damagePatternID IS NULL".format(uniform_damage_pattern_id)
|
||||
update_results = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, update_query)
|
||||
pyfalog.error("Database corruption found. Cleaning up {0} records.", update_results.rowcount)
|
||||
|
||||
@staticmethod
|
||||
def OrphanedFitCharacterIDs(saveddata_engine):
|
||||
# Find orphaned character IDs. This solves an issue where the character doesn't exist, but fits reference the pattern.
|
||||
try:
|
||||
logger.debug("Running database cleanup for orphaned characters attached to fits.")
|
||||
results = saveddata_engine.execute("SELECT COUNT(*) AS num FROM fits WHERE characterID NOT IN (SELECT ID FROM characters) OR characterID IS NULL")
|
||||
pyfalog.debug("Running database cleanup for orphaned characters attached to fits.")
|
||||
query = "SELECT COUNT(*) AS num FROM fits WHERE characterID NOT IN (SELECT ID FROM characters) OR characterID IS NULL"
|
||||
results = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, query)
|
||||
|
||||
if results is None:
|
||||
return
|
||||
|
||||
row = results.first()
|
||||
|
||||
if row and row['num']:
|
||||
# Get All 5 character ID
|
||||
all5_query = "SELECT ID FROM characters WHERE name = 'All 5'"
|
||||
all5_results = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, all5_query)
|
||||
|
||||
if all5_results is None:
|
||||
return
|
||||
|
||||
rows = all5_results.fetchall()
|
||||
|
||||
if len(rows) == 0:
|
||||
pyfalog.error("Missing 'All 5' character.")
|
||||
elif len(rows) > 1:
|
||||
pyfalog.error("More than one 'All 5' character found.")
|
||||
else:
|
||||
all5_id = rows[0]['ID']
|
||||
update_query = "UPDATE 'fits' SET 'characterID' = " + str(all5_id) + \
|
||||
" WHERE characterID not in (select ID from characters) OR characterID IS NULL"
|
||||
update_results = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, update_query)
|
||||
pyfalog.error("Database corruption found. Cleaning up {0} records.", update_results.rowcount)
|
||||
|
||||
@staticmethod
|
||||
def NullDamagePatternNames(saveddata_engine):
|
||||
# Find damage patterns that are missing the name.
|
||||
# This solves an issue where the damage pattern ends up with a name that is null.
|
||||
# See issue #949
|
||||
pyfalog.debug("Running database cleanup for missing damage pattern names.")
|
||||
query = "SELECT COUNT(*) AS num FROM damagePatterns WHERE name IS NULL OR name = ''"
|
||||
results = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, query)
|
||||
|
||||
if results is None:
|
||||
return
|
||||
|
||||
row = results.first()
|
||||
|
||||
if row and row['num']:
|
||||
query = "DELETE FROM damagePatterns WHERE name IS NULL OR name = ''"
|
||||
delete = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, query)
|
||||
pyfalog.error("Database corruption found. Cleaning up {0} records.", delete.rowcount)
|
||||
|
||||
@staticmethod
|
||||
def NullTargetResistNames(saveddata_engine):
|
||||
# Find target resists that are missing the name.
|
||||
# This solves an issue where the target resist ends up with a name that is null.
|
||||
# See issue #949
|
||||
pyfalog.debug("Running database cleanup for missing target resist names.")
|
||||
query = "SELECT COUNT(*) AS num FROM targetResists WHERE name IS NULL OR name = ''"
|
||||
results = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, query)
|
||||
|
||||
if results is None:
|
||||
return
|
||||
|
||||
row = results.first()
|
||||
|
||||
if row and row['num']:
|
||||
query = "DELETE FROM targetResists WHERE name IS NULL OR name = ''"
|
||||
delete = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, query)
|
||||
pyfalog.error("Database corruption found. Cleaning up {0} records.", delete.rowcount)
|
||||
|
||||
@staticmethod
|
||||
def OrphanedFitIDItemID(saveddata_engine):
|
||||
# Orphaned items that are missing the fit ID or item ID.
|
||||
# See issue #954
|
||||
for table in ['drones', 'cargo', 'fighters']:
|
||||
pyfalog.debug("Running database cleanup for orphaned {0} items.", table)
|
||||
query = "SELECT COUNT(*) AS num FROM {} WHERE itemID IS NULL OR itemID = '' or itemID = '0' or fitID IS NULL OR fitID = '' or fitID = '0'".format(
|
||||
table)
|
||||
results = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, query)
|
||||
|
||||
if results is None:
|
||||
return
|
||||
|
||||
row = results.first()
|
||||
|
||||
if row['num']:
|
||||
# Get All 5 character ID
|
||||
query = saveddata_engine.execute("SELECT ID FROM characters WHERE name = 'All 5'")
|
||||
rows = query.fetchall()
|
||||
if row and row['num']:
|
||||
query = "DELETE FROM {} WHERE itemID IS NULL OR itemID = '' or itemID = '0' or fitID IS NULL OR fitID = '' or fitID = '0'".format(
|
||||
table)
|
||||
delete = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, query)
|
||||
pyfalog.error("Database corruption found. Cleaning up {0} records.", delete.rowcount)
|
||||
|
||||
if len(rows) == 0:
|
||||
logger.error("Missing 'All 5' character.")
|
||||
elif len(rows) > 1:
|
||||
logger.error("More than one 'All 5' character found.")
|
||||
else:
|
||||
all5_id = rows[0]['ID']
|
||||
update = saveddata_engine.execute("UPDATE 'fits' SET 'characterID' = ? "
|
||||
"WHERE characterID not in (select ID from characters) OR characterID IS NULL",
|
||||
all5_id)
|
||||
logger.error("Database corruption found. Cleaning up %d records.", update.rowcount)
|
||||
except sqlalchemy.exc.DatabaseError:
|
||||
logger.error("Failed to connect to database.")
|
||||
for table in ['modules']:
|
||||
pyfalog.debug("Running database cleanup for orphaned {0} items.", table)
|
||||
query = "SELECT COUNT(*) AS num FROM {} WHERE itemID = '0' or fitID IS NULL OR fitID = '' or fitID = '0'".format(
|
||||
table)
|
||||
results = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, query)
|
||||
|
||||
if results is None:
|
||||
return
|
||||
|
||||
row = results.first()
|
||||
|
||||
if row and row['num']:
|
||||
query = "DELETE FROM {} WHERE itemID = '0' or fitID IS NULL OR fitID = '' or fitID = '0'".format(table)
|
||||
delete = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, query)
|
||||
pyfalog.error("Database corruption found. Cleaning up {0} records.", delete.rowcount)
|
||||
|
||||
@staticmethod
|
||||
def NullDamageTargetPatternValues(saveddata_engine):
|
||||
# Find patterns that have null values
|
||||
# See issue #954
|
||||
for profileType in ['damagePatterns', 'targetResists']:
|
||||
for damageType in ['em', 'thermal', 'kinetic', 'explosive']:
|
||||
pyfalog.debug("Running database cleanup for null {0} values. ({1})", profileType, damageType)
|
||||
query = "SELECT COUNT(*) AS num FROM {0} WHERE {1}Amount IS NULL OR {1}Amount = ''".format(profileType,
|
||||
damageType)
|
||||
results = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, query)
|
||||
|
||||
if results is None:
|
||||
return
|
||||
|
||||
row = results.first()
|
||||
|
||||
if row and row['num']:
|
||||
query = "UPDATE '{0}' SET '{1}Amount' = '0' WHERE {1}Amount IS NULL OR Amount = ''".format(profileType,
|
||||
damageType)
|
||||
delete = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, query)
|
||||
pyfalog.error("Database corruption found. Cleaning up {0} records.", delete.rowcount)
|
||||
|
||||
@staticmethod
|
||||
def DuplicateSelectedAmmoName(saveddata_engine):
|
||||
# Orphaned items that are missing the fit ID or item ID.
|
||||
# See issue #954
|
||||
pyfalog.debug("Running database cleanup for duplicated selected ammo profiles.")
|
||||
query = "SELECT COUNT(*) AS num FROM damagePatterns WHERE name = 'Selected Ammo'"
|
||||
results = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, query)
|
||||
|
||||
if results is None:
|
||||
return
|
||||
|
||||
row = results.first()
|
||||
|
||||
if row and row['num'] > 1:
|
||||
query = "DELETE FROM damagePatterns WHERE name = 'Selected Ammo'"
|
||||
delete = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, query)
|
||||
pyfalog.error("Database corruption found. Cleaning up {0} records.", delete.rowcount)
|
||||
|
||||
@@ -21,7 +21,7 @@ from sqlalchemy import Table, Column, Integer, ForeignKey, Boolean
|
||||
from sqlalchemy.orm import mapper
|
||||
|
||||
from eos.db import saveddata_meta
|
||||
from eos.types import Drone
|
||||
from eos.saveddata.drone import Drone
|
||||
|
||||
drones_table = Table("drones", saveddata_meta,
|
||||
Column("groupID", Integer, primary_key=True),
|
||||
|
||||
@@ -18,11 +18,12 @@
|
||||
# ===============================================================================
|
||||
|
||||
from sqlalchemy import Table, Column, Integer, ForeignKey, Boolean
|
||||
from sqlalchemy.orm import *
|
||||
from sqlalchemy.orm import mapper, relation
|
||||
|
||||
from eos.db import saveddata_meta
|
||||
from eos.types import Fighter, Fit
|
||||
from eos.types import FighterAbility
|
||||
from eos.saveddata.fighterAbility import FighterAbility
|
||||
from eos.saveddata.fighter import Fighter
|
||||
from eos.saveddata.fit import Fit
|
||||
|
||||
fighters_table = Table("fighters", saveddata_meta,
|
||||
Column("groupID", Integer, primary_key=True),
|
||||
|
||||
@@ -17,21 +17,32 @@
|
||||
# along with eos. If not, see <http://www.gnu.org/licenses/>.
|
||||
# ===============================================================================
|
||||
|
||||
from sqlalchemy import *
|
||||
from sqlalchemy.ext.associationproxy import association_proxy
|
||||
from sqlalchemy.orm import *
|
||||
from sqlalchemy.orm.collections import attribute_mapped_collection
|
||||
from sqlalchemy.sql import and_
|
||||
from sqlalchemy.orm import relation, reconstructor, mapper, relationship
|
||||
from sqlalchemy import ForeignKey, Column, Integer, String, Table, Boolean
|
||||
|
||||
from eos.db import saveddata_meta
|
||||
from eos.db import saveddata_session
|
||||
from eos.db.saveddata.cargo import cargo_table
|
||||
from eos.db.saveddata.drone import drones_table
|
||||
from eos.db.saveddata.fighter import fighters_table
|
||||
from eos.db.saveddata.implant import fitImplants_table
|
||||
from eos.db.saveddata.module import modules_table
|
||||
from eos.effectHandlerHelpers import *
|
||||
from eos.types import Fit, Module, User, Booster, Drone, Fighter, Cargo, Implant, Character, DamagePattern, \
|
||||
TargetResists, ImplantLocation
|
||||
from eos.effectHandlerHelpers import HandledModuleList, HandledImplantBoosterList, HandledProjectedModList, \
|
||||
HandledDroneCargoList, HandledProjectedDroneList
|
||||
from eos.saveddata.implant import Implant
|
||||
from eos.saveddata.character import Character
|
||||
from eos.saveddata.user import User
|
||||
from eos.saveddata.fighter import Fighter
|
||||
from eos.saveddata.fit import Fit as es_Fit, ImplantLocation
|
||||
from eos.saveddata.drone import Drone
|
||||
from eos.saveddata.booster import Booster
|
||||
from eos.saveddata.module import Module
|
||||
from eos.saveddata.cargo import Cargo
|
||||
from eos.saveddata.damagePattern import DamagePattern
|
||||
from eos.saveddata.targetResists import TargetResists
|
||||
|
||||
fits_table = Table("fits", saveddata_meta,
|
||||
Column("ID", Integer, primary_key=True),
|
||||
@@ -45,7 +56,7 @@ fits_table = Table("fits", saveddata_meta,
|
||||
Column("targetResistsID", ForeignKey("targetResists.ID"), nullable=True),
|
||||
Column("modeID", Integer, nullable=True),
|
||||
Column("implantLocation", Integer, nullable=False, default=ImplantLocation.FIT),
|
||||
Column("notes", String, nullable = True),
|
||||
Column("notes", String, nullable=True),
|
||||
)
|
||||
|
||||
projectedFits_table = Table("projectedFits", saveddata_meta,
|
||||
@@ -61,6 +72,7 @@ commandFits_table = Table("commandFits", saveddata_meta,
|
||||
Column("active", Boolean, nullable=False, default=1)
|
||||
)
|
||||
|
||||
|
||||
class ProjectedFit(object):
|
||||
def __init__(self, sourceID, source_fit, amount=1, active=True):
|
||||
self.sourceID = sourceID
|
||||
@@ -72,9 +84,9 @@ class ProjectedFit(object):
|
||||
def init(self):
|
||||
if self.source_fit.isInvalid:
|
||||
# Very rare for this to happen, but be prepared for it
|
||||
eos.db.saveddata_session.delete(self.source_fit)
|
||||
eos.db.saveddata_session.flush()
|
||||
eos.db.saveddata_session.refresh(self.victim_fit)
|
||||
saveddata_session.delete(self.source_fit)
|
||||
saveddata_session.flush()
|
||||
saveddata_session.refresh(self.victim_fit)
|
||||
|
||||
# We have a series of setters and getters here just in case someone
|
||||
# downgrades and screws up the table with NULL values
|
||||
@@ -91,6 +103,7 @@ class ProjectedFit(object):
|
||||
self.sourceID, self.victimID, self.amount, self.active, hex(id(self))
|
||||
)
|
||||
|
||||
|
||||
class CommandFit(object):
|
||||
def __init__(self, boosterID, booster_fit, active=True):
|
||||
self.boosterID = boosterID
|
||||
@@ -101,125 +114,126 @@ class CommandFit(object):
|
||||
def init(self):
|
||||
if self.booster_fit.isInvalid:
|
||||
# Very rare for this to happen, but be prepared for it
|
||||
eos.db.saveddata_session.delete(self.booster_fit)
|
||||
eos.db.saveddata_session.flush()
|
||||
eos.db.saveddata_session.refresh(self.boosted_fit)
|
||||
saveddata_session.delete(self.booster_fit)
|
||||
saveddata_session.flush()
|
||||
saveddata_session.refresh(self.boosted_fit)
|
||||
|
||||
def __repr__(self):
|
||||
return "CommandFit(boosterID={}, boostedID={}, active={}) at {}".format(
|
||||
self.boosterID, self.boostedID, self.active, hex(id(self))
|
||||
)
|
||||
|
||||
Fit._Fit__projectedFits = association_proxy(
|
||||
|
||||
es_Fit._Fit__projectedFits = association_proxy(
|
||||
"victimOf", # look at the victimOf association...
|
||||
"source_fit", # .. and return the source fits
|
||||
creator=lambda sourceID, source_fit: ProjectedFit(sourceID, source_fit)
|
||||
)
|
||||
|
||||
Fit._Fit__commandFits = association_proxy(
|
||||
es_Fit._Fit__commandFits = association_proxy(
|
||||
"boostedOf", # look at the boostedOf association...
|
||||
"booster_fit", # .. and return the booster fit
|
||||
creator=lambda boosterID, booster_fit: CommandFit(boosterID, booster_fit)
|
||||
)
|
||||
mapper(Fit, fits_table,
|
||||
properties={
|
||||
"_Fit__modules": relation(
|
||||
Module,
|
||||
collection_class=HandledModuleList,
|
||||
primaryjoin=and_(modules_table.c.fitID == fits_table.c.ID, modules_table.c.projected == False),
|
||||
order_by=modules_table.c.position,
|
||||
cascade='all, delete, delete-orphan'),
|
||||
"_Fit__projectedModules": relation(
|
||||
Module,
|
||||
collection_class=HandledProjectedModList,
|
||||
cascade='all, delete, delete-orphan',
|
||||
single_parent=True,
|
||||
primaryjoin=and_(modules_table.c.fitID == fits_table.c.ID, modules_table.c.projected == True)),
|
||||
"owner": relation(
|
||||
User,
|
||||
backref="fits"),
|
||||
"itemID": fits_table.c.shipID,
|
||||
"shipID": fits_table.c.shipID,
|
||||
"_Fit__boosters": relation(
|
||||
Booster,
|
||||
collection_class=HandledImplantBoosterList,
|
||||
cascade='all, delete, delete-orphan',
|
||||
single_parent=True),
|
||||
"_Fit__drones": relation(
|
||||
Drone,
|
||||
collection_class=HandledDroneCargoList,
|
||||
cascade='all, delete, delete-orphan',
|
||||
single_parent=True,
|
||||
primaryjoin=and_(drones_table.c.fitID == fits_table.c.ID, drones_table.c.projected == False)),
|
||||
"_Fit__fighters": relation(
|
||||
Fighter,
|
||||
collection_class=HandledDroneCargoList,
|
||||
cascade='all, delete, delete-orphan',
|
||||
single_parent=True,
|
||||
primaryjoin=and_(fighters_table.c.fitID == fits_table.c.ID, fighters_table.c.projected == False)),
|
||||
"_Fit__cargo": relation(
|
||||
Cargo,
|
||||
collection_class=HandledDroneCargoList,
|
||||
cascade='all, delete, delete-orphan',
|
||||
single_parent=True,
|
||||
primaryjoin=and_(cargo_table.c.fitID == fits_table.c.ID)),
|
||||
"_Fit__projectedDrones": relation(
|
||||
Drone,
|
||||
collection_class=HandledProjectedDroneList,
|
||||
cascade='all, delete, delete-orphan',
|
||||
single_parent=True,
|
||||
primaryjoin=and_(drones_table.c.fitID == fits_table.c.ID, drones_table.c.projected == True)),
|
||||
"_Fit__projectedFighters": relation(
|
||||
Fighter,
|
||||
collection_class=HandledProjectedDroneList,
|
||||
cascade='all, delete, delete-orphan',
|
||||
single_parent=True,
|
||||
primaryjoin=and_(fighters_table.c.fitID == fits_table.c.ID, fighters_table.c.projected == True)),
|
||||
"_Fit__implants": relation(
|
||||
Implant,
|
||||
collection_class=HandledImplantBoosterList,
|
||||
cascade='all, delete, delete-orphan',
|
||||
backref='fit',
|
||||
single_parent=True,
|
||||
primaryjoin=fitImplants_table.c.fitID == fits_table.c.ID,
|
||||
secondaryjoin=fitImplants_table.c.implantID == Implant.ID,
|
||||
secondary=fitImplants_table),
|
||||
"_Fit__character": relation(
|
||||
Character,
|
||||
backref="fits"),
|
||||
"_Fit__damagePattern": relation(DamagePattern),
|
||||
"_Fit__targetResists": relation(TargetResists),
|
||||
"projectedOnto": relationship(
|
||||
ProjectedFit,
|
||||
primaryjoin=projectedFits_table.c.sourceID == fits_table.c.ID,
|
||||
backref='source_fit',
|
||||
collection_class=attribute_mapped_collection('victimID'),
|
||||
cascade='all, delete, delete-orphan'),
|
||||
"victimOf": relationship(
|
||||
ProjectedFit,
|
||||
primaryjoin=fits_table.c.ID == projectedFits_table.c.victimID,
|
||||
backref='victim_fit',
|
||||
collection_class=attribute_mapped_collection('sourceID'),
|
||||
cascade='all, delete, delete-orphan'),
|
||||
"boostedOnto": relationship(
|
||||
CommandFit,
|
||||
primaryjoin=commandFits_table.c.boosterID == fits_table.c.ID,
|
||||
backref='booster_fit',
|
||||
collection_class=attribute_mapped_collection('boostedID'),
|
||||
cascade='all, delete, delete-orphan'),
|
||||
"boostedOf": relationship(
|
||||
CommandFit,
|
||||
primaryjoin=fits_table.c.ID == commandFits_table.c.boostedID,
|
||||
backref='boosted_fit',
|
||||
collection_class=attribute_mapped_collection('boosterID'),
|
||||
cascade='all, delete, delete-orphan'),
|
||||
}
|
||||
)
|
||||
mapper(es_Fit, fits_table,
|
||||
properties={
|
||||
"_Fit__modules": relation(
|
||||
Module,
|
||||
collection_class=HandledModuleList,
|
||||
primaryjoin=and_(modules_table.c.fitID == fits_table.c.ID, modules_table.c.projected == False), # noqa
|
||||
order_by=modules_table.c.position,
|
||||
cascade='all, delete, delete-orphan'),
|
||||
"_Fit__projectedModules": relation(
|
||||
Module,
|
||||
collection_class=HandledProjectedModList,
|
||||
cascade='all, delete, delete-orphan',
|
||||
single_parent=True,
|
||||
primaryjoin=and_(modules_table.c.fitID == fits_table.c.ID, modules_table.c.projected == True)), # noqa
|
||||
"owner": relation(
|
||||
User,
|
||||
backref="fits"),
|
||||
"itemID": fits_table.c.shipID,
|
||||
"shipID": fits_table.c.shipID,
|
||||
"_Fit__boosters": relation(
|
||||
Booster,
|
||||
collection_class=HandledImplantBoosterList,
|
||||
cascade='all, delete, delete-orphan',
|
||||
single_parent=True),
|
||||
"_Fit__drones": relation(
|
||||
Drone,
|
||||
collection_class=HandledDroneCargoList,
|
||||
cascade='all, delete, delete-orphan',
|
||||
single_parent=True,
|
||||
primaryjoin=and_(drones_table.c.fitID == fits_table.c.ID, drones_table.c.projected == False)), # noqa
|
||||
"_Fit__fighters": relation(
|
||||
Fighter,
|
||||
collection_class=HandledDroneCargoList,
|
||||
cascade='all, delete, delete-orphan',
|
||||
single_parent=True,
|
||||
primaryjoin=and_(fighters_table.c.fitID == fits_table.c.ID, fighters_table.c.projected == False)), # noqa
|
||||
"_Fit__cargo": relation(
|
||||
Cargo,
|
||||
collection_class=HandledDroneCargoList,
|
||||
cascade='all, delete, delete-orphan',
|
||||
single_parent=True,
|
||||
primaryjoin=and_(cargo_table.c.fitID == fits_table.c.ID)),
|
||||
"_Fit__projectedDrones": relation(
|
||||
Drone,
|
||||
collection_class=HandledProjectedDroneList,
|
||||
cascade='all, delete, delete-orphan',
|
||||
single_parent=True,
|
||||
primaryjoin=and_(drones_table.c.fitID == fits_table.c.ID, drones_table.c.projected == True)), # noqa
|
||||
"_Fit__projectedFighters": relation(
|
||||
Fighter,
|
||||
collection_class=HandledProjectedDroneList,
|
||||
cascade='all, delete, delete-orphan',
|
||||
single_parent=True,
|
||||
primaryjoin=and_(fighters_table.c.fitID == fits_table.c.ID, fighters_table.c.projected == True)), # noqa
|
||||
"_Fit__implants": relation(
|
||||
Implant,
|
||||
collection_class=HandledImplantBoosterList,
|
||||
cascade='all, delete, delete-orphan',
|
||||
backref='fit',
|
||||
single_parent=True,
|
||||
primaryjoin=fitImplants_table.c.fitID == fits_table.c.ID,
|
||||
secondaryjoin=fitImplants_table.c.implantID == Implant.ID,
|
||||
secondary=fitImplants_table),
|
||||
"_Fit__character": relation(
|
||||
Character,
|
||||
backref="fits"),
|
||||
"_Fit__damagePattern": relation(DamagePattern),
|
||||
"_Fit__targetResists": relation(TargetResists),
|
||||
"projectedOnto": relationship(
|
||||
ProjectedFit,
|
||||
primaryjoin=projectedFits_table.c.sourceID == fits_table.c.ID,
|
||||
backref='source_fit',
|
||||
collection_class=attribute_mapped_collection('victimID'),
|
||||
cascade='all, delete, delete-orphan'),
|
||||
"victimOf": relationship(
|
||||
ProjectedFit,
|
||||
primaryjoin=fits_table.c.ID == projectedFits_table.c.victimID,
|
||||
backref='victim_fit',
|
||||
collection_class=attribute_mapped_collection('sourceID'),
|
||||
cascade='all, delete, delete-orphan'),
|
||||
"boostedOnto": relationship(
|
||||
CommandFit,
|
||||
primaryjoin=commandFits_table.c.boosterID == fits_table.c.ID,
|
||||
backref='booster_fit',
|
||||
collection_class=attribute_mapped_collection('boostedID'),
|
||||
cascade='all, delete, delete-orphan'),
|
||||
"boostedOf": relationship(
|
||||
CommandFit,
|
||||
primaryjoin=fits_table.c.ID == commandFits_table.c.boostedID,
|
||||
backref='boosted_fit',
|
||||
collection_class=attribute_mapped_collection('boosterID'),
|
||||
cascade='all, delete, delete-orphan'),
|
||||
}
|
||||
)
|
||||
|
||||
mapper(ProjectedFit, projectedFits_table,
|
||||
properties={
|
||||
"_ProjectedFit__amount": projectedFits_table.c.amount,
|
||||
}
|
||||
)
|
||||
properties={
|
||||
"_ProjectedFit__amount": projectedFits_table.c.amount,
|
||||
}
|
||||
)
|
||||
|
||||
mapper(CommandFit, commandFits_table)
|
||||
mapper(CommandFit, commandFits_table)
|
||||
|
||||
@@ -21,7 +21,7 @@ from sqlalchemy import Table, Column, Integer, ForeignKey, Boolean
|
||||
from sqlalchemy.orm import mapper
|
||||
|
||||
from eos.db import saveddata_meta
|
||||
from eos.types import Implant
|
||||
from eos.saveddata.implant import Implant
|
||||
|
||||
implants_table = Table("implants", saveddata_meta,
|
||||
Column("ID", Integer, primary_key=True),
|
||||
|
||||
@@ -23,7 +23,8 @@ from sqlalchemy.orm import relation, mapper
|
||||
from eos.db import saveddata_meta
|
||||
from eos.db.saveddata.implant import implantsSetMap_table
|
||||
from eos.effectHandlerHelpers import HandledImplantBoosterList
|
||||
from eos.types import Implant, ImplantSet
|
||||
from eos.saveddata.implant import Implant
|
||||
from eos.saveddata.implantSet import ImplantSet
|
||||
|
||||
implant_set_table = Table("implantSets", saveddata_meta,
|
||||
Column("ID", Integer, primary_key=True),
|
||||
|
||||
@@ -18,14 +18,15 @@
|
||||
# ===============================================================================
|
||||
|
||||
import eos.db
|
||||
import eos.types
|
||||
from eos.saveddata.damagePattern import DamagePattern as es_DamagePattern
|
||||
from eos.saveddata.targetResists import TargetResists as es_TargetResists
|
||||
|
||||
|
||||
class ImportError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class DefaultDatabaseValues():
|
||||
class DefaultDatabaseValues(object):
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@@ -118,7 +119,7 @@ class DefaultDatabaseValues():
|
||||
name, em, therm, kin, exp = damageProfileRow
|
||||
damageProfile = eos.db.getDamagePattern(name)
|
||||
if damageProfile is None:
|
||||
damageProfile = eos.types.DamagePattern(em, therm, kin, exp)
|
||||
damageProfile = es_DamagePattern(em, therm, kin, exp)
|
||||
damageProfile.name = name
|
||||
eos.db.save(damageProfile)
|
||||
|
||||
@@ -180,7 +181,7 @@ class DefaultDatabaseValues():
|
||||
name, em, therm, kin, exp = targetResistProfileRow
|
||||
resistsProfile = eos.db.eos.db.getTargetResists(name)
|
||||
if resistsProfile is None:
|
||||
resistsProfile = eos.types.TargetResists(em, therm, kin, exp)
|
||||
resistsProfile = es_TargetResists(em, therm, kin, exp)
|
||||
resistsProfile.name = name
|
||||
eos.db.save(resistsProfile)
|
||||
|
||||
@@ -192,6 +193,6 @@ class DefaultDatabaseValues():
|
||||
name, em, therm, kin, exp = damageProfileRow
|
||||
damageProfile = eos.db.getDamagePattern(name)
|
||||
if damageProfile is None:
|
||||
damageProfile = eos.types.DamagePattern(em, therm, kin, exp)
|
||||
damageProfile = es_DamagePattern(em, therm, kin, exp)
|
||||
damageProfile.name = name
|
||||
eos.db.save(damageProfile)
|
||||
|
||||
@@ -21,7 +21,7 @@ from sqlalchemy import Column, Table, String
|
||||
from sqlalchemy.orm import mapper
|
||||
|
||||
from eos.db import saveddata_meta
|
||||
from eos.types import MiscData
|
||||
from eos.saveddata.miscData import MiscData
|
||||
|
||||
miscdata_table = Table("miscdata", saveddata_meta,
|
||||
Column("fieldName", String, primary_key=True),
|
||||
|
||||
@@ -21,7 +21,8 @@ from sqlalchemy import Table, Column, Integer, ForeignKey, CheckConstraint, Bool
|
||||
from sqlalchemy.orm import relation, mapper
|
||||
|
||||
from eos.db import saveddata_meta
|
||||
from eos.types import Module, Fit
|
||||
from eos.saveddata.module import Module
|
||||
from eos.saveddata.fit import Fit
|
||||
|
||||
modules_table = Table("modules", saveddata_meta,
|
||||
Column("ID", Integer, primary_key=True),
|
||||
|
||||
@@ -21,7 +21,7 @@ from sqlalchemy import Table, Column, Integer, Float
|
||||
from sqlalchemy.orm import mapper
|
||||
|
||||
from eos.db import saveddata_meta
|
||||
from eos.types import Override
|
||||
from eos.saveddata.override import Override
|
||||
|
||||
overrides_table = Table("overrides", saveddata_meta,
|
||||
Column("itemID", Integer, primary_key=True, index=True),
|
||||
|
||||
@@ -21,7 +21,7 @@ from sqlalchemy import Table, Column, Float, Integer
|
||||
from sqlalchemy.orm import mapper
|
||||
|
||||
from eos.db import saveddata_meta
|
||||
from eos.types import Price
|
||||
from eos.saveddata.price import Price
|
||||
|
||||
prices_table = Table("prices", saveddata_meta,
|
||||
Column("typeID", Integer, primary_key=True),
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#===============================================================================
|
||||
# ===============================================================================
|
||||
# Copyright (C) 2010 Diego Duclos
|
||||
#
|
||||
# This file is part of eos.
|
||||
@@ -15,26 +15,40 @@
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with eos. If not, see <http://www.gnu.org/licenses/>.
|
||||
#===============================================================================
|
||||
# ===============================================================================
|
||||
|
||||
from eos.db.util import processEager, processWhere
|
||||
from eos.db import saveddata_session, sd_lock
|
||||
|
||||
from eos.types import *
|
||||
from eos.db.saveddata.fit import projectedFits_table
|
||||
from sqlalchemy.sql import and_
|
||||
|
||||
from eos.db import saveddata_session, sd_lock
|
||||
from eos.db.saveddata.fit import projectedFits_table
|
||||
from eos.db.util import processEager, processWhere
|
||||
from eos.saveddata.price import Price
|
||||
from eos.saveddata.user import User
|
||||
from eos.saveddata.crestchar import CrestChar
|
||||
from eos.saveddata.damagePattern import DamagePattern
|
||||
from eos.saveddata.targetResists import TargetResists
|
||||
from eos.saveddata.character import Character
|
||||
from eos.saveddata.implantSet import ImplantSet
|
||||
from eos.saveddata.fit import Fit
|
||||
from eos.saveddata.miscData import MiscData
|
||||
from eos.saveddata.override import Override
|
||||
|
||||
import eos.config
|
||||
|
||||
configVal = getattr(eos.config, "saveddataCache", None)
|
||||
if configVal is True:
|
||||
import weakref
|
||||
|
||||
itemCache = {}
|
||||
queryCache = {}
|
||||
|
||||
def cachedQuery(type, amount, *keywords):
|
||||
itemCache[type] = localItemCache = weakref.WeakValueDictionary()
|
||||
queryCache[type] = typeQueryCache = {}
|
||||
|
||||
def deco(function):
|
||||
localQueryCache = typeQueryCache[function] = {}
|
||||
|
||||
def setCache(cacheKey, args, kwargs):
|
||||
items = function(*args, **kwargs)
|
||||
IDs = set()
|
||||
@@ -43,7 +57,7 @@ if configVal is True:
|
||||
for item in stuff:
|
||||
ID = getattr(item, "ID", None)
|
||||
if ID is None:
|
||||
#Some uncachable data, don't cache this query
|
||||
# Some uncachable data, don't cache this query
|
||||
del localQueryCache[cacheKey]
|
||||
break
|
||||
localItemCache[ID] = item
|
||||
@@ -54,6 +68,7 @@ if configVal is True:
|
||||
def checkAndReturn(*args, **kwargs):
|
||||
useCache = kwargs.pop("useCache", True)
|
||||
cacheKey = []
|
||||
items = None
|
||||
cacheKey.extend(args)
|
||||
for keyword in keywords:
|
||||
cacheKey.append(kwargs.get(keyword))
|
||||
@@ -69,7 +84,7 @@ if configVal is True:
|
||||
for ID in IDs:
|
||||
data = localItemCache.get(ID)
|
||||
if data is None:
|
||||
#Fuck, some of our stuff isn't cached it seems.
|
||||
# Fuck, some of our stuff isn't cached it seems.
|
||||
items = setCache(cacheKey, args, kwargs)
|
||||
break
|
||||
items.append(data)
|
||||
@@ -81,11 +96,13 @@ if configVal is True:
|
||||
break
|
||||
|
||||
return items
|
||||
|
||||
return checkAndReturn
|
||||
|
||||
return deco
|
||||
|
||||
def removeCachedEntry(type, ID):
|
||||
if not type in queryCache:
|
||||
if type not in queryCache:
|
||||
return
|
||||
functionCache = queryCache[type]
|
||||
for _, localCache in functionCache.iteritems():
|
||||
@@ -110,11 +127,13 @@ else:
|
||||
return function(*args, **kwargs)
|
||||
|
||||
return checkAndReturn
|
||||
|
||||
return deco
|
||||
|
||||
def removeCachedEntry(*args, **kwargs):
|
||||
return
|
||||
|
||||
|
||||
def sqlizeString(line):
|
||||
# Escape backslashes first, as they will be as escape symbol in queries
|
||||
# Then escape percent and underscore signs
|
||||
@@ -122,6 +141,7 @@ def sqlizeString(line):
|
||||
line = line.replace("\\", "\\\\").replace("%", "\\%").replace("_", "\\_").replace("*", "%")
|
||||
return line
|
||||
|
||||
|
||||
@cachedQuery(User, 1, "lookfor")
|
||||
def getUser(lookfor, eager=None):
|
||||
if isinstance(lookfor, int):
|
||||
@@ -140,6 +160,7 @@ def getUser(lookfor, eager=None):
|
||||
raise TypeError("Need integer or string as argument")
|
||||
return user
|
||||
|
||||
|
||||
@cachedQuery(Character, 1, "lookfor")
|
||||
def getCharacter(lookfor, eager=None):
|
||||
if isinstance(lookfor, int):
|
||||
@@ -153,17 +174,20 @@ def getCharacter(lookfor, eager=None):
|
||||
elif isinstance(lookfor, basestring):
|
||||
eager = processEager(eager)
|
||||
with sd_lock:
|
||||
character = saveddata_session.query(Character).options(*eager).filter(Character.savedName == lookfor).first()
|
||||
character = saveddata_session.query(Character).options(*eager).filter(
|
||||
Character.savedName == lookfor).first()
|
||||
else:
|
||||
raise TypeError("Need integer or string as argument")
|
||||
return character
|
||||
|
||||
|
||||
def getCharacterList(eager=None):
|
||||
eager = processEager(eager)
|
||||
with sd_lock:
|
||||
characters = saveddata_session.query(Character).options(*eager).all()
|
||||
return characters
|
||||
|
||||
|
||||
def getCharactersForUser(lookfor, eager=None):
|
||||
if isinstance(lookfor, int):
|
||||
eager = processEager(eager)
|
||||
@@ -173,6 +197,7 @@ def getCharactersForUser(lookfor, eager=None):
|
||||
raise TypeError("Need integer as argument")
|
||||
return characters
|
||||
|
||||
|
||||
@cachedQuery(Fit, 1, "lookfor")
|
||||
def getFit(lookfor, eager=None):
|
||||
if isinstance(lookfor, int):
|
||||
@@ -193,6 +218,7 @@ def getFit(lookfor, eager=None):
|
||||
|
||||
return fit
|
||||
|
||||
|
||||
def getFitsWithShip(shipID, ownerID=None, where=None, eager=None):
|
||||
"""
|
||||
Get all the fits using a certain ship.
|
||||
@@ -214,6 +240,7 @@ def getFitsWithShip(shipID, ownerID=None, where=None, eager=None):
|
||||
|
||||
return fits
|
||||
|
||||
|
||||
def getBoosterFits(ownerID=None, where=None, eager=None):
|
||||
"""
|
||||
Get all the fits that are flagged as a boosting ship
|
||||
@@ -233,31 +260,41 @@ def getBoosterFits(ownerID=None, where=None, eager=None):
|
||||
|
||||
return fits
|
||||
|
||||
|
||||
def countAllFits():
|
||||
with sd_lock:
|
||||
count = saveddata_session.query(Fit).count()
|
||||
return count
|
||||
|
||||
def countFitsWithShip(shipID, ownerID=None, where=None, eager=None):
|
||||
|
||||
def countFitsWithShip(lookfor, ownerID=None, where=None, eager=None):
|
||||
"""
|
||||
Get all the fits using a certain ship.
|
||||
If no user is passed, do this for all users.
|
||||
"""
|
||||
if isinstance(shipID, int):
|
||||
if ownerID is not None and not isinstance(ownerID, int):
|
||||
raise TypeError("OwnerID must be integer")
|
||||
filter = Fit.shipID == shipID
|
||||
if ownerID is not None:
|
||||
filter = and_(filter, Fit.ownerID == ownerID)
|
||||
if ownerID is not None and not isinstance(ownerID, int):
|
||||
raise TypeError("OwnerID must be integer")
|
||||
|
||||
filter = processWhere(filter, where)
|
||||
eager = processEager(eager)
|
||||
with sd_lock:
|
||||
count = saveddata_session.query(Fit).options(*eager).filter(filter).count()
|
||||
if isinstance(lookfor, int):
|
||||
filter = Fit.shipID == lookfor
|
||||
elif isinstance(lookfor, list):
|
||||
if len(lookfor) == 0:
|
||||
return 0
|
||||
filter = Fit.shipID.in_(lookfor)
|
||||
else:
|
||||
raise TypeError("ShipID must be integer")
|
||||
raise TypeError("You must supply either an integer or ShipID must be integer")
|
||||
|
||||
if ownerID is not None:
|
||||
filter = and_(filter, Fit.ownerID == ownerID)
|
||||
|
||||
filter = processWhere(filter, where)
|
||||
eager = processEager(eager)
|
||||
with sd_lock:
|
||||
count = saveddata_session.query(Fit).options(*eager).filter(filter).count()
|
||||
|
||||
return count
|
||||
|
||||
|
||||
def getFitList(eager=None):
|
||||
eager = processEager(eager)
|
||||
with sd_lock:
|
||||
@@ -265,6 +302,7 @@ def getFitList(eager=None):
|
||||
|
||||
return fits
|
||||
|
||||
|
||||
@cachedQuery(Price, 1, "typeID")
|
||||
def getPrice(typeID):
|
||||
if isinstance(typeID, int):
|
||||
@@ -274,12 +312,14 @@ def getPrice(typeID):
|
||||
raise TypeError("Need integer as argument")
|
||||
return price
|
||||
|
||||
|
||||
def clearPrices():
|
||||
with sd_lock:
|
||||
deleted_rows = saveddata_session.query(Price).delete()
|
||||
commit()
|
||||
return deleted_rows
|
||||
|
||||
|
||||
def getMiscData(field):
|
||||
if isinstance(field, basestring):
|
||||
with sd_lock:
|
||||
@@ -288,24 +328,28 @@ def getMiscData(field):
|
||||
raise TypeError("Need string as argument")
|
||||
return data
|
||||
|
||||
|
||||
def getDamagePatternList(eager=None):
|
||||
eager = processEager(eager)
|
||||
with sd_lock:
|
||||
patterns = saveddata_session.query(DamagePattern).options(*eager).all()
|
||||
return patterns
|
||||
|
||||
|
||||
def getTargetResistsList(eager=None):
|
||||
eager = processEager(eager)
|
||||
with sd_lock:
|
||||
patterns = saveddata_session.query(TargetResists).options(*eager).all()
|
||||
return patterns
|
||||
|
||||
|
||||
def getImplantSetList(eager=None):
|
||||
eager = processEager(eager)
|
||||
with sd_lock:
|
||||
sets = saveddata_session.query(ImplantSet).options(*eager).all()
|
||||
return sets
|
||||
|
||||
|
||||
@cachedQuery(DamagePattern, 1, "lookfor")
|
||||
def getDamagePattern(lookfor, eager=None):
|
||||
if isinstance(lookfor, int):
|
||||
@@ -315,15 +359,18 @@ def getDamagePattern(lookfor, eager=None):
|
||||
else:
|
||||
eager = processEager(eager)
|
||||
with sd_lock:
|
||||
pattern = saveddata_session.query(DamagePattern).options(*eager).filter(DamagePattern.ID == lookfor).first()
|
||||
pattern = saveddata_session.query(DamagePattern).options(*eager).filter(
|
||||
DamagePattern.ID == lookfor).first()
|
||||
elif isinstance(lookfor, basestring):
|
||||
eager = processEager(eager)
|
||||
with sd_lock:
|
||||
pattern = saveddata_session.query(DamagePattern).options(*eager).filter(DamagePattern.name == lookfor).first()
|
||||
pattern = saveddata_session.query(DamagePattern).options(*eager).filter(
|
||||
DamagePattern.name == lookfor).first()
|
||||
else:
|
||||
raise TypeError("Need integer or string as argument")
|
||||
return pattern
|
||||
|
||||
|
||||
@cachedQuery(TargetResists, 1, "lookfor")
|
||||
def getTargetResists(lookfor, eager=None):
|
||||
if isinstance(lookfor, int):
|
||||
@@ -333,15 +380,18 @@ def getTargetResists(lookfor, eager=None):
|
||||
else:
|
||||
eager = processEager(eager)
|
||||
with sd_lock:
|
||||
pattern = saveddata_session.query(TargetResists).options(*eager).filter(TargetResists.ID == lookfor).first()
|
||||
pattern = saveddata_session.query(TargetResists).options(*eager).filter(
|
||||
TargetResists.ID == lookfor).first()
|
||||
elif isinstance(lookfor, basestring):
|
||||
eager = processEager(eager)
|
||||
with sd_lock:
|
||||
pattern = saveddata_session.query(TargetResists).options(*eager).filter(TargetResists.name == lookfor).first()
|
||||
pattern = saveddata_session.query(TargetResists).options(*eager).filter(
|
||||
TargetResists.name == lookfor).first()
|
||||
else:
|
||||
raise TypeError("Need integer or string as argument")
|
||||
return pattern
|
||||
|
||||
|
||||
@cachedQuery(ImplantSet, 1, "lookfor")
|
||||
def getImplantSet(lookfor, eager=None):
|
||||
if isinstance(lookfor, int):
|
||||
@@ -351,7 +401,8 @@ def getImplantSet(lookfor, eager=None):
|
||||
else:
|
||||
eager = processEager(eager)
|
||||
with sd_lock:
|
||||
pattern = saveddata_session.query(ImplantSet).options(*eager).filter(TargetResists.ID == lookfor).first()
|
||||
pattern = saveddata_session.query(ImplantSet).options(*eager).filter(
|
||||
TargetResists.ID == lookfor).first()
|
||||
elif isinstance(lookfor, basestring):
|
||||
eager = processEager(eager)
|
||||
with sd_lock:
|
||||
@@ -360,13 +411,14 @@ def getImplantSet(lookfor, eager=None):
|
||||
raise TypeError("Improper argument")
|
||||
return pattern
|
||||
|
||||
|
||||
def searchFits(nameLike, where=None, eager=None):
|
||||
if not isinstance(nameLike, basestring):
|
||||
raise TypeError("Need string as argument")
|
||||
# Prepare our string for request
|
||||
nameLike = u"%{0}%".format(sqlizeString(nameLike))
|
||||
|
||||
#Add any extra components to the search to our where clause
|
||||
# Add any extra components to the search to our where clause
|
||||
filter = processWhere(Fit.name.like(nameLike, escape="\\"), where)
|
||||
eager = processEager(eager)
|
||||
with sd_lock:
|
||||
@@ -374,6 +426,7 @@ def searchFits(nameLike, where=None, eager=None):
|
||||
|
||||
return fits
|
||||
|
||||
|
||||
def getProjectedFits(fitID):
|
||||
if isinstance(fitID, int):
|
||||
with sd_lock:
|
||||
@@ -383,12 +436,14 @@ def getProjectedFits(fitID):
|
||||
else:
|
||||
raise TypeError("Need integer as argument")
|
||||
|
||||
|
||||
def getCrestCharacters(eager=None):
|
||||
eager = processEager(eager)
|
||||
with sd_lock:
|
||||
characters = saveddata_session.query(CrestChar).options(*eager).all()
|
||||
return characters
|
||||
|
||||
|
||||
@cachedQuery(CrestChar, 1, "lookfor")
|
||||
def getCrestCharacter(lookfor, eager=None):
|
||||
if isinstance(lookfor, int):
|
||||
@@ -407,21 +462,25 @@ def getCrestCharacter(lookfor, eager=None):
|
||||
raise TypeError("Need integer or string as argument")
|
||||
return character
|
||||
|
||||
|
||||
def getOverrides(itemID, eager=None):
|
||||
if isinstance(itemID, int):
|
||||
return saveddata_session.query(Override).filter(Override.itemID == itemID).all()
|
||||
else:
|
||||
raise TypeError("Need integer as argument")
|
||||
|
||||
|
||||
def clearOverrides():
|
||||
with sd_lock:
|
||||
deleted_rows = saveddata_session.query(Override).delete()
|
||||
commit()
|
||||
return deleted_rows
|
||||
|
||||
|
||||
def getAllOverrides(eager=None):
|
||||
return saveddata_session.query(Override).all()
|
||||
|
||||
|
||||
def removeInvalid(fits):
|
||||
invalids = [f for f in fits if f.isInvalid]
|
||||
|
||||
@@ -432,14 +491,17 @@ def removeInvalid(fits):
|
||||
|
||||
return fits
|
||||
|
||||
|
||||
def add(stuff):
|
||||
with sd_lock:
|
||||
saveddata_session.add(stuff)
|
||||
|
||||
|
||||
def save(stuff):
|
||||
add(stuff)
|
||||
commit()
|
||||
|
||||
|
||||
def remove(stuff):
|
||||
removeCachedEntry(type(stuff), stuff.ID)
|
||||
with sd_lock:
|
||||
|
||||
@@ -21,7 +21,7 @@ from sqlalchemy import Table, Column, Integer, ForeignKey
|
||||
from sqlalchemy.orm import mapper
|
||||
|
||||
from eos.db import saveddata_meta
|
||||
from eos.types import Skill
|
||||
from eos.saveddata.character import Skill
|
||||
|
||||
skills_table = Table("characterSkills", saveddata_meta,
|
||||
Column("characterID", ForeignKey("characters.ID"), primary_key=True, index=True),
|
||||
|
||||
@@ -21,7 +21,7 @@ from sqlalchemy import Table, Column, Integer, Float, ForeignKey, String
|
||||
from sqlalchemy.orm import mapper
|
||||
|
||||
from eos.db import saveddata_meta
|
||||
from eos.types import TargetResists
|
||||
from eos.saveddata.targetResists import TargetResists
|
||||
|
||||
targetResists_table = Table("targetResists", saveddata_meta,
|
||||
Column("ID", Integer, primary_key=True),
|
||||
|
||||
@@ -21,7 +21,7 @@ from sqlalchemy import Table, Column, Integer, String, Boolean
|
||||
from sqlalchemy.orm import mapper
|
||||
|
||||
from eos.db import saveddata_meta
|
||||
from eos.types import User
|
||||
from eos.saveddata.user import User
|
||||
|
||||
users_table = Table("users", saveddata_meta,
|
||||
Column("ID", Integer, primary_key=True),
|
||||
|
||||
@@ -17,13 +17,9 @@
|
||||
# along with eos. If not, see <http://www.gnu.org/licenses/>.
|
||||
# ===============================================================================
|
||||
|
||||
# from sqlalchemy.orm.attributes import flag_modified
|
||||
import logging
|
||||
from logbook import Logger
|
||||
|
||||
import eos.db
|
||||
import eos.types
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
class HandledList(list):
|
||||
@@ -140,10 +136,6 @@ class HandledModuleList(HandledList):
|
||||
self.remove(mod)
|
||||
return
|
||||
|
||||
# fix for #529, where a module may be in incorrect state after CCP changes mechanics of module
|
||||
if not mod.isValidState(mod.state):
|
||||
mod.state = eos.types.State.ONLINE
|
||||
|
||||
def insert(self, index, mod):
|
||||
mod.position = index
|
||||
i = index
|
||||
@@ -163,7 +155,7 @@ class HandledModuleList(HandledList):
|
||||
def toDummy(self, index):
|
||||
mod = self[index]
|
||||
if not mod.isEmpty:
|
||||
dummy = eos.types.Module.buildEmpty(mod.slot)
|
||||
dummy = mod.buildEmpty(mod.slot)
|
||||
dummy.position = index
|
||||
self[index] = dummy
|
||||
|
||||
@@ -172,10 +164,11 @@ class HandledModuleList(HandledList):
|
||||
self[index] = mod
|
||||
|
||||
def freeSlot(self, slot):
|
||||
for i in range(len(self) - 1, -1, -1):
|
||||
for i in range(len(self)):
|
||||
mod = self[i]
|
||||
if mod.getModifiedItemAttr("subSystemSlot") == slot:
|
||||
del self[i]
|
||||
self.toDummy(i)
|
||||
break
|
||||
|
||||
|
||||
class HandledDroneCargoList(HandledList):
|
||||
@@ -205,7 +198,7 @@ class HandledImplantBoosterList(HandledList):
|
||||
# if needed, remove booster that was occupying slot
|
||||
oldObj = next((m for m in self if m.slot == thing.slot), None)
|
||||
if oldObj:
|
||||
logging.info("Slot %d occupied with %s, replacing with %s", thing.slot, oldObj.item.name, thing.item.name)
|
||||
pyfalog.info("Slot {0} occupied with {1}, replacing with {2}", thing.slot, oldObj.item.name, thing.item.name)
|
||||
oldObj.itemID = 0 # hack to remove from DB. See GH issue #324
|
||||
self.remove(oldObj)
|
||||
|
||||
@@ -229,7 +222,7 @@ class HandledProjectedModList(HandledList):
|
||||
oldEffect = next((m for m in self if m.item.group.name == "Effect Beacon"), None)
|
||||
|
||||
if oldEffect:
|
||||
logging.info("System effect occupied with %s, replacing with %s", oldEffect.item.name, proj.item.name)
|
||||
pyfalog.info("System effect occupied with {0}, replacing with {1}", oldEffect.item.name, proj.item.name)
|
||||
self.remove(oldEffect)
|
||||
|
||||
HandledList.append(self, proj)
|
||||
|
||||
@@ -2,19 +2,19 @@
|
||||
#
|
||||
# Used by:
|
||||
# Module: Reactive Armor Hardener
|
||||
import logging
|
||||
from logbook import Logger
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
runTime = "late"
|
||||
type = "active"
|
||||
|
||||
|
||||
def handler(fit, module, context):
|
||||
damagePattern = fit.damagePattern
|
||||
|
||||
# Skip if there is no damage pattern. Example: projected ships or fleet boosters
|
||||
if damagePattern:
|
||||
#logger.debug("Damage Pattern: %f/%f/%f/%f", damagePattern.emAmount, damagePattern.thermalAmount, damagePattern.kineticAmount, damagePattern.explosiveAmount)
|
||||
#logger.debug("Original Armor Resists: %f/%f/%f/%f", fit.ship.getModifiedItemAttr('armorEmDamageResonance'), fit.ship.getModifiedItemAttr('armorThermalDamageResonance'), fit.ship.getModifiedItemAttr('armorKineticDamageResonance'), fit.ship.getModifiedItemAttr('armorExplosiveDamageResonance'))
|
||||
|
||||
# Populate a tuple with the damage profile modified by current armor resists.
|
||||
baseDamageTaken = (
|
||||
@@ -23,35 +23,35 @@ def handler(fit, module, context):
|
||||
damagePattern.kineticAmount * fit.ship.getModifiedItemAttr('armorKineticDamageResonance'),
|
||||
damagePattern.explosiveAmount * fit.ship.getModifiedItemAttr('armorExplosiveDamageResonance'),
|
||||
)
|
||||
#logger.debug("Damage Adjusted for Armor Resists: %f/%f/%f/%f", baseDamageTaken[0], baseDamageTaken[1], baseDamageTaken[2], baseDamageTaken[3])
|
||||
# pyfalog.debug("Damage Adjusted for Armor Resists: %f/%f/%f/%f", baseDamageTaken[0], baseDamageTaken[1], baseDamageTaken[2], baseDamageTaken[3])
|
||||
|
||||
resistanceShiftAmount = module.getModifiedItemAttr('resistanceShiftAmount') / 100 # The attribute is in percent and we want a fraction
|
||||
resistanceShiftAmount = module.getModifiedItemAttr(
|
||||
'resistanceShiftAmount') / 100 # The attribute is in percent and we want a fraction
|
||||
RAHResistance = [
|
||||
module.getModifiedItemAttr('armorEmDamageResonance'),
|
||||
module.getModifiedItemAttr('armorThermalDamageResonance'),
|
||||
module.getModifiedItemAttr('armorKineticDamageResonance'),
|
||||
module.getModifiedItemAttr('armorEmDamageResonance'),
|
||||
module.getModifiedItemAttr('armorThermalDamageResonance'),
|
||||
module.getModifiedItemAttr('armorKineticDamageResonance'),
|
||||
module.getModifiedItemAttr('armorExplosiveDamageResonance'),
|
||||
]
|
||||
|
||||
|
||||
# Simulate RAH cycles until the RAH either stops changing or enters a loop.
|
||||
# The number of iterations is limited to prevent an infinite loop if something goes wrong.
|
||||
cycleList = []
|
||||
loopStart = -20
|
||||
for num in range(50):
|
||||
#logger.debug("Starting cycle %d.", num)
|
||||
# pyfalog.debug("Starting cycle %d.", num)
|
||||
# The strange order is to emulate the ingame sorting when different types have taken the same amount of damage.
|
||||
# This doesn't take into account stacking penalties. In a few cases fitting a Damage Control causes an inaccurate result.
|
||||
damagePattern_tuples = [
|
||||
(0, baseDamageTaken[0] * RAHResistance[0], RAHResistance[0]),
|
||||
(3, baseDamageTaken[3] * RAHResistance[3], RAHResistance[3]),
|
||||
(3, baseDamageTaken[3] * RAHResistance[3], RAHResistance[3]),
|
||||
(2, baseDamageTaken[2] * RAHResistance[2], RAHResistance[2]),
|
||||
(1, baseDamageTaken[1] * RAHResistance[1], RAHResistance[1]),
|
||||
]
|
||||
#logger.debug("Damage taken this cycle: %f/%f/%f/%f", damagePattern_tuples[0][1], damagePattern_tuples[3][1], damagePattern_tuples[2][1], damagePattern_tuples[1][1])
|
||||
|
||||
|
||||
# Sort the tuple to drop the highest damage value to the bottom
|
||||
sortedDamagePattern_tuples = sorted(damagePattern_tuples, key=lambda damagePattern: damagePattern[1])
|
||||
|
||||
|
||||
if sortedDamagePattern_tuples[2][1] == 0:
|
||||
# One damage type: the top damage type takes from the other three
|
||||
# Since the resistances not taking damage will end up going to the type taking damage we just do the whole thing at once.
|
||||
@@ -72,41 +72,47 @@ def handler(fit, module, context):
|
||||
change1 = min(resistanceShiftAmount, 1 - sortedDamagePattern_tuples[1][2])
|
||||
change2 = -(change0 + change1) / 2
|
||||
change3 = -(change0 + change1) / 2
|
||||
|
||||
|
||||
RAHResistance[sortedDamagePattern_tuples[0][0]] = sortedDamagePattern_tuples[0][2] + change0
|
||||
RAHResistance[sortedDamagePattern_tuples[1][0]] = sortedDamagePattern_tuples[1][2] + change1
|
||||
RAHResistance[sortedDamagePattern_tuples[2][0]] = sortedDamagePattern_tuples[2][2] + change2
|
||||
RAHResistance[sortedDamagePattern_tuples[3][0]] = sortedDamagePattern_tuples[3][2] + change3
|
||||
#logger.debug("Resistances shifted to %f/%f/%f/%f", RAHResistance[0], RAHResistance[1], RAHResistance[2], RAHResistance[3])
|
||||
|
||||
# pyfalog.debug("Resistances shifted to %f/%f/%f/%f", RAHResistance[0], RAHResistance[1], RAHResistance[2], RAHResistance[3])
|
||||
|
||||
# See if the current RAH profile has been encountered before, indicating a loop.
|
||||
for i, val in enumerate(cycleList):
|
||||
tolerance = 1e-06
|
||||
if abs(RAHResistance[0] - val[0]) <= tolerance and abs(RAHResistance[1] - val[1]) <= tolerance and abs(RAHResistance[2] - val[2]) <= tolerance and abs(RAHResistance[3] - val[3]) <= tolerance:
|
||||
tolerance = 1e-06
|
||||
if abs(RAHResistance[0] - val[0]) <= tolerance and \
|
||||
abs(RAHResistance[1] - val[1]) <= tolerance and \
|
||||
abs(RAHResistance[2] - val[2]) <= tolerance and \
|
||||
abs(RAHResistance[3] - val[3]) <= tolerance:
|
||||
loopStart = i
|
||||
#logger.debug("Loop found: %d-%d", loopStart, num)
|
||||
# pyfalog.debug("Loop found: %d-%d", loopStart, num)
|
||||
break
|
||||
if loopStart >= 0: break
|
||||
|
||||
if loopStart >= 0:
|
||||
break
|
||||
|
||||
cycleList.append(list(RAHResistance))
|
||||
|
||||
|
||||
if loopStart < 0:
|
||||
logger.error("Reactive Armor Hardener failed to find equilibrium. Damage profile after armor: %f/%f/%f/%f", baseDamageTaken[0], baseDamageTaken[1], baseDamageTaken[2], baseDamageTaken[3])
|
||||
|
||||
# Average the profiles in the RAH loop, or the last 20 if it didn't find a loop.
|
||||
pyfalog.error("Reactive Armor Hardener failed to find equilibrium. Damage profile after armor: {0}/{1}/{2}/{3}",
|
||||
baseDamageTaken[0], baseDamageTaken[1], baseDamageTaken[2], baseDamageTaken[3])
|
||||
|
||||
# Average the profiles in the RAH loop, or the last 20 if it didn't find a loop.
|
||||
loopCycles = cycleList[loopStart:]
|
||||
numCycles = len(loopCycles)
|
||||
average = [0, 0, 0, 0]
|
||||
for cycle in loopCycles:
|
||||
for i in range(4):
|
||||
average[i] += cycle[i]
|
||||
|
||||
|
||||
for i in range(4):
|
||||
average[i] = round(average[i] / numCycles, 3)
|
||||
|
||||
|
||||
# Set the new resistances
|
||||
#logger.debug("Setting new resist profile: %f/%f/%f/%f", average[0], average[1], average[2],average[3])
|
||||
for i, attr in enumerate(('armorEmDamageResonance', 'armorThermalDamageResonance', 'armorKineticDamageResonance', 'armorExplosiveDamageResonance')):
|
||||
# pyfalog.debug("Setting new resist profile: %f/%f/%f/%f", average[0], average[1], average[2],average[3])
|
||||
for i, attr in enumerate((
|
||||
'armorEmDamageResonance', 'armorThermalDamageResonance', 'armorKineticDamageResonance',
|
||||
'armorExplosiveDamageResonance')):
|
||||
module.increaseItemAttr(attr, average[i] - module.getModifiedItemAttr(attr))
|
||||
fit.ship.multiplyItemAttr(attr, average[i], stackingPenalties=True, penaltyGroup="preMul")
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# ammoInfluenceCapNeed
|
||||
#
|
||||
# Used by:
|
||||
# Items from category: Charge (465 of 899)
|
||||
# Items from category: Charge (465 of 912)
|
||||
# Charges from group: Frequency Crystal (185 of 185)
|
||||
# Charges from group: Hybrid Charge (209 of 209)
|
||||
type = "passive"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# ammoInfluenceRange
|
||||
#
|
||||
# Used by:
|
||||
# Items from category: Charge (571 of 899)
|
||||
# Items from category: Charge (571 of 912)
|
||||
type = "passive"
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# ammoSpeedMultiplier
|
||||
#
|
||||
# Used by:
|
||||
# Charges from group: Festival Charges (9 of 9)
|
||||
# Charges from group: Festival Charges (22 of 22)
|
||||
# Charges from group: Interdiction Probe (2 of 2)
|
||||
# Charges from group: Survey Probe (3 of 3)
|
||||
type = "passive"
|
||||
|
||||
@@ -8,7 +8,7 @@ type = "passive"
|
||||
|
||||
def handler(fit, implant, context):
|
||||
fit.appliedImplants.filteredItemMultiply(
|
||||
lambda
|
||||
implant: "signatureRadiusBonus" in implant.itemModifiedAttributes and "implantSetAngel" in implant.itemModifiedAttributes,
|
||||
lambda implant: "signatureRadiusBonus" in implant.itemModifiedAttributes and
|
||||
"implantSetAngel" in implant.itemModifiedAttributes,
|
||||
"signatureRadiusBonus",
|
||||
implant.getModifiedItemAttr("implantSetAngel"))
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
# Used by:
|
||||
# Skill: Armored Command
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, src, context):
|
||||
lvl = src.level
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "buffDuration", src.getModifiedItemAttr("durationBonus") * lvl)
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "buffDuration",
|
||||
src.getModifiedItemAttr("durationBonus") * lvl)
|
||||
|
||||
@@ -5,9 +5,16 @@
|
||||
# Implant: Federation Navy Command Mindlink
|
||||
# Implant: Imperial Navy Command Mindlink
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, src, context):
|
||||
fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff2Multiplier", src.getModifiedItemAttr("mindlinkBonus"))
|
||||
fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff1Multiplier", src.getModifiedItemAttr("mindlinkBonus"))
|
||||
fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff4Multiplier", src.getModifiedItemAttr("mindlinkBonus"))
|
||||
fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff3Multiplier", src.getModifiedItemAttr("mindlinkBonus"))
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "buffDuration", src.getModifiedItemAttr("mindlinkBonus"))
|
||||
fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff2Multiplier",
|
||||
src.getModifiedItemAttr("mindlinkBonus"))
|
||||
fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff1Multiplier",
|
||||
src.getModifiedItemAttr("mindlinkBonus"))
|
||||
fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff4Multiplier",
|
||||
src.getModifiedItemAttr("mindlinkBonus"))
|
||||
fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff3Multiplier",
|
||||
src.getModifiedItemAttr("mindlinkBonus"))
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "buffDuration",
|
||||
src.getModifiedItemAttr("mindlinkBonus"))
|
||||
|
||||
@@ -3,9 +3,15 @@
|
||||
# Used by:
|
||||
# Skill: Armored Command Specialist
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, src, context):
|
||||
lvl = src.level
|
||||
fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff1Multiplier", src.getModifiedItemAttr("commandStrengthBonus") * lvl)
|
||||
fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff2Multiplier", src.getModifiedItemAttr("commandStrengthBonus") * lvl)
|
||||
fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff4Multiplier", src.getModifiedItemAttr("commandStrengthBonus") * lvl)
|
||||
fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff3Multiplier", src.getModifiedItemAttr("commandStrengthBonus") * lvl)
|
||||
fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff1Multiplier",
|
||||
src.getModifiedItemAttr("commandStrengthBonus") * lvl)
|
||||
fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff2Multiplier",
|
||||
src.getModifiedItemAttr("commandStrengthBonus") * lvl)
|
||||
fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff4Multiplier",
|
||||
src.getModifiedItemAttr("commandStrengthBonus") * lvl)
|
||||
fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff3Multiplier",
|
||||
src.getModifiedItemAttr("commandStrengthBonus") * lvl)
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
# Used by:
|
||||
# Modules from group: Armor Coating (202 of 202)
|
||||
# Modules from group: Armor Plating Energized (187 of 187)
|
||||
# Modules named like: QA Multiship Module Players (4 of 4)
|
||||
type = "passive"
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# armorRepairAmountBonusSubcap
|
||||
#
|
||||
# Used by:
|
||||
# Implants named like: Grade Asklepian (15 of 16)
|
||||
# Implants named like: grade Asklepian (15 of 18)
|
||||
type = "passive"
|
||||
|
||||
|
||||
|
||||
@@ -7,5 +7,7 @@ type = "passive"
|
||||
|
||||
def handler(fit, ship, context):
|
||||
for sensorType in ("Gravimetric", "Ladar", "Magnetometric", "Radar"):
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Electronic Warfare"), "scan{0}StrengthBonus".format(sensorType),
|
||||
ship.getModifiedItemAttr("shipBonusCB"), stackingPenalties=True, skill="Caldari Battleship")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Electronic Warfare"),
|
||||
"scan{0}StrengthBonus".format(sensorType),
|
||||
ship.getModifiedItemAttr("shipBonusCB"), stackingPenalties=True,
|
||||
skill="Caldari Battleship")
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
# Items from market group: Ammunition & Charges > Command Burst Charges (15 of 15)
|
||||
type = "active"
|
||||
|
||||
|
||||
def handler(fit, module, context):
|
||||
for x in xrange(1, 4):
|
||||
value = module.getModifiedChargeAttr("warfareBuff{}Multiplier".format(x))
|
||||
module.multiplyItemAttr("warfareBuff{}Value".format(x), value)
|
||||
module.multiplyItemAttr("warfareBuff{}Value".format(x), value)
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
# Skill: Leadership
|
||||
# Skill: Wing Command
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, src, context):
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Leadership"),
|
||||
"maxRange",
|
||||
|
||||
@@ -11,5 +11,8 @@
|
||||
# Ship: Orca
|
||||
# Ship: Rorqual
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, src, context):
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Leadership"), "maxRange", src.getModifiedItemAttr("roleBonusCommandBurstAoERange"))
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Leadership"), "maxRange",
|
||||
src.getModifiedItemAttr("roleBonusCommandBurstAoERange"))
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
# Used by:
|
||||
# Skill: Command Burst Specialist
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, src, context):
|
||||
lvl = src.level
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Leadership"),
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
# Used by:
|
||||
# Modules named like: Command Processor I (4 of 4)
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, src, context):
|
||||
fit.modules.filteredItemIncrease(lambda mod: mod.item.requiresSkill("Leadership"), "maxGroupActive", src.getModifiedItemAttr("maxGangModules"))
|
||||
fit.modules.filteredItemIncrease(lambda mod: mod.item.requiresSkill("Leadership"), "maxGroupOnline", src.getModifiedItemAttr("maxGangModules"))
|
||||
fit.modules.filteredItemIncrease(lambda mod: mod.item.requiresSkill("Leadership"), "maxGroupActive",
|
||||
src.getModifiedItemAttr("maxGangModules"))
|
||||
fit.modules.filteredItemIncrease(lambda mod: mod.item.requiresSkill("Leadership"), "maxGroupOnline",
|
||||
src.getModifiedItemAttr("maxGangModules"))
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
# Ship: Rorqual
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, src, context):
|
||||
fit.modules.filteredItemIncrease(lambda mod: mod.item.requiresSkill("Leadership"), "maxGroupActive", src.getModifiedItemAttr("maxGangModules"))
|
||||
fit.modules.filteredItemIncrease(lambda mod: mod.item.requiresSkill("Leadership"), "maxGroupOnline", src.getModifiedItemAttr("maxGangModules"))
|
||||
fit.modules.filteredItemIncrease(lambda mod: mod.item.requiresSkill("Leadership"), "maxGroupActive",
|
||||
src.getModifiedItemAttr("maxGangModules"))
|
||||
fit.modules.filteredItemIncrease(lambda mod: mod.item.requiresSkill("Leadership"), "maxGroupOnline",
|
||||
src.getModifiedItemAttr("maxGangModules"))
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#
|
||||
# Used by:
|
||||
# Modules from group: Data Miners (15 of 16)
|
||||
# Module: QA Cross Protocol Analyzer
|
||||
type = "active"
|
||||
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#
|
||||
# Used by:
|
||||
# Modules from group: Automated Targeting System (6 of 6)
|
||||
# Module: QA Damage Module
|
||||
type = "passive"
|
||||
|
||||
|
||||
|
||||
@@ -4,9 +4,16 @@
|
||||
# Ship: Magus
|
||||
# Ship: Pontifex
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, src, context):
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff2Value", src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff3Value", src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "buffDuration", src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff4Value", src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff1Value", src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff2Value",
|
||||
src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff3Value",
|
||||
src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "buffDuration",
|
||||
src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff4Value",
|
||||
src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff1Value",
|
||||
src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers")
|
||||
|
||||
@@ -4,9 +4,16 @@
|
||||
# Ship: Pontifex
|
||||
# Ship: Stork
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, src, context):
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff1Value", src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff3Value", src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff2Value", src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "buffDuration", src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff4Value", src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff1Value",
|
||||
src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff3Value",
|
||||
src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff2Value",
|
||||
src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "buffDuration",
|
||||
src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff4Value",
|
||||
src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers")
|
||||
|
||||
@@ -3,4 +3,7 @@ type = "passive"
|
||||
|
||||
|
||||
def handler(fit, src, context):
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command Specialist"), "commandBonusHidden", src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command Specialist"),
|
||||
"commandBonusHidden",
|
||||
src.getModifiedItemAttr("eliteBonusCommandDestroyer1"),
|
||||
skill="Command Destroyers")
|
||||
|
||||
@@ -4,9 +4,16 @@
|
||||
# Ship: Bifrost
|
||||
# Ship: Stork
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, src, context):
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff3Value", src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "buffDuration", src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff1Value", src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff4Value", src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff2Value", src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff3Value",
|
||||
src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "buffDuration",
|
||||
src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff1Value",
|
||||
src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff4Value",
|
||||
src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff2Value",
|
||||
src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers")
|
||||
|
||||
@@ -4,9 +4,16 @@
|
||||
# Ship: Bifrost
|
||||
# Ship: Magus
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, src, context):
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff3Value", src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "buffDuration", src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff1Value", src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff4Value", src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff2Value", src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff3Value",
|
||||
src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "buffDuration",
|
||||
src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff1Value",
|
||||
src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff4Value",
|
||||
src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff2Value",
|
||||
src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers")
|
||||
|
||||
@@ -3,9 +3,16 @@
|
||||
# Used by:
|
||||
# Ships from group: Command Ship (4 of 8)
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, src, context):
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff3Value", src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff1Value", src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff2Value", src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "buffDuration", src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff4Value", src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff3Value",
|
||||
src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff1Value",
|
||||
src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff2Value",
|
||||
src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "buffDuration",
|
||||
src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff4Value",
|
||||
src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships")
|
||||
|
||||
@@ -3,9 +3,16 @@
|
||||
# Used by:
|
||||
# Ships from group: Command Ship (4 of 8)
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, src, context):
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "buffDuration", src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff3Value", src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff2Value", src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff1Value", src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff4Value", src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "buffDuration",
|
||||
src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff3Value",
|
||||
src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff2Value",
|
||||
src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff1Value",
|
||||
src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff4Value",
|
||||
src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships")
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# Not used by any item
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, module, context):
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command Specialist"),
|
||||
"commandBonusHidden", module.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships")
|
||||
|
||||
@@ -3,9 +3,16 @@
|
||||
# Used by:
|
||||
# Ships from group: Command Ship (4 of 8)
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, src, context):
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff1Value", src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff4Value", src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff2Value", src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "buffDuration", src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff3Value", src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff1Value",
|
||||
src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff4Value",
|
||||
src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff2Value",
|
||||
src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "buffDuration",
|
||||
src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff3Value",
|
||||
src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships")
|
||||
|
||||
@@ -3,9 +3,16 @@
|
||||
# Used by:
|
||||
# Ships from group: Command Ship (4 of 8)
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, src, context):
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff2Value", src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff1Value", src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff3Value", src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff4Value", src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "buffDuration", src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff2Value",
|
||||
src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff1Value",
|
||||
src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff3Value",
|
||||
src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff4Value",
|
||||
src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "buffDuration",
|
||||
src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships")
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
# Used by:
|
||||
# Ship: Caedes
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, src, context):
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.group.name in ("Energy Nosferatu", "Energy Neutralizer"),
|
||||
"falloffEffectiveness", src.getModifiedItemAttr("eliteBonusCoverOps1"), stackingPenalties=True, skill="Covert Ops")
|
||||
|
||||
"falloffEffectiveness", src.getModifiedItemAttr("eliteBonusCoverOps1"),
|
||||
stackingPenalties=True, skill="Covert Ops")
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user