Merge pull request #1 from pyfa-org/master

Update Commit
This commit is contained in:
IndictionEve
2019-02-24 08:24:57 +01:00
committed by GitHub
4115 changed files with 17660 additions and 6979 deletions

View File

@@ -1,5 +1,4 @@
environment: environment:
global: global:
# SDK v7.0 MSVC Express 2008's SetEnv.cmd script will fail if the # SDK v7.0 MSVC Express 2008's SetEnv.cmd script will fail if the
# /E:ON and /V:ON options are not enabled in the batch script intepreter # /E:ON and /V:ON options are not enabled in the batch script intepreter
@@ -8,76 +7,11 @@ environment:
matrix: matrix:
# Python 2.7.10 is the latest version and is not pre-installed. - PYTHON: "C:\\Python36"
PYTHON_VERSION: "3.6.x"
- PYTHON: "C:\\Python27.10"
PYTHON_VERSION: "2.7.10"
PYTHON_ARCH: "32" PYTHON_ARCH: "32"
init:
#- PYTHON: "C:\\Python27.10-x64" - ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
# PYTHON_VERSION: "2.7.10"
# PYTHON_ARCH: "64"
# Pre-installed Python versions, which Appveyor may upgrade to
# a later point release.
# See: http://www.appveyor.com/docs/installed-software#python
#- PYTHON: "C:\\Python27"
# PYTHON_VERSION: "2.7.x" # currently 2.7.9
# PYTHON_ARCH: "32"
#- PYTHON: "C:\\Python27-x64"
# PYTHON_VERSION: "2.7.x" # currently 2.7.9
# PYTHON_ARCH: "64"
#- PYTHON: "C:\\Python33"
# PYTHON_VERSION: "3.3.x" # currently 3.3.5
# PYTHON_ARCH: "32"
#- PYTHON: "C:\\Python33-x64"
# PYTHON_VERSION: "3.3.x" # currently 3.3.5
# PYTHON_ARCH: "64"
#- PYTHON: "C:\\Python34"
# PYTHON_VERSION: "3.4.x" # currently 3.4.3
# PYTHON_ARCH: "32"
#- PYTHON: "C:\\Python34-x64"
# PYTHON_VERSION: "3.4.x" # currently 3.4.3
# PYTHON_ARCH: "64"
# Python versions not pre-installed
# Python 2.6.6 is the latest Python 2.6 with a Windows installer
# See: https://github.com/ogrisel/python-appveyor-demo/issues/10
#- PYTHON: "C:\\Python266"
# PYTHON_VERSION: "2.6.6"
# PYTHON_ARCH: "32"
#- PYTHON: "C:\\Python266-x64"
# PYTHON_VERSION: "2.6.6"
# PYTHON_ARCH: "64"
#- PYTHON: "C:\\Python35"
# PYTHON_VERSION: "3.5.0"
# PYTHON_ARCH: "32"
#- PYTHON: "C:\\Python35-x64"
# PYTHON_VERSION: "3.5.0"
# PYTHON_ARCH: "64"
# Major and minor releases (i.e x.0.0 and x.y.0) prior to 3.3.0 use
# a different naming scheme.
#- PYTHON: "C:\\Python270"
# PYTHON_VERSION: "2.7.0"
# PYTHON_ARCH: "32"
#- PYTHON: "C:\\Python270-x64"
# PYTHON_VERSION: "2.7.0"
# PYTHON_ARCH: "64"
install: install:
# If there is a newer build queued for the same PR, cancel this one. # If there is a newer build queued for the same PR, cancel this one.
# The AppVeyor 'rollout builds' option is supposed to serve the same # The AppVeyor 'rollout builds' option is supposed to serve the same
@@ -89,34 +23,23 @@ install:
Where-Object pullRequestId -eq $env:APPVEYOR_PULL_REQUEST_NUMBER)[0].buildNumber) { ` Where-Object pullRequestId -eq $env:APPVEYOR_PULL_REQUEST_NUMBER)[0].buildNumber) { `
throw "There are newer queued builds for this pull request, failing early." } throw "There are newer queued builds for this pull request, failing early." }
# Install wxPython
- 'ECHO Downloading wxPython.'
- "appveyor DownloadFile https://goo.gl/yvO8PB -FileName C:\\wxpython.exe"
#- "appveyor DownloadFile https://goo.gl/Uj0jV3 -FileName C:\\wxpython64.exe"
- 'ECHO Install wxPython'
- "C:\\wxpython.exe /SP- /VERYSILENT /NORESTART"
#- "C:\\wxpython64.exe /SP- /VERYSILENT /NORESTART"
- ECHO "Filesystem root:" - ECHO "Filesystem root:"
- ps: "ls \"C:/\"" - ps: "ls \"C:/\""
- ECHO "Filesystem projects root:"
- ps: "ls \"C:\\projects\\\""
- ECHO "Filesystem pyfa root:" - ECHO "Filesystem pyfa root:"
- ps: "ls \"C:\\projects\\pyfa\\\"" - ps: "ls \"C:\\projects\\$env:APPVEYOR_PROJECT_SLUG\""
- ECHO "Installed SDKs:" - ECHO "Installed SDKs:"
- ps: "ls \"C:/Program Files/Microsoft SDKs/Windows\"" - ps: "ls \"C:/Program Files/Microsoft SDKs/Windows\""
# Install Python (from the official .msi of http://python.org) and pip when
# not already installed.
# - ps: if (-not(Test-Path($env:PYTHON))) { & appveyor\install.ps1 }
# Prepend newly installed Python to the PATH of this build (this cannot be # Prepend newly installed Python to the PATH of this build (this cannot be
# done from inside the powershell script as it would require to restart # done from inside the powershell script as it would require to restart
# the parent CMD process). # the parent CMD process).
- "SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%" - "SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%"
# Check that we have the expected version and architecture for Python
- "python --version" - "python --version"
- "python -c \"import struct; print(struct.calcsize('P') * 8)\"" - "python -c \"import struct; print(struct.calcsize('P') * 8)\""
@@ -128,19 +51,36 @@ install:
# compiled extensions and are not provided as pre-built wheel packages, # compiled extensions and are not provided as pre-built wheel packages,
# pip will build them from source using the MSVC compiler matching the # pip will build them from source using the MSVC compiler matching the
# target Python version and architecture # target Python version and architecture
# C:\\projects\\eve-gnosis\\
- ECHO "Install pip requirements:" - ECHO "Install pip requirements:"
- "pip install -r requirements.txt" - "pip install -r requirements.txt"
- "pip install -r requirements_test.txt" - "pip install PyInstaller"
- "pip install -r requirements_build_windows.txt"
before_build:
# directory that will contain the built files
- ps: $env:PYFA_DIST_DIR = "c:\projects\$env:APPVEYOR_PROJECT_SLUG\dist"
- ps: $env:PYFA_VERSION = (python ./scripts/dump_version.py)
- ps: echo("pyfa version ")
- ps: echo ($env:PYFA_VERSION)
build_script: build_script:
# Build the compiled extension
# - "python setup.py build"
- ECHO "Build pyfa:" - ECHO "Build pyfa:"
#- copy C:\projects\pyfa\dist_assets\win\pyfa.spec C:\projects\pyfa\pyfa.spec
- "python C:\\projects\\pyfa\\setup.py build"
##########
# PyInstaller - create binaries for pyfa
##########
# Build command for PyInstaller
- "python -m PyInstaller --noupx --clean --windowed --noconsole -y pyfa.spec"
# Copy over manifest (See pyfa-org/pyfa#1622)
- ps: xcopy /y dist_assets\win\pyfa.exe.manifest $env:PYFA_DIST_DIR\pyfa\
# Not really sure if this is needed, but why not
- ps: xcopy /y dist_assets\win\Microsoft.VC90.CRT.manifest $env:PYFA_DIST_DIR\pyfa\
##########
# InnoScript EXE building
# This is in a separate script because I don't feel like copying over the logic to AppVeyor script right now...
##########
- "python dist_assets/win/dist.py"
- ps: dir $env:PYFA_DIST_DIR/
#- ECHO "Build pyfa (Debug):" #- ECHO "Build pyfa (Debug):"
#- copy C:\projects\pyfa\dist_assets\win\pyfa_debug.spec C:\projects\pyfa\pyfa_debug.spec #- copy C:\projects\pyfa\dist_assets\win\pyfa_debug.spec C:\projects\pyfa\pyfa_debug.spec
#- "pyinstaller.exe --clean --noconfirm --windowed --upx-dir=C:\\projects\\pyfa\\scripts\\upx.exe C:\\projects\\pyfa\\pyfa_debug.spec" #- "pyinstaller.exe --clean --noconfirm --windowed --upx-dir=C:\\projects\\pyfa\\scripts\\upx.exe C:\\projects\\pyfa\\pyfa_debug.spec"
@@ -150,12 +90,11 @@ build: on
after_build: after_build:
- ps: "ls \"./\"" - ps: "ls \"./\""
#- ps: "ls \"C:\\projects\\pyfa\\build\\pyfa\\\"" #- ps: "ls \"C:\\projects\\pyfa\\build\\pyfa\\\""
- ps: "ls \"C:\\projects\\pyfa\\build\\\"" # - ps: "ls \"C:\\projects\\$env:APPVEYOR_PROJECT_SLUG\\build\\exe.win32-2.7\\\""
- ps: "ls \"C:\\projects\\pyfa\\build\\exe.win32-2.7\\\""
# Zip # Zip
# APPVEYOR_PULL_REQUEST_NUMBER -and $env:APPVEYOR_BUILD_NUMBER # APPVEYOR_PULL_REQUEST_NUMBER -and $env:APPVEYOR_BUILD_NUMBER
#- 7z a build.zip -r C:\projects\pyfa\build\pyfa\*.* #- 7z a build.zip -r C:\projects\pyfa\build\pyfa\*.*
- 7z a pyfa.zip -r C:\projects\pyfa\build\exe.win32-2.7\*.* - ps: 7z a "pyfa-$env:PYFA_VERSION-win.zip" -r "$env:PYFA_DIST_DIR\pyfa\*.*"
#- 7z a pyfa_debug.zip -r C:\projects\pyfa\dist\pyfa_debug\*.* #- 7z a pyfa_debug.zip -r C:\projects\pyfa\dist\pyfa_debug\*.*
on_success: on_success:
@@ -176,11 +115,21 @@ after_test:
artifacts: artifacts:
# Archive the generated packages in the ci.appveyor.com build report. # Archive the generated packages in the ci.appveyor.com build report.
- path: pyfa.zip - path: pyfa*-win.zip
name: 'pyfa.zip' - path: pyfa*-win.exe
#- path: pyfa_debug.zip #- path: pyfa_debug.zip
# name: Pyfa_debug # name: Pyfa_debug
deploy:
tag: $(pyfa_version)
release: pyfa $(pyfa_version)
description: 'Release description'
provider: GitHub
auth_token:
secure: BfNHO66ff5hVx2O2ORbl49X0U/5h2V2T0IuRZDwm7fd1HvsVluF0wRCbl29oRp1M
draft: true
on:
APPVEYOR_REPO_TAG: true # deploy on tag push only
#on_success: #on_success:
# - TODO: upload the content of dist/*.whl to a public wheelhouse # - TODO: upload the content of dist/*.whl to a public wheelhouse
# #

1
.gitignore vendored
View File

@@ -122,3 +122,4 @@ gitversion
/.version /.version
*.swp *.swp
*.fsdbinary

View File

@@ -1,39 +1,29 @@
os: linux
language: python language: python
cache: pip
python: python:
- '2.7' - 3.6
env: matrix:
- TOXENV=pep8 include:
addons: - os: osx
apt: osx_image: xcode7.3
packages: language: generic
env: PYTHON=3.6.1
before_install: before_install:
- sudo apt-get update && sudo apt-get --reinstall install -qq language-pack-en language-pack-ru language-pack-he language-pack-zh-hans - bash scripts/setup-osx.sh
- pip install tox
# We're not actually installing Tox, but have to run it before we install wxPython via Conda. This is fugly but vOv
- tox
# get Conda
- if [[ "$TRAVIS_PYTHON_VERSION" == "2.7" ]]; then
wget https://repo.continuum.io/miniconda/Miniconda-latest-Linux-x86_64.sh -O miniconda.sh;
else
wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda.sh;
fi
- bash miniconda.sh -b -p $HOME/miniconda
- export PATH="$HOME/miniconda/bin:$PATH"
- hash -r
- conda config --set always_yes yes --set changeps1 no
- conda update -q conda
# Useful for debugging any issues with conda
- conda info -a
install: install:
# install wxPython 3.0.0.0 - export PYFA_VERSION="$(python3 scripts/dump_version.py)"
- conda install -c https://conda.anaconda.org/travis wxpython - bash scripts/package-osx.sh
before_script:
- pip install -r requirements.txt
- pip install -r requirements_test.txt
script:
- py.test --cov=./
after_success:
- bash <(curl -s https://codecov.io/bash)
before_deploy: before_deploy:
- pip install -r requirements_build_linux.txt - export RELEASE_PKG_FILE=$(ls *.deb)
- echo "deploying $RELEASE_PKG_FILE to GitHub releases"
deploy:
provider: releases
api_key:
secure: Xfu0xApoB0zUPLXl29aYUulVC3iA4/3bXQwwADKCfAKZwxgNon4dLbO7Rie5/7Ukf2POL0KwmRaQGN3kOr+XSoIVTE4M5sXxnhiaaLGKQ+48hDizLE6JuXcZGJvkxUaghaTzIdCwHsG7VGBsPfQgfGsjJcfBp8tFNLmRyM/Jpsr8T6BR2MxtBIEUVy8zrOWFNZqnmWrY2pWMsB9fYt3JFNdpqeIgRAYqbBsBcZQ1MngLTi3ztuYS5IaF+lk06RrnBlHmUsJu/5nCvIpvPvD0i2BLZ3Uu0+Fn+8QWUgjJEL9MNseXZMXynu05xd8YRk7Ajc9CUrzQIIbAktyteYp85kE3pUJHmrMLcXhh7nqkwttR5/47Zwa3OLJLJFKBxMx6wY5jFkJjkV08850B7aWrmTFl/Eqc3Q5nZMuiEt3wFRbjxHi9h1mTN/fkxfRRHg8u3ENGPR+ZPiFC3J18qtks/B/hsKjjHvZP1i79OYlET4V/zyLyyQkCbpDaARQANuotLYJyZ7tH+KWEyRsvTi0M9Yev9mNNw6aI4vzh4HfkEhvcvnWnYwckPj1dnjQ573Qpw0Z9wsconoWfHAn+hBDt3+YLMrrFZl++mCRskHH1mZChX3aGMDi49zD0kfxBUkYPOAhguc6PwudBxHUZP+O6T/SoHylff6EizCE/k5dGeAk=
file_glob: true
file: "dist/pyfa-*.zip"
skip_cleanup: true
draft: true
on:
tags: true
repo: pyfa-org/Pyfa

View File

@@ -100,8 +100,8 @@ def DBInMemory():
import eos.db import eos.db
# Output debug info to help us troubleshoot Travis # Output debug info to help us troubleshoot Travis
print((eos.db.saveddata_engine)) print(eos.db.saveddata_engine)
print((eos.db.gamedata_engine)) print(eos.db.gamedata_engine)
helper = { helper = {
'config': eos.config, 'config': eos.config,

View File

@@ -1,7 +1,6 @@
import pytest import pytest
# noinspection PyPackageRequirements # noinspection PyPackageRequirements
from _development.helpers import DBInMemory as DB, Gamedata, Saveddata
# noinspection PyShadowingNames # noinspection PyShadowingNames

View File

@@ -1,7 +1,6 @@
import pytest import pytest
# noinspection PyPackageRequirements # noinspection PyPackageRequirements
from _development.helpers import DBInMemory as DB, Gamedata, Saveddata
# noinspection PyShadowingNames # noinspection PyShadowingNames

View File

@@ -1,5 +1,6 @@
import os import os
import sys import sys
import yaml
from logbook import CRITICAL, DEBUG, ERROR, FingersCrossedHandler, INFO, Logger, NestedSetup, NullHandler, \ from logbook import CRITICAL, DEBUG, ERROR, FingersCrossedHandler, INFO, Logger, NestedSetup, NullHandler, \
StreamHandler, TimedRotatingFileHandler, WARNING StreamHandler, TimedRotatingFileHandler, WARNING
@@ -22,12 +23,6 @@ debug = False
# Defines if our saveddata will be in pyfa root or not # Defines if our saveddata will be in pyfa root or not
saveInRoot = False saveInRoot = False
# Version data
version = "2.0.0"
tag = "Stable"
expansionName = "YC120.3"
expansionVersion = "1.8"
evemonMinVersion = "4081" evemonMinVersion = "4081"
minItemSearchLength = 3 minItemSearchLength = 3
@@ -42,7 +37,6 @@ logging_setup = None
cipher = None cipher = None
clientHash = None clientHash = None
ESI_AUTH_PROXY = "https://www.pyfa.io" # "http://localhost:5015"
ESI_CACHE = 'esi_cache' ESI_CACHE = 'esi_cache'
LOGLEVEL_MAP = { LOGLEVEL_MAP = {
@@ -80,12 +74,7 @@ def getPyfaRoot():
def getVersion(): def getVersion():
if os.path.isfile(os.path.join(pyfaPath, '.version')): return version
with open(os.path.join(pyfaPath, '.version')) as f:
gitVersion = f.readline()
return gitVersion
# if no version file exists, then user is running from source or not an official build
return version + " (git)"
def getDefaultSave(): def getDefaultSave():
@@ -97,11 +86,12 @@ def defPaths(customSavePath=None):
global pyfaPath global pyfaPath
global savePath global savePath
global saveDB global saveDB
global gameDB global gameDB
global saveInRoot global saveInRoot
global logPath global logPath
global cipher global cipher
global clientHash global clientHash
global version
pyfalog.debug("Configuring Pyfa") pyfalog.debug("Configuring Pyfa")
@@ -111,6 +101,12 @@ def defPaths(customSavePath=None):
if pyfaPath is None: if pyfaPath is None:
pyfaPath = getPyfaRoot() pyfaPath = getPyfaRoot()
# Version data
with open(os.path.join(pyfaPath, "version.yml"), 'r') as file:
data = yaml.load(file)
version = data['version']
# Where we store the saved fits etc, default is the current users home directory # Where we store the saved fits etc, default is the current users home directory
if saveInRoot is True: if saveInRoot is True:
savePath = getattr(configforced, "savePath", None) savePath = getattr(configforced, "savePath", None)
@@ -230,20 +226,6 @@ def defLogging():
) )
]) ])
with logging_setup.threadbound():
# Output all stdout (print) messages as warnings
try:
sys.stdout = LoggerWriter(pyfalog.warning)
except:
pyfalog.critical("Cannot redirect. Continuing without writing stdout to log.")
# Output all stderr (stacktrace) messages as critical
try:
sys.stderr = LoggerWriter(pyfalog.critical)
except:
pyfalog.critical("Cannot redirect. Continuing without writing stderr to log.")
class LoggerWriter(object): class LoggerWriter(object):
def __init__(self, level): def __init__(self, level):

View File

@@ -24,11 +24,15 @@ added_files = [
('../../eve.db', '.'), ('../../eve.db', '.'),
('../../README.md', '.'), ('../../README.md', '.'),
('../../LICENSE', '.'), ('../../LICENSE', '.'),
('../../.version', '.'), ('../../version.yml', '.'),
] ]
import_these = [] import_these = [
'numpy.core._dtype_ctypes' # https://github.com/pyinstaller/pyinstaller/issues/3982
]
icon = os.path.join(os.getcwd(), "dist_assets", "mac", "pyfa.icns")
# Walk directories that do dynamic importing # Walk directories that do dynamic importing
paths = ('eos/effects', 'eos/db/migrations', 'service/conversions') paths = ('eos/effects', 'eos/db/migrations', 'service/conversions')
@@ -52,8 +56,10 @@ a = Analysis([r'../../pyfa.py'],
win_no_prefer_redirects=False, win_no_prefer_redirects=False,
win_private_assemblies=False, win_private_assemblies=False,
cipher=block_cipher) cipher=block_cipher)
pyz = PYZ(a.pure, a.zipped_data, pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher) cipher=block_cipher)
exe = EXE(pyz, exe = EXE(pyz,
a.scripts, a.scripts,
a.binaries, a.binaries,
@@ -65,10 +71,19 @@ exe = EXE(pyz,
upx=True, upx=True,
runtime_tmpdir=None, runtime_tmpdir=None,
console=False , console=False ,
icon='dist_assets/mac/pyfa.icns', icon=icon,
) )
app = BUNDLE(exe, app = BUNDLE(
name='pyfa.app', exe,
icon=None, name='pyfa.app',
bundle_identifier=None) icon=icon,
bundle_identifier=None,
info_plist={
'NSHighResolutionCapable': 'True',
'NSPrincipalClass': 'NSApplication',
'CFBundleName': 'pyfa',
'CFBundleDisplayName': 'pyfa',
'CFBundleIdentifier': 'org.pyfaorg.pyfa',
}
)

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<noInheritable/>
<assemblyIdentity
type="win32"
name="Microsoft.VC90.CRT"
version="9.0.21022.8"
processorArchitecture="x86"
publicKeyToken="1fc8b3b9a1e18e3b"/>
<file name="MSVCR90.DLL"/>
<file name="MSVCM90.DLL"/>
<file name="MSVCP90.DLL"/>
</assembly>

37
dist_assets/win/dist.py Normal file
View File

@@ -0,0 +1,37 @@
# helper script to zip up pyinstaller distribution and create installer file
import os.path
from subprocess import call
import zipfile
from packaging.version import Version
import yaml
with open("version.yml", 'r') as file:
data = yaml.load(file)
version = data['version']
os.environ["PYFA_DIST_DIR"] = os.path.join(os.getcwd(), 'dist')
os.environ["PYFA_VERSION"] = version
iscc = "C:\Program Files (x86)\Inno Setup 5\ISCC.exe" # inno script location via wine
source = os.path.join(os.environ["PYFA_DIST_DIR"], "pyfa")
fileName = "pyfa-{}-win".format(os.environ["PYFA_VERSION"])
print("Compiling EXE")
v = Version(version)
print(v)
call([
iscc,
os.path.join(os.getcwd(), "dist_assets", "win", "pyfa-setup.iss"),
"/dMyAppVersion=%s" % v,
"/dMyAppDir=%s" % source,
"/dMyOutputDir=%s" % os.path.join(os.getcwd()),
"/dMyOutputFile=%s" % fileName]) # stdout=devnull, stderr=devnull
print("Done")

View File

@@ -5,24 +5,22 @@
; we do some #ifdef conditionals because automated compilation passes these as arguments ; we do some #ifdef conditionals because automated compilation passes these as arguments
#ifndef MyAppVersion #ifndef MyAppVersion
#define MyAppVersion "1.15.0" #define MyAppVersion "2.1.0"
#endif
#ifndef MyAppExpansion
#define MyAppExpansion "Vanguard 1.0"
#endif #endif
; Other config ; Other config
#define MyAppName "pyfa" #define MyAppName "pyfa"
#define MyAppPublisher "pyfa" #define MyAppPublisher "pyfa"
#define MyAppURL "https://forums.eveonline.com/t/27156" #define MyAppURL "https://github.com/pyfa-org/Pyfa/"
#define MyAppExeName "pyfa.exe" #define MyAppExeName "pyfa.exe"
; What version starts with the new structure (1.x.0). This is used to determine if we run directory structure cleanup ; What version starts with the new structure (1.x.0). This is used to determine if we run directory structure cleanup
#define VersionFlag 16 #define MajorVersionFlag 2
#define MinorVersionFlag 0
#ifndef MyOutputFile #ifndef MyOutputFile
#define MyOutputFile LowerCase(StringChange(MyAppName+'-'+MyAppVersion+'-'+MyAppExpansion+'-win-wx3', " ", "-")) #define MyOutputFile LowerCase(StringChange(MyAppName+'-'+MyAppVersion+'-win', " ", "-"))
#endif #endif
#ifndef MyAppDir #ifndef MyAppDir
#define MyAppDir "pyfa" #define MyAppDir "pyfa"
@@ -38,7 +36,7 @@
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.) ; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
AppId={{3DA39096-C08D-49CD-90E0-1D177F32C8AA} AppId={{3DA39096-C08D-49CD-90E0-1D177F32C8AA}
AppName={#MyAppName} AppName={#MyAppName}
AppVersion={#MyAppVersion} ({#MyAppExpansion}) AppVersion={#MyAppVersion}
AppPublisher={#MyAppPublisher} AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL} AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL} AppSupportURL={#MyAppURL}
@@ -50,10 +48,8 @@ LicenseFile={#MyAppDir}\LICENSE
OutputDir={#MyOutputDir} OutputDir={#MyOutputDir}
OutputBaseFilename={#MyOutputFile} OutputBaseFilename={#MyOutputFile}
SetupIconFile={#MyAppDir}\pyfa.ico SetupIconFile={#MyAppDir}\pyfa.ico
Compression=lzma
SolidCompression=yes SolidCompression=yes
CloseApplications=yes CloseApplications=yes
AppReadmeFile=https://github.com/pyfa-org/Pyfa/blob/v{#MyAppVersion}/readme.txt
[Languages] [Languages]
Name: "english"; MessagesFile: "compiler:Default.isl" Name: "english"; MessagesFile: "compiler:Default.isl"
@@ -63,7 +59,7 @@ Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{
Name: "quicklaunchicon"; Description: "{cm:CreateQuickLaunchIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked; OnlyBelowVersion: 0,6.1 Name: "quicklaunchicon"; Description: "{cm:CreateQuickLaunchIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked; OnlyBelowVersion: 0,6.1
[Files] [Files]
Source: "{#MyAppDir}\pyfa.exe"; DestDir: "{app}"; Flags: ignoreversion Source: "{#MyAppDir}\pyfa.exe"; DestDir: "{app}"; Flags: ignoreversion; AfterInstall: RemoveFromVirtualStore
Source: "{#MyAppDir}\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs Source: "{#MyAppDir}\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
; NOTE: Don't use "Flags: ignoreversion" on any shared system files ; NOTE: Don't use "Flags: ignoreversion" on any shared system files
@@ -103,6 +99,22 @@ begin
FSWbemLocator := Unassigned; FSWbemLocator := Unassigned;
end; end;
procedure RemoveFromVirtualStore;
var
VirtualStore,FileName,FilePath:String;
DriveChars:Integer;
begin
VirtualStore:=AddBackslash(ExpandConstant('{localappdata}'))+'VirtualStore';
FileName:=ExpandConstant(CurrentFileName);
DriveChars:=Length(ExtractFileDrive(FileName));
if DriveChars>0 then begin
Delete(FileName,1,DriveChars);
FileName:=VirtualStore+FileName;
FilePath:=ExtractFilePath(FileName);
DelTree(FilePath, True, True, True);
end;
end;
function PrepareToInstall(var NeedsRestart: Boolean): String; function PrepareToInstall(var NeedsRestart: Boolean): String;
begin begin
if(IsAppRunning( 'pyfa.exe' )) then if(IsAppRunning( 'pyfa.exe' )) then
@@ -138,15 +150,19 @@ var
V: Integer; V: Integer;
iResultCode: Integer; iResultCode: Integer;
sUnInstallString: string; sUnInstallString: string;
iOldVersion: Cardinal; iOldVersionMajor: Cardinal;
iOldVersionMinor: Cardinal;
begin begin
Result := True; // in case when no previous version is found Result := True; // in case when no previous version is found
if RegValueExists(HKEY_LOCAL_MACHINE,'Software\Microsoft\Windows\CurrentVersion\Uninstall\{3DA39096-C08D-49CD-90E0-1D177F32C8AA}_is1', 'UninstallString') then //Your App GUID/ID if RegValueExists(HKEY_LOCAL_MACHINE,'Software\Microsoft\Windows\CurrentVersion\Uninstall\{3DA39096-C08D-49CD-90E0-1D177F32C8AA}_is1', 'UninstallString') then //Your App GUID/ID
begin begin
RegQueryDWordValue(HKEY_LOCAL_MACHINE, RegQueryDWordValue(HKEY_LOCAL_MACHINE,
'Software\Microsoft\Windows\CurrentVersion\Uninstall\{3DA39096-C08D-49CD-90E0-1D177F32C8AA}_is1', 'Software\Microsoft\Windows\CurrentVersion\Uninstall\{3DA39096-C08D-49CD-90E0-1D177F32C8AA}_is1',
'MinorVersion', iOldVersion); 'MajorVersion', iOldVersionMajor);
if iOldVersion < {#VersionFlag} then // If old version with old structure is installed. RegQueryDWordValue(HKEY_LOCAL_MACHINE,
'Software\Microsoft\Windows\CurrentVersion\Uninstall\{3DA39096-C08D-49CD-90E0-1D177F32C8AA}_is1',
'MinorVersion', iOldVersionMinor);
if (iOldVersionMajor < {#MajorVersionFlag}) or ((iOldVersionMajor = {#MajorVersionFlag}) and (iOldVersionMinor < {#MinorVersionFlag})) then // If old version with old structure is installed.
begin begin
V := MsgBox(ExpandConstant('An old version of pyfa was detected. Due to recent changes in the application structure, you must uninstall the previous version first. This will not affect your user data (saved fittings, characters, etc.). Do you want to uninstall now?'), mbInformation, MB_YESNO); //Custom Message if App installed V := MsgBox(ExpandConstant('An old version of pyfa was detected. Due to recent changes in the application structure, you must uninstall the previous version first. This will not affect your user data (saved fittings, characters, etc.). Do you want to uninstall now?'), mbInformation, MB_YESNO); //Custom Message if App installed
if V = IDYES then if V = IDYES then

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity name="pyfa" processorArchitecture="x86" type="win32" version="1.0.0.0"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="asInvoker" uiAccess="false"></requestedExecutionLevel>
</requestedPrivileges>
</security>
</trustInfo>
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32" name="Microsoft.VC90.CRT" version="9.0.21022.8" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"></assemblyIdentity>
</dependentAssembly>
</dependency>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
</application>
</compatibility>
</assembly>

View File

@@ -5,8 +5,7 @@ from itertools import chain
import subprocess import subprocess
import requests.certs import requests.certs
label = subprocess.check_output([ label = subprocess.check_output(["git", "describe", "--tags"]).strip()
"git", "describe", "--tags"]).strip()
with open('.version', 'w+') as f: with open('.version', 'w+') as f:
f.write(label.decode()) f.write(label.decode())
@@ -18,16 +17,20 @@ added_files = [
('../../imgs/gui/*.gif', 'imgs/gui'), ('../../imgs/gui/*.gif', 'imgs/gui'),
('../../imgs/icons/*.png', 'imgs/icons'), ('../../imgs/icons/*.png', 'imgs/icons'),
('../../imgs/renders/*.png', 'imgs/renders'), ('../../imgs/renders/*.png', 'imgs/renders'),
('../../service/jargon/*.yaml', 'service/jargon'), ('../../service/jargon/*.yaml', 'service/jargon'),
('../../dist_assets/win/pyfa.ico', '.'), ('../../dist_assets/win/pyfa.ico', '.'),
('../../dist_assets/win/pyfa.exe.manifest', '.'),
('../../dist_assets/win/Microsoft.VC90.CRT.manifest', '.'),
(requests.certs.where(), '.'), # is this needed anymore? (requests.certs.where(), '.'), # is this needed anymore?
('../../eve.db', '.'), ('../../eve.db', '.'),
('../../README.md', '.'), ('../../README.md', '.'),
('../../LICENSE', '.'), ('../../LICENSE', '.'),
('../../.version', '.'), ('../../version.yml', '.'),
] ]
import_these = [] import_these = [
'numpy.core._dtype_ctypes' # https://github.com/pyinstaller/pyinstaller/issues/3982
]
# Walk directories that do dynamic importing # Walk directories that do dynamic importing
paths = ('eos/effects', 'eos/db/migrations', 'service/conversions') paths = ('eos/effects', 'eos/db/migrations', 'service/conversions')
@@ -79,4 +82,5 @@ coll = COLLECT(
upx=True, upx=True,
name='pyfa', name='pyfa',
icon='dist_assets/win/pyfa.ico', icon='dist_assets/win/pyfa.ico',
) )

View File

@@ -11,6 +11,7 @@ debug = False
gamedataCache = True gamedataCache = True
saveddataCache = True saveddataCache = True
gamedata_version = "" gamedata_version = ""
gamedata_date = ""
gamedata_connectionstring = 'sqlite:///' + realpath(join(dirname(abspath(__file__)), "..", "eve.db")) gamedata_connectionstring = 'sqlite:///' + realpath(join(dirname(abspath(__file__)), "..", "eve.db"))
pyfalog.debug("Gamedata connection string: {0}", gamedata_connectionstring) pyfalog.debug("Gamedata connection string: {0}", gamedata_connectionstring)

View File

@@ -51,10 +51,14 @@ try:
config.gamedata_version = gamedata_session.execute( config.gamedata_version = gamedata_session.execute(
"SELECT `field_value` FROM `metadata` WHERE `field_name` LIKE 'client_build'" "SELECT `field_value` FROM `metadata` WHERE `field_name` LIKE 'client_build'"
).fetchone()[0] ).fetchone()[0]
config.gamedata_date = gamedata_session.execute(
"SELECT `field_value` FROM `metadata` WHERE `field_name` LIKE 'dump_time'"
).fetchone()[0]
except Exception as e: except Exception as e:
pyfalog.warning("Missing gamedata version.") pyfalog.warning("Missing gamedata version.")
pyfalog.critical(e) pyfalog.critical(e)
config.gamedata_version = None config.gamedata_version = None
config.gamedata_date = None
saveddata_connectionstring = config.saveddata_connectionstring saveddata_connectionstring = config.saveddata_connectionstring
if saveddata_connectionstring is not None: if saveddata_connectionstring is not None:
@@ -74,10 +78,10 @@ sd_lock = threading.RLock()
# Import all the definitions for all our database stuff # Import all the definitions for all our database stuff
# noinspection PyPep8 # noinspection PyPep8
from eos.db.gamedata import alphaClones, attribute, category, effect, group, icon, item, marketGroup, metaData, metaGroup, queries, traits, unit from eos.db.gamedata import alphaClones, attribute, category, effect, group, item, marketGroup, metaData, metaGroup, queries, traits, unit, dynamicAttributes
# noinspection PyPep8 # noinspection PyPep8
from eos.db.saveddata import booster, cargo, character, damagePattern, databaseRepair, drone, fighter, fit, implant, implantSet, loadDefaultDatabaseValues, \ from eos.db.saveddata import booster, cargo, character, damagePattern, databaseRepair, drone, fighter, fit, implant, implantSet, loadDefaultDatabaseValues, \
miscData, module, override, price, queries, skill, targetResists, user miscData, mutator, module, override, price, queries, skill, targetResists, user
# Import queries # Import queries
# noinspection PyPep8 # noinspection PyPep8

View File

@@ -1,2 +1,2 @@
__all__ = ["attribute", "category", "effect", "group", "metaData", __all__ = ["attribute", "category", "effect", "group", "metaData", "dynamicAttributes",
"icon", "item", "marketGroup", "metaGroup", "unit", "alphaClones"] "item", "marketGroup", "metaGroup", "unit", "alphaClones"]

View File

@@ -22,7 +22,7 @@ from sqlalchemy.ext.associationproxy import association_proxy
from sqlalchemy.orm import relation, mapper, synonym, deferred from sqlalchemy.orm import relation, mapper, synonym, deferred
from eos.db import gamedata_meta from eos.db import gamedata_meta
from eos.gamedata import Attribute, AttributeInfo, Unit, Icon from eos.gamedata import Attribute, AttributeInfo, Unit
typeattributes_table = Table("dgmtypeattribs", gamedata_meta, typeattributes_table = Table("dgmtypeattribs", gamedata_meta,
Column("value", Float), Column("value", Float),
@@ -38,7 +38,7 @@ attributes_table = Table("dgmattribs", gamedata_meta,
Column("published", Boolean), Column("published", Boolean),
Column("displayName", String), Column("displayName", String),
Column("highIsGood", Boolean), Column("highIsGood", Boolean),
Column("iconID", Integer, ForeignKey("icons.iconID")), Column("iconID", Integer),
Column("unitID", Integer, ForeignKey("dgmunits.unitID"))) Column("unitID", Integer, ForeignKey("dgmunits.unitID")))
mapper(Attribute, typeattributes_table, mapper(Attribute, typeattributes_table,
@@ -46,7 +46,6 @@ mapper(Attribute, typeattributes_table,
mapper(AttributeInfo, attributes_table, mapper(AttributeInfo, attributes_table,
properties={ properties={
"icon" : relation(Icon),
"unit" : relation(Unit), "unit" : relation(Unit),
"ID" : synonym("attributeID"), "ID" : synonym("attributeID"),
"name" : synonym("attributeName"), "name" : synonym("attributeName"),

View File

@@ -17,22 +17,21 @@
# along with eos. If not, see <http://www.gnu.org/licenses/>. # along with eos. If not, see <http://www.gnu.org/licenses/>.
# =============================================================================== # ===============================================================================
from sqlalchemy import Column, String, Integer, ForeignKey, Boolean, Table from sqlalchemy import Boolean, Column, Integer, String, Table
from sqlalchemy.orm import relation, mapper, synonym, deferred from sqlalchemy.orm import deferred, mapper, synonym
from eos.db import gamedata_meta from eos.db import gamedata_meta
from eos.gamedata import Category, Icon from eos.gamedata import Category
categories_table = Table("invcategories", gamedata_meta, categories_table = Table("invcategories", gamedata_meta,
Column("categoryID", Integer, primary_key=True), Column("categoryID", Integer, primary_key=True),
Column("categoryName", String), Column("categoryName", String),
Column("description", String), Column("description", String),
Column("published", Boolean), Column("published", Boolean),
Column("iconID", Integer, ForeignKey("icons.iconID"))) Column("iconID", Integer))
mapper(Category, categories_table, mapper(Category, categories_table,
properties={ properties={
"icon" : relation(Icon),
"ID" : synonym("categoryID"), "ID" : synonym("categoryID"),
"name" : synonym("categoryName"), "name" : synonym("categoryName"),
"description": deferred(categories_table.c.description) "description": deferred(categories_table.c.description)

View File

@@ -0,0 +1,65 @@
# ===============================================================================
# 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, Float, Integer, Table, ForeignKey
from sqlalchemy.orm import mapper, relation, synonym
from sqlalchemy.ext.associationproxy import association_proxy
from eos.db import gamedata_meta
from eos.gamedata import DynamicItem, DynamicItemAttribute, DynamicItemItem, Item
from eos.gamedata import AttributeInfo
dynamic_table = Table("mutaplasmids", gamedata_meta,
Column("typeID", ForeignKey("invtypes.typeID"), primary_key=True, index=True),
Column("resultingTypeID", ForeignKey("invtypes.typeID"), primary_key=True))
dynamicAttributes_table = Table("mutaplasmidAttributes", gamedata_meta,
Column("typeID", Integer, ForeignKey("mutaplasmids.typeID"), primary_key=True),
Column("attributeID", ForeignKey("dgmattribs.attributeID"), primary_key=True),
Column("min", Float),
Column("max", Float))
dynamicApplicable_table = Table("mutaplasmidItems", gamedata_meta,
Column("typeID", ForeignKey("mutaplasmids.typeID"), primary_key=True),
Column("applicableTypeID", ForeignKey("invtypes.typeID"), primary_key=True),)
mapper(DynamicItem, dynamic_table, properties={
"attributes": relation(DynamicItemAttribute),
"item": relation(Item, foreign_keys=[dynamic_table.c.typeID]),
"resultingItem": relation(Item, foreign_keys=[dynamic_table.c.resultingTypeID]),
"ID": synonym("typeID"),
})
mapper(DynamicItemAttribute, dynamicAttributes_table,
properties={"info": relation(AttributeInfo, lazy=False)})
mapper(DynamicItemItem, dynamicApplicable_table, properties={
"mutaplasmid": relation(DynamicItem),
})
DynamicItemAttribute.ID = association_proxy("info", "attributeID")
DynamicItemAttribute.name = association_proxy("info", "attributeName")
DynamicItemAttribute.description = association_proxy("info", "description")
DynamicItemAttribute.published = association_proxy("info", "published")
DynamicItemAttribute.displayName = association_proxy("info", "displayName")
DynamicItemAttribute.highIsGood = association_proxy("info", "highIsGood")
DynamicItemAttribute.iconID = association_proxy("info", "iconID")
DynamicItemAttribute.icon = association_proxy("info", "icon")
DynamicItemAttribute.unit = association_proxy("info", "unit")

View File

@@ -18,10 +18,10 @@
# =============================================================================== # ===============================================================================
from sqlalchemy import Column, String, Integer, Boolean, ForeignKey, Table from sqlalchemy import Column, String, Integer, Boolean, ForeignKey, Table
from sqlalchemy.orm import relation, mapper, synonym, deferred from sqlalchemy.orm import relation, mapper, synonym, deferred, backref
from eos.db import gamedata_meta from eos.db import gamedata_meta
from eos.gamedata import Category, Group, Icon from eos.gamedata import Category, Group
groups_table = Table("invgroups", gamedata_meta, groups_table = Table("invgroups", gamedata_meta,
Column("groupID", Integer, primary_key=True), Column("groupID", Integer, primary_key=True),
@@ -29,12 +29,11 @@ groups_table = Table("invgroups", gamedata_meta,
Column("description", String), Column("description", String),
Column("published", Boolean), Column("published", Boolean),
Column("categoryID", Integer, ForeignKey("invcategories.categoryID")), Column("categoryID", Integer, ForeignKey("invcategories.categoryID")),
Column("iconID", Integer, ForeignKey("icons.iconID"))) Column("iconID", Integer))
mapper(Group, groups_table, mapper(Group, groups_table,
properties={ properties={
"category" : relation(Category, backref="groups"), "category" : relation(Category, backref=backref("groups", cascade="all,delete")),
"icon" : relation(Icon),
"ID" : synonym("groupID"), "ID" : synonym("groupID"),
"name" : synonym("groupName"), "name" : synonym("groupName"),
"description": deferred(groups_table.c.description) "description": deferred(groups_table.c.description)

View File

@@ -1,35 +0,0 @@
# ===============================================================================
# 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
from sqlalchemy.orm import mapper, synonym, deferred
from eos.db import gamedata_meta
from eos.gamedata import Icon
icons_table = Table("icons", gamedata_meta,
Column("iconID", Integer, primary_key=True),
Column("description", String),
Column("iconFile", String))
mapper(Icon, icons_table,
properties={
"ID" : synonym("iconID"),
"description": deferred(icons_table.c.description)
})

View File

@@ -17,14 +17,15 @@
# along with eos. If not, see <http://www.gnu.org/licenses/>. # along with eos. If not, see <http://www.gnu.org/licenses/>.
# =============================================================================== # ===============================================================================
from sqlalchemy import Column, String, Integer, Boolean, ForeignKey, Table, Float from sqlalchemy import Boolean, Column, Float, ForeignKey, Integer, String, Table
from sqlalchemy.ext.associationproxy import association_proxy from sqlalchemy.ext.associationproxy import association_proxy
from sqlalchemy.orm import relation, mapper, synonym, deferred from sqlalchemy.orm import backref, deferred, mapper, relation, synonym
from sqlalchemy.orm.collections import attribute_mapped_collection from sqlalchemy.orm.collections import attribute_mapped_collection
from eos.db.gamedata.effect import typeeffects_table
from eos.db import gamedata_meta from eos.db import gamedata_meta
from eos.gamedata import Attribute, Effect, Group, Icon, Item, MetaType, Traits from eos.db.gamedata.dynamicAttributes import dynamicApplicable_table
from eos.db.gamedata.effect import typeeffects_table
from eos.gamedata import Attribute, DynamicItem, Effect, Group, Item, MetaType, Traits
items_table = Table("invtypes", gamedata_meta, items_table = Table("invtypes", gamedata_meta,
Column("typeID", Integer, primary_key=True), Column("typeID", Integer, primary_key=True),
@@ -37,16 +38,18 @@ items_table = Table("invtypes", gamedata_meta,
Column("capacity", Float), Column("capacity", Float),
Column("published", Boolean), Column("published", Boolean),
Column("marketGroupID", Integer, ForeignKey("invmarketgroups.marketGroupID")), Column("marketGroupID", Integer, ForeignKey("invmarketgroups.marketGroupID")),
Column("iconID", Integer, ForeignKey("icons.iconID")), Column("iconID", Integer),
Column("groupID", Integer, ForeignKey("invgroups.groupID"), index=True)) Column("graphicID", Integer),
Column("groupID", Integer, ForeignKey("invgroups.groupID"), index=True),
Column("replaceSame", String),
Column("replaceBetter", String))
from .metaGroup import metatypes_table # noqa from .metaGroup import metatypes_table # noqa
from .traits import traits_table # noqa from .traits import traits_table # noqa
mapper(Item, items_table, mapper(Item, items_table,
properties={ properties={
"group" : relation(Group, backref="items"), "group" : relation(Group, backref=backref("items", cascade="all,delete")),
"icon" : relation(Icon),
"_Item__attributes": relation(Attribute, cascade='all, delete, delete-orphan', collection_class=attribute_mapped_collection('name')), "_Item__attributes": relation(Attribute, cascade='all, delete, delete-orphan', collection_class=attribute_mapped_collection('name')),
"effects": relation(Effect, secondary=typeeffects_table, collection_class=attribute_mapped_collection('name')), "effects": relation(Effect, secondary=typeeffects_table, collection_class=attribute_mapped_collection('name')),
"metaGroup" : relation(MetaType, "metaGroup" : relation(MetaType,
@@ -57,7 +60,12 @@ mapper(Item, items_table,
"description" : deferred(items_table.c.description), "description" : deferred(items_table.c.description),
"traits" : relation(Traits, "traits" : relation(Traits,
primaryjoin=traits_table.c.typeID == items_table.c.typeID, primaryjoin=traits_table.c.typeID == items_table.c.typeID,
uselist=False) uselist=False),
"mutaplasmids": relation(DynamicItem,
primaryjoin=dynamicApplicable_table.c.applicableTypeID == items_table.c.typeID,
secondaryjoin=dynamicApplicable_table.c.typeID == DynamicItem.typeID,
secondary=dynamicApplicable_table,
backref="applicableItems")
}) })
Item.category = association_proxy("group", "category") Item.category = association_proxy("group", "category")

View File

@@ -21,7 +21,7 @@ from sqlalchemy import Column, String, Integer, Boolean, ForeignKey, Table
from sqlalchemy.orm import relation, mapper, synonym, deferred from sqlalchemy.orm import relation, mapper, synonym, deferred
from eos.db import gamedata_meta from eos.db import gamedata_meta
from eos.gamedata import Icon, Item, MarketGroup from eos.gamedata import Item, MarketGroup
marketgroups_table = Table("invmarketgroups", gamedata_meta, marketgroups_table = Table("invmarketgroups", gamedata_meta,
Column("marketGroupID", Integer, primary_key=True), Column("marketGroupID", Integer, primary_key=True),
@@ -30,14 +30,13 @@ marketgroups_table = Table("invmarketgroups", gamedata_meta,
Column("hasTypes", Boolean), Column("hasTypes", Boolean),
Column("parentGroupID", Integer, Column("parentGroupID", Integer,
ForeignKey("invmarketgroups.marketGroupID", initially="DEFERRED", deferrable=True)), ForeignKey("invmarketgroups.marketGroupID", initially="DEFERRED", deferrable=True)),
Column("iconID", Integer, ForeignKey("icons.iconID"))) Column("iconID", Integer))
mapper(MarketGroup, marketgroups_table, mapper(MarketGroup, marketgroups_table,
properties={ properties={
"items" : relation(Item, backref="marketGroup"), "items" : relation(Item, backref="marketGroup"),
"parent" : relation(MarketGroup, backref="children", "parent" : relation(MarketGroup, backref="children",
remote_side=[marketgroups_table.c.marketGroupID]), remote_side=[marketgroups_table.c.marketGroupID]),
"icon" : relation(Icon),
"ID" : synonym("marketGroupID"), "ID" : synonym("marketGroupID"),
"name" : synonym("marketGroupName"), "name" : synonym("marketGroupName"),
"description": deferred(marketgroups_table.c.description) "description": deferred(marketgroups_table.c.description)

View File

@@ -17,15 +17,16 @@
# along with eos. If not, see <http://www.gnu.org/licenses/>. # along with eos. If not, see <http://www.gnu.org/licenses/>.
# =============================================================================== # ===============================================================================
from sqlalchemy.orm import join, exc, aliased from sqlalchemy.inspection import inspect
from sqlalchemy.orm import aliased, exc, join
from sqlalchemy.sql import and_, or_, select from sqlalchemy.sql import and_, or_, select
import eos.config import eos.config
from eos.db import gamedata_session 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.gamedata.group import groups_table
from eos.db.gamedata.metaGroup import items_table, metatypes_table
from eos.db.util import processEager, processWhere from eos.db.util import processEager, processWhere
from eos.gamedata import AlphaClone, Attribute, Category, Group, Item, MarketGroup, MetaGroup, AttributeInfo, MetaData from eos.gamedata import AlphaClone, Attribute, AttributeInfo, Category, DynamicItem, Group, Item, MarketGroup, MetaData, MetaGroup
cache = {} cache = {}
configVal = getattr(eos.config, "gamedataCache", None) configVal = getattr(eos.config, "gamedataCache", None)
@@ -97,6 +98,36 @@ def getItem(lookfor, eager=None):
return item return item
def getMutaplasmid(lookfor, eager=None):
if isinstance(lookfor, int):
item = gamedata_session.query(DynamicItem).filter(DynamicItem.ID == lookfor).first()
else:
raise TypeError("Need integer as argument")
return item
def getItemWithBaseItemAttribute(lookfor, baseItemID, eager=None):
# A lot of this is described in more detail in #1597
item = gamedata_session.query(Item).get(lookfor)
base = getItem(baseItemID)
# we have to load all attributes for this object, otherwise we'll lose access to them when we expunge.
# todo: figure out a way to eagerly load all these via the query...
for x in [*inspect(Item).relationships.keys(), 'description']:
getattr(item, x)
# Copy over the attributes from the base, but ise the items attributes when there's an overlap
# WARNING: the attribute object still has the old typeID. I don't believe we access this typeID anywhere in the code,
# but should keep this in mind for now.
item._Item__attributes = {**base.attributes, **item.attributes}
# Expunge the item form the session. This is required to have different Abyssal / Base combinations loaded in memory.
# Without expunging it, once one Abyssal Web is created, SQLAlchmey will use it for all others. We don't want this,
# we want to generate a completely new object to work with
gamedata_session.expunge(item)
return item
@cachedQuery(1, "lookfor") @cachedQuery(1, "lookfor")
def getItems(lookfor, eager=None): def getItems(lookfor, eager=None):
""" """
@@ -361,6 +392,25 @@ def directAttributeRequest(itemIDs, attrIDs):
return result return result
def getAbyssalTypes():
return set([r.resultingTypeID for r in gamedata_session.query(DynamicItem.resultingTypeID).distinct()])
@cachedQuery(1, "itemID")
def getDynamicItem(itemID, eager=None):
try:
if isinstance(itemID, int):
if eager is None:
result = gamedata_session.query(DynamicItem).filter(DynamicItem.ID == itemID).one()
else:
result = gamedata_session.query(DynamicItem).options(*processEager(eager)).filter(DynamicItem.ID == itemID).one()
else:
raise TypeError("Need integer as argument")
except exc.NoResultFound:
result = None
return result
def getRequiredFor(itemID, attrMapping): def getRequiredFor(itemID, attrMapping):
Attribute1 = aliased(Attribute) Attribute1 = aliased(Attribute)
Attribute2 = aliased(Attribute) Attribute2 = aliased(Attribute)

View File

@@ -14,7 +14,7 @@ def upgrade(saveddata_engine):
"boosters": 2, "boosters": 2,
"cargo": 2, "cargo": 2,
"characters": 2, "characters": 2,
"crest": 1, # "crest": 1,
"damagePatterns": 2, "damagePatterns": 2,
"drones": 2, "drones": 2,
"fighters": 2, "fighters": 2,

View File

@@ -0,0 +1,18 @@
"""
Migration 28
- adds baseItemID and mutaplasmidID to modules table
"""
import sqlalchemy
def upgrade(saveddata_engine):
try:
saveddata_engine.execute("SELECT baseItemID FROM modules LIMIT 1")
except sqlalchemy.exc.DatabaseError:
saveddata_engine.execute("ALTER TABLE modules ADD COLUMN baseItemID INT;")
try:
saveddata_engine.execute("SELECT mutaplasmidID FROM modules LIMIT 1")
except sqlalchemy.exc.DatabaseError:
saveddata_engine.execute("ALTER TABLE modules ADD COLUMN mutaplasmidID INT;")

View File

@@ -0,0 +1,18 @@
"""
Migration 29
- adds spoolType and spoolAmount to modules table
"""
import sqlalchemy
def upgrade(saveddata_engine):
try:
saveddata_engine.execute("SELECT spoolType FROM modules LIMIT 1")
except sqlalchemy.exc.DatabaseError:
saveddata_engine.execute("ALTER TABLE modules ADD COLUMN spoolType INT;")
try:
saveddata_engine.execute("SELECT spoolAmount FROM modules LIMIT 1")
except sqlalchemy.exc.DatabaseError:
saveddata_engine.execute("ALTER TABLE modules ADD COLUMN spoolAmount FLOAT;")

View File

@@ -0,0 +1,17 @@
"""
Migration 30
- changes to prices table
"""
import sqlalchemy
def upgrade(saveddata_engine):
try:
saveddata_engine.execute("SELECT status FROM prices LIMIT 1")
except sqlalchemy.exc.DatabaseError:
# Just drop table, table will be re-created by sqlalchemy and
# data will be re-fetched
saveddata_engine.execute("DROP TABLE prices;")

View File

@@ -1,6 +1,7 @@
__all__ = [ __all__ = [
"character", "character",
"fit", "fit",
"mutator",
"module", "module",
"user", "user",
"skill", "skill",

View File

@@ -29,9 +29,6 @@ from eos.saveddata.user import User
from eos.saveddata.character import Character, Skill from eos.saveddata.character import Character, Skill
from eos.saveddata.ssocharacter import SsoCharacter from eos.saveddata.ssocharacter import SsoCharacter
characters_table = Table("characters", saveddata_meta, characters_table = Table("characters", saveddata_meta,
Column("ID", Integer, primary_key=True), Column("ID", Integer, primary_key=True),
Column("name", String, nullable=False), Column("name", String, nullable=False),

View File

@@ -17,33 +17,32 @@
# along with eos. If not, see <http://www.gnu.org/licenses/>. # along with eos. If not, see <http://www.gnu.org/licenses/>.
# =============================================================================== # ===============================================================================
from sqlalchemy.ext.associationproxy import association_proxy
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, DateTime
import datetime import datetime
from eos.db import saveddata_meta from sqlalchemy import Boolean, Column, DateTime, ForeignKey, Integer, String, Table
from eos.db import saveddata_session from sqlalchemy.ext.associationproxy import association_proxy
from sqlalchemy.orm import mapper, reconstructor, relation, relationship
from sqlalchemy.orm.collections import attribute_mapped_collection
from sqlalchemy.sql import and_
from eos.db import saveddata_meta, saveddata_session
from eos.db.saveddata.cargo import cargo_table from eos.db.saveddata.cargo import cargo_table
from eos.db.saveddata.drone import drones_table from eos.db.saveddata.drone import drones_table
from eos.db.saveddata.fighter import fighters_table from eos.db.saveddata.fighter import fighters_table
from eos.db.saveddata.implant import fitImplants_table from eos.db.saveddata.implant import fitImplants_table
from eos.db.saveddata.module import modules_table from eos.db.saveddata.module import modules_table
from eos.effectHandlerHelpers import HandledModuleList, HandledImplantBoosterList, HandledProjectedModList, \ from eos.effectHandlerHelpers import HandledDroneCargoList, HandledImplantBoosterList, HandledModuleList, HandledProjectedDroneList, 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.booster import Booster
from eos.saveddata.module import Module
from eos.saveddata.cargo import Cargo from eos.saveddata.cargo import Cargo
from eos.saveddata.character import Character
from eos.saveddata.damagePattern import DamagePattern from eos.saveddata.damagePattern import DamagePattern
from eos.saveddata.drone import Drone
from eos.saveddata.fighter import Fighter
from eos.saveddata.fit import Fit as es_Fit
from eos.saveddata.implant import Implant
from eos.saveddata.module import Module
from eos.saveddata.targetResists import TargetResists from eos.saveddata.targetResists import TargetResists
from eos.saveddata.user import User
fits_table = Table("fits", saveddata_meta, fits_table = Table("fits", saveddata_meta,
Column("ID", Integer, primary_key=True), Column("ID", Integer, primary_key=True),
@@ -56,7 +55,7 @@ fits_table = Table("fits", saveddata_meta,
Column("booster", Boolean, nullable=False, index=True, default=0), Column("booster", Boolean, nullable=False, index=True, default=0),
Column("targetResistsID", ForeignKey("targetResists.ID"), nullable=True), Column("targetResistsID", ForeignKey("targetResists.ID"), nullable=True),
Column("modeID", Integer, nullable=True), Column("modeID", Integer, nullable=True),
Column("implantLocation", Integer, nullable=False, default=ImplantLocation.FIT), Column("implantLocation", Integer, nullable=False),
Column("notes", String, nullable=True), Column("notes", String, nullable=True),
Column("ignoreRestrictions", Boolean, default=0), Column("ignoreRestrictions", Boolean, default=0),
Column("created", DateTime, nullable=True, default=datetime.datetime.now), Column("created", DateTime, nullable=True, default=datetime.datetime.now),
@@ -132,13 +131,13 @@ class CommandFit(object):
) )
es_Fit._Fit__projectedFits = association_proxy( es_Fit.projectedFitDict = association_proxy(
"victimOf", # look at the victimOf association... "victimOf", # look at the victimOf association...
"source_fit", # .. and return the source fits "source_fit", # .. and return the source fits
creator=lambda sourceID, source_fit: ProjectedFit(sourceID, source_fit) creator=lambda sourceID, source_fit: ProjectedFit(sourceID, source_fit)
) )
es_Fit._Fit__commandFits = association_proxy( es_Fit.commandFitDict = association_proxy(
"boostedOf", # look at the boostedOf association... "boostedOf", # look at the boostedOf association...
"booster_fit", # .. and return the booster fit "booster_fit", # .. and return the booster fit
creator=lambda boosterID, booster_fit: CommandFit(boosterID, booster_fit) creator=lambda boosterID, booster_fit: CommandFit(boosterID, booster_fit)

View File

@@ -17,18 +17,22 @@
# along with eos. If not, see <http://www.gnu.org/licenses/>. # along with eos. If not, see <http://www.gnu.org/licenses/>.
# =============================================================================== # ===============================================================================
from sqlalchemy import Table, Column, Integer, ForeignKey, CheckConstraint, Boolean, DateTime from sqlalchemy import Table, Column, Integer, Float, ForeignKey, CheckConstraint, Boolean, DateTime
from sqlalchemy.orm.collections import attribute_mapped_collection
from sqlalchemy.orm import relation, mapper from sqlalchemy.orm import relation, mapper
import datetime import datetime
from eos.db import saveddata_meta from eos.db import saveddata_meta
from eos.saveddata.module import Module from eos.saveddata.module import Module
from eos.saveddata.mutator import Mutator
from eos.saveddata.fit import Fit from eos.saveddata.fit import Fit
modules_table = Table("modules", saveddata_meta, modules_table = Table("modules", saveddata_meta,
Column("ID", Integer, primary_key=True), Column("ID", Integer, primary_key=True),
Column("fitID", Integer, ForeignKey("fits.ID"), nullable=False, index=True), Column("fitID", Integer, ForeignKey("fits.ID"), nullable=False, index=True),
Column("itemID", Integer, nullable=True), Column("itemID", Integer, nullable=True),
Column("baseItemID", Integer, nullable=True),
Column("mutaplasmidID", Integer, nullable=True),
Column("dummySlot", Integer, nullable=True, default=None), Column("dummySlot", Integer, nullable=True, default=None),
Column("chargeID", Integer), Column("chargeID", Integer),
Column("state", Integer, CheckConstraint("state >= -1"), CheckConstraint("state <= 2")), Column("state", Integer, CheckConstraint("state >= -1"), CheckConstraint("state <= 2")),
@@ -36,7 +40,17 @@ modules_table = Table("modules", saveddata_meta,
Column("position", Integer), Column("position", Integer),
Column("created", DateTime, nullable=True, default=datetime.datetime.now), Column("created", DateTime, nullable=True, default=datetime.datetime.now),
Column("modified", DateTime, nullable=True, onupdate=datetime.datetime.now), Column("modified", DateTime, nullable=True, onupdate=datetime.datetime.now),
Column("spoolType", Integer, nullable=True),
Column("spoolAmount", Float, nullable=True),
CheckConstraint('("dummySlot" = NULL OR "itemID" = NULL) AND "dummySlot" != "itemID"')) CheckConstraint('("dummySlot" = NULL OR "itemID" = NULL) AND "dummySlot" != "itemID"'))
mapper(Module, modules_table, mapper(Module, modules_table,
properties={"owner": relation(Fit)}) properties={
"owner": relation(Fit),
"mutators": relation(
Mutator,
backref="module",
cascade="all,delete-orphan",
collection_class=attribute_mapped_collection('attrID')
)
})

View File

@@ -0,0 +1,35 @@
# ===============================================================================
# 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/>.
# ===============================================================================
import datetime
from sqlalchemy import Column, DateTime, Float, ForeignKey, Integer, Table
from sqlalchemy.orm import mapper
from eos.db import saveddata_meta
from eos.saveddata.mutator import Mutator
mutator_table = Table("mutators", saveddata_meta,
Column("moduleID", Integer, ForeignKey("modules.ID"), primary_key=True, index=True),
Column("attrID", Integer, primary_key=True, index=True),
Column("value", Float, nullable=False),
Column("created", DateTime, nullable=True, default=datetime.datetime.now),
Column("modified", DateTime, nullable=True, onupdate=datetime.datetime.now))
mapper(Mutator, mutator_table)

View File

@@ -17,17 +17,20 @@
# along with eos. If not, see <http://www.gnu.org/licenses/>. # along with eos. If not, see <http://www.gnu.org/licenses/>.
# =============================================================================== # ===============================================================================
from sqlalchemy import Table, Column, Float, Integer from sqlalchemy import Table, Column, Float, Integer
from sqlalchemy.orm import mapper from sqlalchemy.orm import mapper
from eos.db import saveddata_meta from eos.db import saveddata_meta
from eos.saveddata.price import Price from eos.saveddata.price import Price
prices_table = Table("prices", saveddata_meta, prices_table = Table("prices", saveddata_meta,
Column("typeID", Integer, primary_key=True), Column("typeID", Integer, primary_key=True),
Column("price", Float, default=0.0), Column("price", Float, default=0.0),
Column("time", Integer, nullable=False), Column("time", Integer, nullable=False),
Column("failed", Integer)) Column("status", Integer, nullable=False))
mapper(Price, prices_table, properties={ mapper(Price, prices_table, properties={
"_Price__price": prices_table.c.price, "_Price__price": prices_table.c.price,

View File

@@ -542,8 +542,17 @@ def commit():
with sd_lock: with sd_lock:
try: try:
saveddata_session.commit() saveddata_session.commit()
saveddata_session.flush() except Exception:
except Exception as ex: saveddata_session.rollback()
exc_info = sys.exc_info()
raise exc_info[0](exc_info[1]).with_traceback(exc_info[2])
def flush():
with sd_lock:
try:
saveddata_session.flush()
except Exception:
saveddata_session.rollback() saveddata_session.rollback()
exc_info = sys.exc_info() exc_info = sys.exc_info()
raise exc_info[0](exc_info[1]).with_traceback(exc_info[2]) raise exc_info[0](exc_info[1]).with_traceback(exc_info[2])

View File

@@ -18,6 +18,7 @@
# =============================================================================== # ===============================================================================
from logbook import Logger from logbook import Logger
from utils.deprecated import deprecated
pyfalog = Logger(__name__) pyfalog = Logger(__name__)
@@ -113,6 +114,7 @@ class HandledList(list):
class HandledModuleList(HandledList): class HandledModuleList(HandledList):
def append(self, mod): def append(self, mod):
emptyPosition = float("Inf") emptyPosition = float("Inf")
for i in range(len(self)): for i in range(len(self)):
@@ -130,12 +132,32 @@ class HandledModuleList(HandledList):
self.remove(mod) self.remove(mod)
return return
self.appendIgnoreEmpty(mod)
def appendIgnoreEmpty(self, mod):
mod.position = len(self) mod.position = len(self)
HandledList.append(self, mod) HandledList.append(self, mod)
if mod.isInvalid: if mod.isInvalid:
self.remove(mod) self.remove(mod)
return return
def replaceRackPosition(self, rackPosition, mod):
listPositions = []
for currMod in self:
if currMod.slot == mod.slot:
listPositions.append(currMod.position)
listPositions.sort()
try:
modListPosition = listPositions[rackPosition]
except IndexError:
self.appendIgnoreEmpty(mod)
else:
self.toDummy(modListPosition)
if not mod.isEmpty:
self.toModule(modListPosition, mod)
if mod.isInvalid:
self.toDummy(modListPosition)
def insert(self, index, mod): def insert(self, index, mod):
mod.position = index mod.position = index
i = index i = index
@@ -163,6 +185,7 @@ class HandledModuleList(HandledList):
mod.position = index mod.position = index
self[index] = mod self[index] = mod
@deprecated
def freeSlot(self, slot): def freeSlot(self, slot):
for i in range(len(self)): for i in range(len(self)):
mod = self[i] mod = self[i]
@@ -195,14 +218,20 @@ class HandledImplantBoosterList(HandledList):
self.remove(thing) self.remove(thing)
return return
self.makeRoom(thing)
HandledList.append(self, thing)
def makeRoom(self, thing):
# if needed, remove booster that was occupying slot # if needed, remove booster that was occupying slot
oldObj = next((m for m in self if m.slot == thing.slot), None) oldObj = next((m for m in self if m.slot == thing.slot), None)
if oldObj: if oldObj:
pyfalog.info("Slot {0} occupied with {1}, replacing with {2}", 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)
itemID = oldObj.itemID
oldObj.itemID = 0 # hack to remove from DB. See GH issue #324 oldObj.itemID = 0 # hack to remove from DB. See GH issue #324
self.remove(oldObj) self.remove(oldObj)
return itemID
HandledList.append(self, thing) return None
class HandledSsoCharacterList(list): class HandledSsoCharacterList(list):
@@ -225,22 +254,30 @@ class HandledProjectedModList(HandledList):
return return
proj.projected = True proj.projected = True
isSystemEffect = proj.item.group.name == "Effect Beacon"
if isSystemEffect: if proj.isExclusiveSystemEffect:
# remove other system effects - only 1 per fit plz self.makeRoom(proj)
oldEffect = next((m for m in self if m.item.group.name == "Effect Beacon"), None)
if oldEffect:
pyfalog.info("System effect occupied with {0}, replacing with {1}", oldEffect.item.name, proj.item.name)
self.remove(oldEffect)
HandledList.append(self, proj) HandledList.append(self, proj)
# Remove non-projectable modules # Remove non-projectable modules
if not proj.item.isType("projected") and not isSystemEffect: if not proj.item.isType("projected") and not proj.isExclusiveSystemEffect:
self.remove(proj) self.remove(proj)
@property
def currentSystemEffect(self):
return next((m for m in self if m.isExclusiveSystemEffect), None)
def makeRoom(self, proj):
# remove other system effects - only 1 per fit plz
oldEffect = self.currentSystemEffect
if oldEffect:
pyfalog.info("System effect occupied with {0}, replacing with {1}", oldEffect.item.name, proj.item.name)
self.remove(oldEffect)
return oldEffect.itemID
return None
class HandledProjectedDroneList(HandledDroneCargoList): class HandledProjectedDroneList(HandledDroneCargoList):
def append(self, proj): def append(self, proj):

View File

@@ -13,11 +13,14 @@ type = "active"
def handler(fit, module, context): def handler(fit, module, context):
damagePattern = fit.damagePattern damagePattern = fit.damagePattern
# pyfalog.debug("==============================")
static_adaptive_behavior = eos.config.settings['useStaticAdaptiveArmorHardener'] static_adaptive_behavior = eos.config.settings['useStaticAdaptiveArmorHardener']
if (damagePattern.emAmount == damagePattern.thermalAmount == damagePattern.kineticAmount == damagePattern.explosiveAmount) and static_adaptive_behavior: if (damagePattern.emAmount == damagePattern.thermalAmount == damagePattern.kineticAmount == damagePattern.explosiveAmount) and static_adaptive_behavior:
pyfalog.debug("Setting adaptivearmorhardener resists to uniform profile.") # pyfalog.debug("Setting adaptivearmorhardener resists to uniform profile.")
for attr in ("armorEmDamageResonance", "armorThermalDamageResonance", "armorKineticDamageResonance", "armorExplosiveDamageResonance"):
fit.ship.multiplyItemAttr(attr, module.getModifiedItemAttr(attr), stackingPenalties=True, penaltyGroup="preMul")
return return
# Skip if there is no damage pattern. Example: projected ships or fleet boosters # Skip if there is no damage pattern. Example: projected ships or fleet boosters
@@ -30,7 +33,7 @@ def handler(fit, module, context):
damagePattern.kineticAmount * fit.ship.getModifiedItemAttr('armorKineticDamageResonance'), damagePattern.kineticAmount * fit.ship.getModifiedItemAttr('armorKineticDamageResonance'),
damagePattern.explosiveAmount * fit.ship.getModifiedItemAttr('armorExplosiveDamageResonance'), damagePattern.explosiveAmount * fit.ship.getModifiedItemAttr('armorExplosiveDamageResonance'),
) )
# pyfalog.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 = module.getModifiedItemAttr(
'resistanceShiftAmount') / 100 # The attribute is in percent and we want a fraction 'resistanceShiftAmount') / 100 # The attribute is in percent and we want a fraction
@@ -46,7 +49,7 @@ def handler(fit, module, context):
cycleList = [] cycleList = []
loopStart = -20 loopStart = -20
for num in range(50): for num in range(50):
# pyfalog.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. # 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. # This doesn't take into account stacking penalties. In a few cases fitting a Damage Control causes an inaccurate result.
damagePattern_tuples = [ damagePattern_tuples = [
@@ -84,7 +87,7 @@ def handler(fit, module, context):
RAHResistance[sortedDamagePattern_tuples[1][0]] = sortedDamagePattern_tuples[1][2] + change1 RAHResistance[sortedDamagePattern_tuples[1][0]] = sortedDamagePattern_tuples[1][2] + change1
RAHResistance[sortedDamagePattern_tuples[2][0]] = sortedDamagePattern_tuples[2][2] + change2 RAHResistance[sortedDamagePattern_tuples[2][0]] = sortedDamagePattern_tuples[2][2] + change2
RAHResistance[sortedDamagePattern_tuples[3][0]] = sortedDamagePattern_tuples[3][2] + change3 RAHResistance[sortedDamagePattern_tuples[3][0]] = sortedDamagePattern_tuples[3][2] + change3
# pyfalog.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. # See if the current RAH profile has been encountered before, indicating a loop.
for i, val in enumerate(cycleList): for i, val in enumerate(cycleList):
@@ -94,16 +97,16 @@ def handler(fit, module, context):
abs(RAHResistance[2] - val[2]) <= tolerance and \ abs(RAHResistance[2] - val[2]) <= tolerance and \
abs(RAHResistance[3] - val[3]) <= tolerance: abs(RAHResistance[3] - val[3]) <= tolerance:
loopStart = i loopStart = i
# pyfalog.debug("Loop found: %d-%d", loopStart, num) # pyfalog.debug("Loop found: %d-%d" % (loopStart, num))
break break
if loopStart >= 0: if loopStart >= 0:
break break
cycleList.append(list(RAHResistance)) cycleList.append(list(RAHResistance))
if loopStart < 0: # if loopStart < 0:
pyfalog.error("Reactive Armor Hardener failed to find equilibrium. Damage profile after armor: {0}/{1}/{2}/{3}", # pyfalog.error("Reactive Armor Hardener failed to find equilibrium. Damage profile after armor: {0}/{1}/{2}/{3}".format(
baseDamageTaken[0], baseDamageTaken[1], baseDamageTaken[2], baseDamageTaken[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. # Average the profiles in the RAH loop, or the last 20 if it didn't find a loop.
loopCycles = cycleList[loopStart:] loopCycles = cycleList[loopStart:]
@@ -117,7 +120,7 @@ def handler(fit, module, context):
average[i] = round(average[i] / numCycles, 3) average[i] = round(average[i] / numCycles, 3)
# Set the new resistances # Set the new resistances
# pyfalog.debug("Setting new resist profile: %f/%f/%f/%f", average[0], average[1], average[2],average[3]) # pyfalog.debug("Setting new resist profile: %f/%f/%f/%f" % ( average[0], average[1], average[2],average[3]))
for i, attr in enumerate(( for i, attr in enumerate((
'armorEmDamageResonance', 'armorThermalDamageResonance', 'armorKineticDamageResonance', 'armorEmDamageResonance', 'armorThermalDamageResonance', 'armorKineticDamageResonance',
'armorExplosiveDamageResonance')): 'armorExplosiveDamageResonance')):

View File

@@ -2,7 +2,7 @@
# #
# Used by: # Used by:
# Modules from group: Missile Launcher Bomb (2 of 2) # Modules from group: Missile Launcher Bomb (2 of 2)
# Modules from group: Shield Extender (33 of 33) # Modules from group: Shield Extender (36 of 36)
type = "passive" type = "passive"

View File

@@ -6,4 +6,4 @@ type = "passive"
def handler(fit, module, context): def handler(fit, module, context):
fit.ship.boostItemAttr("agility", module.getModifiedItemAttr("agilityMultiplier"), stackingPenalties=True) fit.ship.boostItemAttr("agility", module.getModifiedItemAttr("agilityBonus"), stackingPenalties=True)

View File

@@ -1,7 +1,7 @@
# ammoInfluenceCapNeed # ammoInfluenceCapNeed
# #
# Used by: # Used by:
# Items from category: Charge (478 of 928) # Items from category: Charge (493 of 949)
type = "passive" type = "passive"

View File

@@ -1,7 +1,7 @@
# ammoInfluenceRange # ammoInfluenceRange
# #
# Used by: # Used by:
# Items from category: Charge (572 of 928) # Items from category: Charge (587 of 949)
type = "passive" type = "passive"

View File

@@ -1,9 +1,9 @@
# ammoSpeedMultiplier # ammoSpeedMultiplier
# #
# Used by: # Used by:
# Charges from group: Festival Charges (23 of 23) # Charges from group: Festival Charges (26 of 26)
# Charges from group: Interdiction Probe (2 of 2) # Charges from group: Interdiction Probe (2 of 2)
# Charges from group: Structure Festival Charges (3 of 3) # Items from market group: Special Edition Assets > Special Edition Festival Assets (30 of 33)
type = "passive" type = "passive"

View File

@@ -1,12 +1,7 @@
# ammoTrackingMultiplier # ammoTrackingMultiplier
# #
# Used by: # Used by:
# Charges from group: Advanced Artillery Ammo (8 of 8) # Items from category: Charge (182 of 949)
# Charges from group: Advanced Autocannon Ammo (8 of 8)
# Charges from group: Advanced Beam Laser Crystal (8 of 8)
# Charges from group: Advanced Blaster Charge (8 of 8)
# Charges from group: Advanced Pulse Laser Crystal (8 of 8)
# Charges from group: Advanced Railgun Charge (8 of 8)
# Charges from group: Projectile Ammo (128 of 128) # Charges from group: Projectile Ammo (128 of 128)
type = "passive" type = "passive"

View File

@@ -0,0 +1,16 @@
# aoe_beacon_bioluminescence_cloud
#
# Used by:
# Celestials named like: Bioluminescence Cloud (3 of 3)
runTime = "early"
type = ("projected", "passive", "gang")
def handler(fit, beacon, context, **kwargs):
for x in range(1, 3):
if beacon.getModifiedItemAttr("warfareBuff{}ID".format(x)):
value = beacon.getModifiedItemAttr("warfareBuff{}Value".format(x))
id = beacon.getModifiedItemAttr("warfareBuff{}ID".format(x))
if id:
fit.addCommandBonus(id, value, beacon, kwargs['effect'], 'early')

View File

@@ -0,0 +1,16 @@
# aoe_beacon_caustic_cloud
#
# Used by:
# Celestials named like: Caustic Cloud (3 of 3)
runTime = "early"
type = ("projected", "passive", "gang")
def handler(fit, beacon, context, **kwargs):
for x in range(1, 3):
if beacon.getModifiedItemAttr("warfareBuff{}ID".format(x)):
value = beacon.getModifiedItemAttr("warfareBuff{}Value".format(x))
id = beacon.getModifiedItemAttr("warfareBuff{}ID".format(x))
if id:
fit.addCommandBonus(id, value, beacon, kwargs['effect'], 'early')

View File

@@ -0,0 +1,16 @@
# aoe_beacon_filament_cloud
#
# Used by:
# Celestials named like: Filament Cloud (3 of 3)
runTime = "early"
type = ("projected", "passive", "gang")
def handler(fit, beacon, context, **kwargs):
for x in range(1, 3):
if beacon.getModifiedItemAttr("warfareBuff{}ID".format(x)):
value = beacon.getModifiedItemAttr("warfareBuff{}Value".format(x))
id = beacon.getModifiedItemAttr("warfareBuff{}ID".format(x))
if id:
fit.addCommandBonus(id, value, beacon, kwargs['effect'], 'early')

View File

@@ -1,6 +1,7 @@
# armorAllRepairSystemsAmountBonusPassive # armorAllRepairSystemsAmountBonusPassive
# #
# Used by: # Used by:
# Implants named like: Agency 'Hardshell' TB Dose (4 of 4)
# Implants named like: Exile Booster (4 of 4) # Implants named like: Exile Booster (4 of 4)
# Implant: Antipharmakon Kosybo # Implant: Antipharmakon Kosybo
type = "passive" type = "passive"
@@ -9,4 +10,4 @@ type = "passive"
def handler(fit, booster, context): def handler(fit, booster, context):
fit.modules.filteredItemBoost( fit.modules.filteredItemBoost(
lambda mod: mod.item.requiresSkill("Repair Systems") or mod.item.requiresSkill("Capital Repair Systems"), lambda mod: mod.item.requiresSkill("Repair Systems") or mod.item.requiresSkill("Capital Repair Systems"),
"armorDamageAmount", booster.getModifiedItemAttr("armorDamageAmountBonus")) "armorDamageAmount", booster.getModifiedItemAttr("armorDamageAmountBonus") or 0)

View File

@@ -1,7 +1,7 @@
# armorHPBonusAdd # armorHPBonusAdd
# #
# Used by: # Used by:
# Modules from group: Armor Reinforcer (48 of 48) # Modules from group: Armor Reinforcer (51 of 51)
type = "passive" type = "passive"

View File

@@ -1,7 +1,7 @@
# armorReinforcerMassAdd # armorReinforcerMassAdd
# #
# Used by: # Used by:
# Modules from group: Armor Reinforcer (48 of 48) # Modules from group: Armor Reinforcer (51 of 51)
type = "passive" type = "passive"

View File

@@ -1,7 +1,7 @@
# armorRepair # armorRepair
# #
# Used by: # Used by:
# Modules from group: Armor Repair Unit (105 of 105) # Modules from group: Armor Repair Unit (108 of 108)
runTime = "late" runTime = "late"
type = "active" type = "active"
@@ -9,4 +9,7 @@ type = "active"
def handler(fit, module, context): def handler(fit, module, context):
amount = module.getModifiedItemAttr("armorDamageAmount") amount = module.getModifiedItemAttr("armorDamageAmount")
speed = module.getModifiedItemAttr("duration") / 1000.0 speed = module.getModifiedItemAttr("duration") / 1000.0
fit.extraAttributes.increase("armorRepair", amount / speed) rps = amount / speed
fit.extraAttributes.increase("armorRepair", rps)
fit.extraAttributes.increase("armorRepairPreSpool", rps)
fit.extraAttributes.increase("armorRepairFullSpool", rps)

View File

@@ -1,10 +0,0 @@
# Not used by any item
type = "gang", "active"
gangBonus = "armorHpBonus2"
gangBoost = "armorHP"
def handler(fit, module, context):
if "gang" not in context:
return
fit.ship.boostItemAttr("armorHP", module.getModifiedItemAttr("armorHpBonus2"))

View File

@@ -1,7 +1,7 @@
# boosterArmorHpPenalty # boosterArmorHpPenalty
# #
# Used by: # Used by:
# Implants from group: Booster (12 of 62) # Implants named like: Booster (12 of 35)
type = "boosterSideEffect" type = "boosterSideEffect"
# User-friendly name for the side effect # User-friendly name for the side effect

View File

@@ -1,7 +1,8 @@
# boosterMaxVelocityPenalty # boosterMaxVelocityPenalty
# #
# Used by: # Used by:
# Implants from group: Booster (12 of 62) # Implants named like: Crash Booster (3 of 4)
# Items from market group: Implants & Boosters > Booster > Booster Slot 02 (9 of 13)
type = "boosterSideEffect" type = "boosterSideEffect"
# User-friendly name for the side effect # User-friendly name for the side effect

View File

@@ -4,6 +4,7 @@
# Implants named like: Eifyr and Co. 'Alchemist' Neurotoxin Control NC (2 of 2) # Implants named like: Eifyr and Co. 'Alchemist' Neurotoxin Control NC (2 of 2)
# Implants named like: grade Edge (10 of 12) # Implants named like: grade Edge (10 of 12)
# Skill: Neurotoxin Control # Skill: Neurotoxin Control
runTime = 'early'
type = "passive" type = "passive"

View File

@@ -1,7 +1,7 @@
# boosterShieldCapacityPenalty # boosterShieldCapacityPenalty
# #
# Used by: # Used by:
# Implants from group: Booster (12 of 62) # Implants from group: Booster (12 of 70)
type = "boosterSideEffect" type = "boosterSideEffect"
# User-friendly name for the side effect # User-friendly name for the side effect

View File

@@ -1,7 +1,7 @@
# capacitorCapacityBonus # capacitorCapacityBonus
# #
# Used by: # Used by:
# Modules from group: Capacitor Battery (27 of 27) # Modules from group: Capacitor Battery (30 of 30)
type = "passive" type = "passive"

View File

@@ -4,7 +4,7 @@
# Modules from group: Capacitor Flux Coil (6 of 6) # Modules from group: Capacitor Flux Coil (6 of 6)
# Modules from group: Capacitor Power Relay (20 of 20) # Modules from group: Capacitor Power Relay (20 of 20)
# Modules from group: Power Diagnostic System (23 of 23) # Modules from group: Power Diagnostic System (23 of 23)
# Modules from group: Propulsion Module (65 of 127) # Modules from group: Propulsion Module (68 of 133)
# Modules from group: Reactor Control Unit (22 of 22) # Modules from group: Reactor Control Unit (22 of 22)
type = "passive" type = "passive"

View File

@@ -1,4 +1,7 @@
# Not used by any item # citadelRigBonus
#
# Used by:
# Structures from group: Citadel (9 of 9)
type = "passive" type = "passive"
runTime = "early" runTime = "early"

View File

@@ -2,7 +2,7 @@
# #
# Used by: # Used by:
# Ships from group: Carrier (4 of 4) # Ships from group: Carrier (4 of 4)
# Ships from group: Combat Battlecruiser (13 of 13) # Ships from group: Combat Battlecruiser (14 of 14)
# Ships from group: Command Ship (8 of 8) # Ships from group: Command Ship (8 of 8)
# Ships from group: Force Auxiliary (6 of 6) # Ships from group: Force Auxiliary (6 of 6)
# Ships from group: Supercarrier (6 of 6) # Ships from group: Supercarrier (6 of 6)

View File

@@ -3,9 +3,9 @@
# Used by: # Used by:
# Ships from group: Black Ops (5 of 5) # Ships from group: Black Ops (5 of 5)
# Ships from group: Blockade Runner (4 of 4) # Ships from group: Blockade Runner (4 of 4)
# Ships from group: Covert Ops (7 of 7) # Ships from group: Covert Ops (8 of 8)
# Ships from group: Expedition Frigate (2 of 2) # Ships from group: Expedition Frigate (2 of 2)
# Ships from group: Force Recon Ship (8 of 8) # Ships from group: Force Recon Ship (9 of 9)
# Ships from group: Stealth Bomber (5 of 5) # Ships from group: Stealth Bomber (5 of 5)
# Ships named like: Stratios (2 of 2) # Ships named like: Stratios (2 of 2)
# Subsystems named like: Defensive Covert Reconfiguration (4 of 4) # Subsystems named like: Defensive Covert Reconfiguration (4 of 4)

View File

@@ -1,7 +1,7 @@
# covertOpsCloakCpuPercentBonus1 # covertOpsCloakCpuPercentBonus1
# #
# Used by: # Used by:
# Ships from group: Covert Ops (5 of 7) # Ships from group: Covert Ops (6 of 8)
type = "passive" type = "passive"
runTime = "early" runTime = "early"

View File

@@ -0,0 +1,9 @@
# covertOpsWarpResistance
#
# Used by:
# Ships from group: Covert Ops (5 of 8)
type = "passive"
def handler(fit, src, context):
fit.ship.increaseItemAttr("warpFactor", src.getModifiedItemAttr("eliteBonusCovertOps1"), skill="Covert Ops")

View File

@@ -2,6 +2,7 @@
# #
# Used by: # Used by:
# Modules from group: CPU Enhancer (19 of 19) # Modules from group: CPU Enhancer (19 of 19)
# Variations of structure module: Standup Co-Processor Array I (2 of 2)
type = "passive" type = "passive"

View File

@@ -3,7 +3,7 @@
# Used by: # Used by:
# Modules from group: Frequency Mining Laser (3 of 3) # Modules from group: Frequency Mining Laser (3 of 3)
type = "passive" type = "passive"
runTime = "late"
def handler(fit, module, context): def handler(fit, module, context):
module.preAssignItemAttr("specialtyMiningAmount", module.getModifiedItemAttr("miningAmount")) module.preAssignItemAttr("specialtyMiningAmount", module.getModifiedItemAttr("miningAmount"))

View File

@@ -1,10 +1,10 @@
# cynosuralDurationBonus # cynosuralDurationBonus
# #
# Used by: # Used by:
# Ships from group: Force Recon Ship (7 of 8) # Ships from group: Force Recon Ship (8 of 9)
type = "passive" type = "passive"
def handler(fit, ship, context): def handler(fit, ship, context):
fit.modules.filteredItemBoost(lambda mod: mod.item.group.name == "Cynosural Field", fit.modules.filteredItemBoost(lambda mod: mod.item.group.name == "Cynosural Field Generator",
"duration", ship.getModifiedItemAttr("durationBonus")) "duration", ship.getModifiedItemAttr("durationBonus"))

View File

@@ -1,7 +1,7 @@
# cynosuralGeneration # cynosuralGeneration
# #
# Used by: # Used by:
# Modules from group: Cynosural Field (2 of 2) # Modules from group: Cynosural Field Generator (2 of 2)
type = "active" type = "active"

View File

@@ -1,13 +1,13 @@
# cynosuralTheoryConsumptionBonus # cynosuralTheoryConsumptionBonus
# #
# Used by: # Used by:
# Ships from group: Force Recon Ship (7 of 8) # Ships from group: Force Recon Ship (8 of 9)
# Skill: Cynosural Field Theory # Skill: Cynosural Field Theory
type = "passive" type = "passive"
def handler(fit, container, context): def handler(fit, container, context):
level = container.level if "skill" in context else 1 level = container.level if "skill" in context else 1
fit.modules.filteredItemBoost(lambda mod: mod.item.group.name == "Cynosural Field", fit.modules.filteredItemBoost(lambda mod: mod.item.group.name == "Cynosural Field Generator",
"consumptionQuantity", "consumptionQuantity",
container.getModifiedItemAttr("consumptionQuantityBonusPercentage") * level) container.getModifiedItemAttr("consumptionQuantityBonusPercentage") * level)

View File

@@ -11,6 +11,5 @@ def handler(fit, module, context):
bonus = "%s%sDamageResonance" % (attrPrefix, damageType) bonus = "%s%sDamageResonance" % (attrPrefix, damageType)
bonus = "%s%s" % (bonus[0].lower(), bonus[1:]) bonus = "%s%s" % (bonus[0].lower(), bonus[1:])
booster = "%s%sDamageResonance" % (layer, damageType) booster = "%s%sDamageResonance" % (layer, damageType)
penalize = False if layer == 'hull' else True
fit.ship.multiplyItemAttr(bonus, module.getModifiedItemAttr(booster), fit.ship.multiplyItemAttr(bonus, module.getModifiedItemAttr(booster),
stackingPenalties=penalize, penaltyGroup="preMul") stackingPenalties=True, penaltyGroup="preMul")

View File

@@ -1,9 +0,0 @@
# Not used by any item
type = "active", "projected"
def handler(fit, module, context):
if "projected" not in context:
return
fit.ship.boostItemAttr("maxVelocity", module.getModifiedItemAttr("speedFactor"),
stackingPenalties=True)

View File

@@ -0,0 +1,11 @@
# disintegratorWeaponDamageMultiply
#
# Used by:
# Modules from group: Entropic Radiation Sink (4 of 4)
type = "passive"
def handler(fit, module, context):
fit.modules.filteredItemMultiply(lambda mod: mod.item.group.name == "Precursor Weapon",
"damageMultiplier", module.getModifiedItemAttr("damageMultiplier"),
stackingPenalties=True)

View File

@@ -0,0 +1,11 @@
# disintegratorWeaponSpeedMultiply
#
# Used by:
# Modules from group: Entropic Radiation Sink (4 of 4)
type = "passive"
def handler(fit, module, context):
fit.modules.filteredItemMultiply(lambda mod: mod.item.group.name == "Precursor Weapon",
"speed", module.getModifiedItemAttr("speedMultiplier"),
stackingPenalties=True)

View File

@@ -1,7 +1,7 @@
# doHacking # doHacking
# #
# Used by: # Used by:
# Modules from group: Data Miners (9 of 9) # Modules from group: Data Miners (10 of 10)
type = "active" type = "active"

View File

@@ -2,6 +2,7 @@
# #
# Used by: # Used by:
# Module: Warp Disruption Burst Projector # Module: Warp Disruption Burst Projector
# Structure Module: Standup Warp Disruption Burst Projector
type = "projected", "active" type = "projected", "active"

View File

@@ -2,6 +2,7 @@
# #
# Used by: # Used by:
# Module: Sensor Dampening Burst Projector # Module: Sensor Dampening Burst Projector
# Structure Module: Standup Sensor Dampening Burst Projector
type = "projected", "active" type = "projected", "active"

View File

@@ -2,6 +2,7 @@
# #
# Used by: # Used by:
# Module: ECM Jammer Burst Projector # Module: ECM Jammer Burst Projector
# Structure Module: Standup ECM Jammer Burst Projector
from eos.modifiedAttributeDict import ModifiedAttributeDict from eos.modifiedAttributeDict import ModifiedAttributeDict
type = "projected", "active" type = "projected", "active"

View File

@@ -2,6 +2,7 @@
# #
# Used by: # Used by:
# Module: Energy Neutralization Burst Projector # Module: Energy Neutralization Burst Projector
# Structure Module: Standup Energy Neutralization Burst Projector
from eos.saveddata.module import State from eos.saveddata.module import State
from eos.modifiedAttributeDict import ModifiedAttributeDict from eos.modifiedAttributeDict import ModifiedAttributeDict

View File

@@ -2,6 +2,7 @@
# #
# Used by: # Used by:
# Module: Target Illumination Burst Projector # Module: Target Illumination Burst Projector
# Structure Module: Standup Target Illumination Burst Projector
type = "projected", "active" type = "projected", "active"

View File

@@ -2,6 +2,7 @@
# #
# Used by: # Used by:
# Module: Weapon Disruption Burst Projector # Module: Weapon Disruption Burst Projector
# Structure Module: Standup Weapon Disruption Burst Projector
type = "active", "projected" type = "active", "projected"

View File

@@ -2,6 +2,7 @@
# #
# Used by: # Used by:
# Module: Stasis Webification Burst Projector # Module: Stasis Webification Burst Projector
# Structure Module: Standup Stasis Webification Burst Projector
type = "active", "projected" type = "active", "projected"

View File

@@ -1,7 +1,7 @@
# droneArmorDamageBonusEffect # droneArmorDamageBonusEffect
# #
# Used by: # Used by:
# Ships from group: Logistics (5 of 6) # Ships from group: Logistics (6 of 7)
# Ship: Exequror # Ship: Exequror
# Ship: Scythe # Ship: Scythe
type = "passive" type = "passive"

View File

@@ -1,7 +0,0 @@
# Not used by any item
type = "passive"
def handler(fit, skill, context):
fit.drones.filteredItemBoost(lambda drone: drone.item.requiresSkill("Drones"),
"damageMultiplier", skill.getModifiedItemAttr("damageMultiplierBonus") * skill.level)

View File

@@ -1,7 +1,7 @@
# droneHullRepairBonusEffect # droneHullRepairBonusEffect
# #
# Used by: # Used by:
# Ships from group: Logistics (5 of 6) # Ships from group: Logistics (6 of 7)
# Ship: Exequror # Ship: Exequror
# Ship: Scythe # Ship: Scythe
type = "passive" type = "passive"

View File

@@ -2,10 +2,12 @@
# #
# Used by: # Used by:
# Modules named like: Drone Speed Augmentor (6 of 8) # Modules named like: Drone Speed Augmentor (6 of 8)
# Implant: Overmind 'Goliath' Drone Tuner T25-10S
# Implant: Overmind 'Hawkmoth' Drone Tuner S10-25T
type = "passive" type = "passive"
def handler(fit, container, context): def handler(fit, container, context):
level = container.level if "skill" in context else 1 level = container.level if "skill" in context else 1
fit.drones.filteredItemBoost(lambda drone: drone.item.requiresSkill("Drones"), fit.drones.filteredItemBoost(lambda drone: drone.item.requiresSkill("Drones"),
"maxVelocity", container.getModifiedItemAttr("droneMaxVelocityBonus") * level) "maxVelocity", container.getModifiedItemAttr("droneMaxVelocityBonus") * level, stackingPenalties=True)

View File

@@ -1,7 +1,7 @@
# droneShieldBonusBonusEffect # droneShieldBonusBonusEffect
# #
# Used by: # Used by:
# Ships from group: Logistics (5 of 6) # Ships from group: Logistics (6 of 7)
# Ship: Exequror # Ship: Exequror
# Ship: Scythe # Ship: Scythe
type = "passive" type = "passive"

View File

@@ -1,9 +0,0 @@
# Not used by any item
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")

View File

@@ -1,7 +0,0 @@
# Not used by any item
type = "passive"
def handler(fit, src, context):
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("High Speed Maneuvering"), "signatureRadiusBonus",
src.getModifiedItemAttr("eliteBonusCommandDestroyer3"), skill="Command Destroyers")

View File

@@ -1,7 +0,0 @@
# 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")

View File

@@ -1,7 +1,7 @@
# eliteBonusCoverOpsScanProbeStrength2 # eliteBonusCoverOpsScanProbeStrength2
# #
# Used by: # Used by:
# Ships from group: Covert Ops (7 of 7) # Ships from group: Covert Ops (8 of 8)
type = "passive" type = "passive"

View File

@@ -0,0 +1,10 @@
# eliteBonusCovertOps3PCTdamagePerCycle
#
# Used by:
# Ship: Hydra
type = "passive"
def handler(fit, src, context):
fit.modules.filteredItemIncrease(lambda mod: mod.item.requiresSkill("Small Precursor Weapon"), "damageMultiplierBonusPerCycle",
src.getModifiedItemAttr("eliteBonusCovertOps3"), skill="Covert Ops")

View File

@@ -1,6 +0,0 @@
# Not used by any item
type = "passive"
def handler(fit, ship, context):
fit.ship.increaseItemAttr("droneCapacity", ship.getModifiedItemAttr("eliteBonusGunship2"), skill="Assault Frigates")

View File

@@ -1,7 +0,0 @@
# Not used by any item
type = "passive"
def handler(fit, src, context):
fit.drones.filteredItemBoost(lambda mod: mod.item.requiresSkill("Drones"), "trackingSpeed",
src.getModifiedItemAttr("eliteBonusGunship2"), stackingPenalties=True, skill="Assault Frigates")

View File

@@ -1,8 +0,0 @@
# Not used by any item
type = "passive"
def handler(fit, ship, context):
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Small Projectile Turret"),
"damageMultiplier", ship.getModifiedItemAttr("eliteBonusGunship2"),
skill="Assault Frigates")

View File

@@ -1,7 +0,0 @@
# Not used by any item
type = "passive"
def handler(fit, ship, context):
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Small Projectile Turret"),
"maxRange", ship.getModifiedItemAttr("eliteBonusGunship1"), skill="Assault Frigates")

View File

@@ -0,0 +1,10 @@
# eliteBonusReconScanProbeStrength2
#
# Used by:
# Ship: Tiamat
type = "passive"
def handler(fit, src, context):
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Astrometrics"), "baseSensorStrength",
src.getModifiedItemAttr("eliteBonusReconShip2"), skill="Recon Ships")

View File

@@ -0,0 +1,10 @@
# eliteBonusReconShip3PCTdamagePerCycle
#
# Used by:
# Ship: Tiamat
type = "passive"
def handler(fit, src, context):
fit.modules.filteredItemIncrease(lambda mod: mod.item.requiresSkill("Medium Precursor Weapon"), "damageMultiplierBonusPerCycle",
src.getModifiedItemAttr("eliteBonusReconShip3"), skill="Recon Ships")

View File

@@ -0,0 +1,13 @@
# emergencyHullEnergizer
#
# Used by:
# Variations of module: Capital Emergency Hull Energizer I (5 of 5)
type = "active"
runtime = "late"
def handler(fit, src, context):
for dmgType in ('em', 'thermal', 'kinetic', 'explosive'):
fit.ship.multiplyItemAttr('{}DamageResonance'.format(dmgType),
src.getModifiedItemAttr("hull{}DamageResonance".format(dmgType.title())),
stackingPenalties=True, penaltyGroup="postMul")

View File

@@ -1,12 +0,0 @@
# Not used by any item
from eos.saveddata.module import State
type = "active", "projected"
def handler(fit, src, context):
if "projected" in context and ((hasattr(src, "state") and src.state >= State.ACTIVE) or hasattr(src, "amountActive")):
multiplier = src.amountActive if hasattr(src, "amountActive") else 1
amount = src.getModifiedItemAttr("energyNeutralizerAmount")
time = src.getModifiedItemAttr("duration")
fit.addDrain(src, time, amount * multiplier, 0)

View File

@@ -1,7 +1,7 @@
# energyNeutralizerFalloff # energyNeutralizerFalloff
# #
# Used by: # Used by:
# Modules from group: Energy Neutralizer (51 of 51) # Modules from group: Energy Neutralizer (54 of 54)
from eos.saveddata.module import State from eos.saveddata.module import State
from eos.modifiedAttributeDict import ModifiedAttributeDict from eos.modifiedAttributeDict import ModifiedAttributeDict

View File

@@ -1,7 +1,7 @@
# energyNosferatuFalloff # energyNosferatuFalloff
# #
# Used by: # Used by:
# Modules from group: Energy Nosferatu (51 of 51) # Modules from group: Energy Nosferatu (54 of 54)
from eos.modifiedAttributeDict import ModifiedAttributeDict from eos.modifiedAttributeDict import ModifiedAttributeDict
type = "active", "projected" type = "active", "projected"

View File

@@ -1,9 +0,0 @@
# Not used by any item
type = "projected", "active"
def handler(fit, src, context):
if "projected" in context:
amount = src.getModifiedItemAttr("powerTransferAmount")
duration = src.getModifiedItemAttr("duration")
fit.addDrain(src, duration, -amount, 0)

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